前言:最近准备做一个多人在线小游戏的来着,因为没学过udp所以准备用以前学JavaScript时候学来的socket做一个,结果遇到bug裂开了,后来一想socket效率确实不太够然后就没修bug了,但是现在心血来潮把当时写的屎山一样的socket代码刨了一下,简单的封装了一个类。当然,是真的很简单的封装,甚至我自己都不确保能用的那种......
编译器是Microsoft Visual Studio 2022,没改过啥东西,用原生代码码的。
目前能想到但不想处理的问题直接列出来得了:
- 这种破烂异步的使用放到C++里会爆栈的不知道C#怎么说
- 客户端断连的时候估计这边接收不到断连的消息,一个巨大的bug等我有时间了修吧
- 单次收到socket后容纳字符的byte数组大小是1024,这个可以自己调整,但是得注意一下这个不是自适应大小的。
下面是初版的代码,不知道之后有没有兴致改改:
- public class Cilent
- {
- //开放的接口部分
- public static void SocketOn(string IP, Int32 port, int MaxListen = 100)
- {
- socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind(new IPEndPoint(IPAddress.Parse(IP), port));
- socket.Listen(MaxListen);
- socket.BeginAccept(AcceptCallBack, null);
- }
- public static Action
string>? GetMsg; - public void Send(string msg)
- {
- if (!cilent.Connected) return;
- cilent.Send(Encoding.UTF8.GetBytes(msg));
- }
-
- //不开放的部分
- private static Socket? socket;
- private static void AcceptCallBack(IAsyncResult ar)
- {
- if (socket == null) return;
- Cilent Get = new Cilent(socket.EndAccept(ar));
- Get.cilent.BeginReceive(Get.data, 0, 1024, SocketFlags.None, Get.ReceiveCallBack, null);
- socket.BeginAccept(AcceptCallBack, null);
- }
- private void ReceiveCallBack(IAsyncResult ar)
- {
- int Length = this.cilent.EndReceive(ar);
- if (Length == 0) { return; }
- string msg = Encoding.UTF8.GetString(data, 0, Length);
- if (GetMsg != null) GetMsg(this, msg);
- cilent.BeginReceive(this.data, 0, 1024, SocketFlags.None, this.ReceiveCallBack, null);
- }
- private Socket cilent;
- private byte[] data;
- private Cilent(Socket _socket) { cilent = _socket; data = new byte[1024]; }
- }
具体怎么使用也很简单,毕竟只开放了两个接口和一个委托,跟着我思路走应该就会用了。
1. 首先看开放的第一个接口 SocketOn
- public static void SocketOn(string IP, Int32 port, int MaxListen = 100){
- socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind(new IPEndPoint(IPAddress.Parse(IP), port));
- socket.Listen(MaxListen);
- socket.BeginAccept(AcceptCallBack, null);
- }
- //这里的socket指的是下面的
- private static Socket? socket;
因为一般来说运行一个程序只用开放一个端口就行了,所以干脆把管理Socket连入的Socket给设置成静态的,然后就是设置 地址IP,端口port,最大连接数MaxListen应该就是同时连入的最大数量吧没在这块炸过所以不太清楚。正常开放主机的127.0.0.1的80端口还是啥自己看着来就行。
2. 再看看开放的这个委托 GetMsg
public static Actionstring>? GetMsg;
如果是C++的话一个函数指针就啥都啥都解决了,但是C#好像指针不大行,上网找半天找到个看起来算是靠谱的委托的实现方式。先说一下这个GetMsg是干啥的,当静态的socket经过SocketOn被打开后,会一直用异步的方式去等待一个Socket客户端连接,接到之后就会生成一个Cilent实例,这个实例一诞生就会立即异步的不断去接收客户端连入的信息,接收到消息就会执行GetMsg,其中,第一个参数就是接收到信息的Cilent对象,string就是收到的信息。
具体使用如下(举个例子):
- Cilent.GetMsg = (Cilent cilent, string msg) =>
- {
- cilent.Send(msg);
- };
如上就是每接收到一条消息就把消息原封不动的送回去。
3. 所以Send这个方法应该就不用介绍了,基本是配合着GetMsg使用的,因为Cilent类的构造函数是私有的,所以没法在别的地方生成能用的Cilent对象。
- public void Send(string msg)
- {
- if (!cilent.Connected) return;
- cilent.Send(Encoding.UTF8.GetBytes(msg));
- }