使用VS2017创建一个类库。

服务器端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace MyServer
{public class SocketPeer{private Socket serverSocket;/// <summary>/// 信号技术量,线程的拥塞控制/// </summary>private Semaphore semaphore;private ClientPeerPool clientPeerPool;//客户端连接对象池public void StartServer(string ip,int port,int maxClient){try{semaphore = new Semaphore(maxClient, maxClient);clientPeerPool = new ClientPeerPool(maxClient);for (int i = 0; i < maxClient; i++){ClientPeer client = new ClientPeer();client.ReceiveArgs.Completed += ReceiveArgs_Completed;clientPeerPool.Enqueue(client);}serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);serverSocket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));serverSocket.Listen(maxClient);Console.WriteLine("服务器启动成功");//开始接收客户端的连接StartAccept(null);}catch (Exception e){Console.WriteLine(e.Message);}}/// <summary>/// 开始等待客户端的连接/// </summary>private void StartAccept(SocketAsyncEventArgs e){if (e==null){e = new SocketAsyncEventArgs();e.Completed += E_Completed;}//result 为true 代表正在接收连接,连接成功以后会调用E_Completed事件//为false 代表接收成功bool result = serverSocket.AcceptAsync(e);if (result==false){ProcessAccept(e);}}/// <summary>/// 异步接收连接完成后的回调/// </summary>private void E_Completed(object sender, SocketAsyncEventArgs e){ProcessAccept(e);}/// <summary>/// 出来客户端的连接/// </summary>private void ProcessAccept(SocketAsyncEventArgs e){semaphore.WaitOne();//阻止当前线程,直到有客户端释放ClientPeer client = clientPeerPool.Dequeue();client.clientSocket = e.AcceptSocket;//得到Client  e.AcceptSocket 可以获取当前连接的客户端Sockt Console.WriteLine(client.clientSocket.RemoteEndPoint+"客户端连接成功");//接收消息StartReceive(client);e.AcceptSocket = null;StartAccept(e);//伪递归}/// <summary>/// 开始接收消息/// </summary>private void StartReceive(ClientPeer client){try{//这里需要一个异步套接字 在ClientPeer中定义一个,在构造方法中赋值bool result = client.clientSocket.ReceiveAsync(client.ReceiveArgs);if (result == false){ProcessReceive(client.ReceiveArgs);}}catch (Exception e){Console.WriteLine(e.Message);}}/// <summary>///异步接收消息完毕后的回调/// </summary>private void ReceiveArgs_Completed(object sender, SocketAsyncEventArgs e){ProcessReceive(e);}/// <summary>/// 处理数据的接收/// </summary>private void ProcessReceive(SocketAsyncEventArgs e){//UserToken 可以得到与这个套接字绑定的程序对象,在ClientPeer进行了绑定设置,这里得到ClientPeerClientPeer client = e.UserToken as ClientPeer;//判断数据是否接收成功 SocketError.Success是否连接 BytesTransferred 获得收到数据的长度if (client.ReceiveArgs.SocketError == SocketError.Success && client.ReceiveArgs.BytesTransferred > 0){byte[] packet = new byte[client.ReceiveArgs.BytesTransferred];//数据的存储//client.ReceiveArgs.Buffer 数据缓冲区,接收到的数据存放到这里Buffer.BlockCopy(client.ReceiveArgs.Buffer, 0, packet, 0, client.ReceiveArgs.BytesTransferred);//让Client自身处理接收到的消息client.ProcessReceive(packet);StartReceive(client);//伪递归}else//数据接收不成功{//接收的数据为0 代表断开连接了if (client.ReceiveArgs.BytesTransferred==0){//客户端主动断开连接if (client.ReceiveArgs.SocketError==SocketError.Success){DisConnected(client,"客户端主动断开连接");}else//因为网络原因,被动断开连接{DisConnected(client, e.SocketError.ToString());}}}}//断开连接private void DisConnected(ClientPeer client,string reason){try{if (client==null){throw new Exception("客户端为空,无法断开连接!");}Console.WriteLine(client.clientSocket.RemoteEndPoint + "客户端断开连接,原因:" + reason);//客户端自己处理断开连接client.DisConnected();clientPeerPool.Enqueue(client);//断开连接的Client放到客户端连接池中semaphore.Release();//释放一个Client}catch (Exception e){Console.WriteLine(e.Message);}}}
}

客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;namespace MyServer
{public class ClientPeer{public Socket clientSocket { get; set; }public SocketAsyncEventArgs ReceiveArgs { get; set; }public ClientPeer(){ReceiveArgs = new SocketAsyncEventArgs();ReceiveArgs.UserToken = this;//绑定UserToken 通过UserToken获得当前的ClientPeerReceiveArgs.SetBuffer(new byte[2048],0,2048);//设置数据缓冲区,数据缓冲区在使用时,需要进行设置}/// <summary>/// 处理数据的接收/// </summary>/// <param name="packet"></param>public void ProcessReceive(byte[] packet){}/// <summary>/// 断开连接/// </summary>public void DisConnected(){}}
}

客户端连接池

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace MyServer
{public  class ClientPeerPool{public Queue<ClientPeer> clientPeers;public ClientPeerPool(int maxCount){clientPeers = new Queue<ClientPeer>(maxCount);}public void Enqueue(ClientPeer client){clientPeers.Enqueue(client);}public ClientPeer Dequeue(){return clientPeers.Dequeue();}}
}

构造类

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace MyServer
{/// <summary>/// 构造类,避免粘包问题/// </summary>public class EncodeTools{/// <summary>/// 构造包 包头加包尾/// </summary>public static byte[] EncodePacket(byte[] packet){//using 不需要手动释放 会自动释放using (MemoryStream ms = new MemoryStream()){using (BinaryWriter bw = new BinaryWriter(ms)){//写入包头(数据长度,前四个字节)bw.Write(packet.Length);//写入包尾(数据) 解析时:先解析出包头 得到数据长度 数据长度在和剩下数据长度进行比较bw.Write(packet);byte[] data = new byte[ms.Length];//获取所有写入流中的总长度//ms.GetBuffer(); 返回流中所有创建的无符号字节的数组Buffer.BlockCopy(ms.GetBuffer(), 0, data, 0, (int)ms.Length);return data;}}}/// <summary>/// 解析包 这里修改了缓冲区的地址,需要加引用参数ref /// </summary>public static byte[] DecodePacket(ref List<byte> cache){if (cache.Count < 4)//前4位为数据长度,不够4位返回null{return null;}using (MemoryStream ms = new MemoryStream(cache.ToArray())){using (BinaryReader br = new BinaryReader(ms)){int length = br.ReadInt32();//ReadInt32 读取前四个字节 得到数据长度//Position获取当前在流中的所在位置  ReadInt32读取以后会让游标向后移4位 当前的总长度-减去游标 //得到剩下的长度int remainLength = (int)(ms.Length - ms.Position);if (length > remainLength){return null;}byte[] data = br.ReadBytes(length);//读取一个数组cache.Clear();//更新数据缓存//得到读取后的位置int remainLengthAngin = (int)(ms.Length - ms.Position);//把后面的数据填充到缓冲区 解析后的清除掉cache.AddRange(br.ReadBytes(remainLengthAngin));return data;}}}}
}


有需要学习视频欢迎关注微信公众号

Zjh游戏(一)服务器连接、接收消息相关推荐

  1. 微信收到消息很慢无法连接服务器,微信接收消息有延迟原因及解决办法

    微信收到消息总是延迟怎么回事呢?第一个就是网络延迟,第二个是手机信号不好,第三个就是微信自己设置的问题.下面,我们来看看微信收消息有延迟的原因及解决办法. 软件名称:微信安卓版 V8.0.9 for ...

  2. Zjh游戏(二)网络消息类NetMessage的处理

    NetMessage的创建 作用:每次发送消息,都发送这个类,接收到消息后,转换成这个类 自己理解:加上模块号,保证收发消息的准确性,方便接收处理,在脚本中有两个操作码,操作码对应游戏中某个模块,子操 ...

  3. 传奇游戏显示服务器连接失败,操作win7系统玩传奇世界显示连接服务器失败的详细方法...

    使用电脑的时候,有的小伙伴就会碰到win7系统玩传奇世界显示连接服务器失败类似的操作困难,小编认为win7系统玩传奇世界显示连接服务器失败的问题还是比较容易处理的,于是就有一些朋友到本站询问win7系 ...

  4. 服务器启动微信等待,微信接收消息会延迟?只要用对方法,一键下去轻松解决...

    微信接收消息延迟的情况,相信每位微信用户都应该经历过,可是很多人都不知道为什么会出现这种延迟消息的状况,那么小编今天就来跟大家介绍下,为什么会出现接收消息延迟的状况? 一.出现消息延迟的原因 1.手机 ...

  5. 微信如何没有位置信息服务器,微信接收消息会延迟?那是因为你没有这样设置,一键下去轻松解决...

    微信接收消息延迟的情况,相信每位微信用户都应该经历过,可是很多人都不知道为什么会出现这种延迟消息的状况,那么小编今天就来跟大家介绍下,为什么会出现接收消息延迟的状况? 一.出现消息延迟的原因 1.手机 ...

  6. Zjh游戏(六)客户端接收发送消息以及连接测试

    前期准备 创建工程和场景 把Server端的EncodeTools和NetMsg拖到Unity中 创建ClientPeer脚本,封装客户端的接收消息和发送消息 创建空物体NetMsgCenter用来挂 ...

  7. 如何 接收消息服务器url,(读书笔记)网络是怎样连接的——浏览器生成消息...

    概览 本次探索之旅从用户在浏览器中输入网址(URL)开始. 生成HTTP请求消息 浏览器的工作会从对用户输入的网址进行解析开始.浏览器如何解析网址是我们的第一个看点.然后浏览器会根据网址的含义来生成请 ...

  8. 大话西游2接收服务器信息失败,大话西游手游服务器连接失败 无法连接服务器解决步骤_网络-游戏圈...

    大话西游手游连不上服务器怎么办,无法连接服务器怎么办?连不上游戏怎么办?不用急小编为大家分享大话西游手游联网教程,希望可以帮助到大家. 1.服务器维护,官方维护或者出现BUG,也会出现进不了游戏的情况 ...

  9. 微信收到消息很慢无法连接服务器,为什么微信接收消息总会延迟?4个原因要注意,解决方法在这里...

    现在大部分人都将微信作为自己的主要聊天工具,但是有的时候微信却会出现接收消息延迟的情况,而且有的人就算接收到了消息也不会有消息提醒.那到底是什么原因会使得微信出现消息接收延迟的情况呢?接下来,我们就一 ...

最新文章

  1. 重读TCP协议(3)
  2. android onresume时view,android – 在使用ViewPager滑动时,Fragment不会调用OnResume()
  3. php zip.so 编译出错,php使用ZipArchive提示Fatal error: Class ZipArchive not found in的解决方法...
  4. mysql 事物的持久性是指_详解MySQL中事务的持久性实现原理
  5. 表达式求值负数乘负数_为什么现在很多期权的时间价值都为负数?
  6. jq如何在打开新的页面 关闭之前同链接的页面_教你如何“抢”其他域名的权重...
  7. java. 三个人比赛怎么写_两个乒乓球队进行比赛,找出三队赛手的名单
  8. Python 3.8实现支持断点续传的网络文件下载功能
  9. mzy git学习,初识git(一)
  10. 孕期服务器声音影响,噪音多少分贝影响胎儿听力
  11. 最新和平精英画质助手iApp源码+实测可用
  12. 斐讯手表怎么刷机华为系统_智能手表怎么刷机?
  13. Vue 引入阿里巴巴矢量图标库 (详细)
  14. Hprose轻松实现远程过程调用(RPC)
  15. 小区市话配套和宽带接入系统研究报告
  16. 一个 Python Bug 干倒了估值 1.6 亿美元的公司
  17. excel合并多个工作表_EXCEL动态合并工作表,操作其实很简单
  18. 数据增强——对文件夹中的图片进行读取、数据增强,保存操作
  19. JAVA连接SQL2005
  20. 利用python进行股票分析(四)pandas

热门文章

  1. 小程序真机调试提示系统错误
  2. CLAHE (Contrast Limited Adaptive Histogram Equalization)算法学习
  3. IPV6 -ping6用法
  4. 计算机无法切换用户,Win10微软账户无法切换Administrator本地帐户的解决方法
  5. python之逗号的用法
  6. MyErp-人事管理系统的问题总结
  7. Thank you 我应该怎么去回应呢
  8. Ubuntu 23.04、22.04、20.04、18.04国内源--阿里云、中科大、163、清华更新源(sources.list)
  9. 【Redis可视化工具连接redis】
  10. 送给逝去的日子,何必活的这么的累