C#的Socket简单实现消息发送
Socket一般用于网络之间的通信,在这里,实现的是服务端与客户端的简单消息通信。
首先是客户端的搭建,一般步骤是先建立Socket绑定本地的IP和端口,并对远端连接进行连接进行监听,这里的监听一般开启后台线程进行循环处理;如果远端有连接到本机的Socket的端口,则获取一个新的Socket对象并重新添加一个线程用于对远端地址进行消息通信(消息的收发),这样,服务端的Socket就简单实现,下面是winForm的具体实现。
一、先建立Socket的服务类SocketServerManager,用于对Socket各种操作的统一管理:
1 public class SocketManager 2 { 3 Socket _socket = null; 4 EndPoint _endPoint = null; 5 bool _isListening = false; 6 int BACKLOG = 10; 7 8 public SocketManager(string ip, int port) 9 { 10 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 11 IPAddress _ip = IPAddress.Parse(ip); 12 _endPoint = new IPEndPoint(_ip, port); 13 } 14 15 public void Start() 16 { 17 _socket.Bind(_endPoint); //绑定端口 18 _socket.Listen(BACKLOG); //开启监听 19 Thread acceptServer = new Thread(AcceptWork); //开启新线程处理监听 20 acceptServer.IsBackground = true; 21 _isListening = true; 22 acceptServer.Start(); 23 } 24 25 public void AcceptWork() 26 { 27 while (_isListening) 28 { 29 Socket acceptSocket = _socket.Accept(); 30 if (acceptSocket != null) 31 { 32 Thread socketConnectedThread = new Thread(newSocketReceive); 33 socketConnectedThread.IsBackground = true; 34 socketConnectedThread.Start(acceptSocket); 35 } 36 Thread.Sleep(200); 37 } 38 } 39 40 public void newSocketReceive(object obj) 41 { 42 Socket socket = obj as Socket; 43 while (true) 44 { 45 try 46 { 47 if (socket == null) return; 48 //这里向系统投递一个接收信息的请求,并为其指定ReceiveCallBack做为回调函数 49 socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallBack, buffer); 50 } 51 catch (Exception ex) 52 { 53 return; 54 } 55 Thread.Sleep(100); 56 } 57 } 58 59 private void ReceiveCallBack(IAsyncResult ar) 60 { 61 } 62 }
上面是Socket管理类的模型,具体的方法是初始化和开启监听,接下来就是在Form的界面调用建立类和Start方法。
客户端同样是初始化socket,然后就不是监听socket,而是调用Connect连接指定的Socket地址,最后是开启新的线程接收和发送消息。
1 public class SocketClientManager 2 { 3 public Socket _socket = null; 4 public EndPoint endPoint = null; 5 public bool _isConnected = false; 6 7 public SocketClientManager(string ip, int port) 8 { 9 IPAddress _ip = IPAddress.Parse(ip); 10 endPoint = new IPEndPoint(_ip, port); 11 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 12 } 13 14 public void Start() 15 { 16 _socket.BeginConnect(endPoint, ConnectedCallback, _socket); 17 _isConnected = true; 18 Thread socketClient = new Thread(SocketClientReceive); 19 socketClient.IsBackground = true; 20 socketClient.Start(); 21 } 22 23 public void SocketClientReceive() 24 { 25 while (_isConnected) 26 { 27 try { 28 _socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, buffer); 29 } 30 catch (SocketException ex) 31 { 32 _isConnected = false; 33 } 34 35 Thread.Sleep(100); 36 } 37 } 38 39 public void ReceiveCallback(IAsyncResult ar) 40 { 41 } 42 }
主要记住的是,客户端是监听Socket是固定的,是监听绑定地址的,每当有新的连接访问,则开启新的线程与之进行交互,而客户端只简单实现与服务端交互,服务端则只有一个。
Socket的进行发送与接收,一般是通过异步方法BeginReceive和BeginSend进行处理,方法一般带有回调函数,用于执行操作之后的处理。
还有就是连接的关闭,每关闭一个连接,先要结束在Socket所在的线程方法,我这里的处理是停止掉死循环的函数调用,每当线程所在函数执行完毕,则线程自动销毁。之后就是关闭所连接的socket。
下面是我程序的完整实现,为了方便socket的管理,我把服务器的所有与客户端对话的Socket统一用字典管理,并封装在SocketInfo的内部类中,消息的发送与接收必须先找到该连接socket。
最后就是界面的调用,完成Socket的网络消息交互。
下面是具体的实现及源码:
1 public class SocketManager 2 { 3 public Dictionary<string,SocketInfo> _listSocketInfo = null; 4 Socket _socket = null; 5 public SocketInfo socketInfo = null; 6 EndPoint _endPoint = null; 7 bool _isListening = false; 8 int BACKLOG = 10; 9 10 public delegate void OnConnectedHandler(string clientIP); 11 public event OnConnectedHandler OnConnected; 12 public delegate void OnReceiveMsgHandler(string ip); 13 public event OnReceiveMsgHandler OnReceiveMsg; 14 public event OnReceiveMsgHandler OnDisConnected; 15 16 public SocketManager(string ip, int port) 17 { 18 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 19 IPAddress _ip = IPAddress.Parse(ip); 20 _endPoint = new IPEndPoint(_ip, port); 21 _listSocketInfo = new Dictionary<string, SocketInfo>(); 22 } 23 24 public void Start() 25 { 26 _socket.Bind(_endPoint); //绑定端口 27 _socket.Listen(BACKLOG); //开启监听 28 Thread acceptServer = new Thread(AcceptWork); //开启新线程处理监听 29 acceptServer.IsBackground = true; 30 _isListening = true; 31 acceptServer.Start(); 32 } 33 34 public void AcceptWork() 35 { 36 while (_isListening) 37 { 38 Socket acceptSocket = _socket.Accept(); 39 if (acceptSocket != null && this.OnConnected != null) 40 { 41 SocketInfo sInfo = new SocketInfo(); 42 sInfo.socket = acceptSocket; 43 _listSocketInfo.Add(acceptSocket.RemoteEndPoint.ToString(), sInfo); 44 OnConnected(acceptSocket.RemoteEndPoint.ToString()); 45 Thread socketConnectedThread = new Thread(newSocketReceive); 46 socketConnectedThread.IsBackground = true; 47 socketConnectedThread.Start(acceptSocket); 48 } 49 Thread.Sleep(200); 50 } 51 } 52 53 public void newSocketReceive(object obj) 54 { 55 Socket socket = obj as Socket; 56 SocketInfo sInfo = _listSocketInfo[socket.RemoteEndPoint.ToString()]; 57 sInfo.isConnected = true; 58 while (sInfo.isConnected) 59 { 60 try 61 { 62 if (sInfo.socket == null) return; 63 //这里向系统投递一个接收信息的请求,并为其指定ReceiveCallBack做为回调函数 64 sInfo.socket.BeginReceive(sInfo.buffer, 0, sInfo.buffer.Length, SocketFlags.None, ReceiveCallBack, sInfo.socket.RemoteEndPoint); 65 } 66 catch (Exception ex) 67 { 68 return; 69 } 70 Thread.Sleep(100); 71 } 72 } 73 74 private void ReceiveCallBack(IAsyncResult ar) 75 { 76 EndPoint ep = ar.AsyncState as IPEndPoint; 77 SocketInfo info = _listSocketInfo[ep.ToString()]; 78 int readCount = 0; 79 try 80 { 81 if (info.socket == null) return; 82 readCount = info.socket.EndReceive(ar); 83 }catch(Exception ex){ 84 return; 85 } 86 if (readCount > 0) 87 { 88 //byte[] buffer = new byte[readCount]; 89 //Buffer.BlockCopy(info.buffer, 0, buffer, 0, readCount); 90 if (readCount < info.buffer.Length) 91 { 92 byte[] newBuffer = new byte[readCount]; 93 Buffer.BlockCopy(info.buffer, 0, newBuffer, 0, readCount); 94 info.msgBuffer = newBuffer; 95 } 96 else 97 { 98 info.msgBuffer = info.buffer; 99 } 100 string msgTip = Encoding.ASCII.GetString(info.msgBuffer); 101 if (msgTip == "\0\0\0faild") 102 { 103 info.isConnected = false; 104 if (this.OnDisConnected != null) OnDisConnected(info.socket.RemoteEndPoint.ToString()); 105 _listSocketInfo.Remove(info.socket.RemoteEndPoint.ToString()); 106 info.socket.Close(); 107 return; 108 } 109 if (OnReceiveMsg != null) OnReceiveMsg(info.socket.RemoteEndPoint.ToString()); 110 } 111 } 112 113 public void SendMsg(string text, string endPoint) 114 { 115 if (_listSocketInfo.Keys.Contains(endPoint) && _listSocketInfo[endPoint] != null) 116 { 117 _listSocketInfo[endPoint].socket.Send(Encoding.ASCII.GetBytes(text)); 118 } 119 } 120 121 public void Stop() 122 { 123 _isListening = false; 124 foreach (SocketInfo s in _listSocketInfo.Values) 125 { 126 s.socket.Close(); 127 } 128 } 129 130 public class SocketInfo 131 { 132 public Socket socket = null; 133 public byte[] buffer = null; 134 public byte[] msgBuffer = null; 135 public bool isConnected = false; 136 137 public SocketInfo() 138 { 139 buffer = new byte[1024 * 4]; 140 } 141 } 142 }
1 public class SocketClientManager 2 { 3 public Socket _socket = null; 4 public EndPoint endPoint = null; 5 public SocketInfo socketInfo = null; 6 public bool _isConnected = false; 7 8 public delegate void OnConnectedHandler(); 9 public event OnConnectedHandler OnConnected; 10 public event OnConnectedHandler OnFaildConnect; 11 public delegate void OnReceiveMsgHandler(); 12 public event OnReceiveMsgHandler OnReceiveMsg; 13 14 public SocketClientManager(string ip, int port) 15 { 16 IPAddress _ip = IPAddress.Parse(ip); 17 endPoint = new IPEndPoint(_ip, port); 18 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 19 } 20 21 public void Start() 22 { 23 _socket.BeginConnect(endPoint, ConnectedCallback, _socket); 24 _isConnected = true; 25 Thread socketClient = new Thread(SocketClientReceive); 26 socketClient.IsBackground = true; 27 socketClient.Start(); 28 } 29 30 public void SocketClientReceive() 31 { 32 while (_isConnected) 33 { 34 SocketInfo info = new SocketInfo(); 35 try { 36 _socket.BeginReceive(info.buffer, 0, info.buffer.Length, SocketFlags.None, ReceiveCallback, info); 37 } 38 catch (SocketException ex) 39 { 40 _isConnected = false; 41 } 42 43 Thread.Sleep(100); 44 } 45 } 46 47 public void ReceiveCallback(IAsyncResult ar) 48 { 49 socketInfo = ar.AsyncState as SocketInfo; 50 if (this.OnReceiveMsg != null) OnReceiveMsg(); 51 } 52 53 public void ConnectedCallback(IAsyncResult ar) 54 { 55 Socket socket = ar.AsyncState as Socket; 56 if (socket.Connected) 57 { 58 if (this.OnConnected != null) OnConnected(); 59 } 60 else 61 { 62 if (this.OnFaildConnect != null) OnFaildConnect(); 63 } 64 } 65 66 public void SendMsg(string msg) 67 { 68 byte[] buffer = Encoding.ASCII.GetBytes(msg); 69 _socket.Send(buffer); 70 } 71 72 public class SocketInfo 73 { 74 public Socket socket = null; 75 public byte[] buffer = null; 76 77 public SocketInfo() 78 { 79 buffer = new byte[1024 * 4]; 80 } 81 } 82 }
具体源码(.net4.5,vs2013):具体源码 https://files.cnblogs.com/files/supheart/ServerBySocket.zip