看了系列一 我们开启了对socket tcp的监听状态,那么这一章我们来讲解怎么创建socket的通信代码
我新建一个类 TSocketBase
1 public abstract class TSocketBase 2 { 3 //封装socket 4 internal Socket _Socket; 5 //回调 6 private AsyncCallback aCallback; 7 //接受数据的缓冲区 8 private byte[] Buffers; 9 //标识是否已经释放 10 private volatile bool IsDispose; 11 //10K的缓冲区空间 12 private int BufferSize = 10 * 1024; 13 //收取消息状态码 14 private SocketError ReceiveError; 15 //发送消息的状态码 16 private SocketError SenderError; 17 //每一次接受到的字节数 18 private int ReceiveSize = 0; 19 //接受空消息次数 20 byte ZeroCount = 0; 21 22 public abstract void Receive(byte[] rbuff); 23 24 public void SetSocket() 25 { 26 this.aCallback = new AsyncCallback(this.ReceiveCallback); 27 this.IsDispose = false; 28 this._Socket.ReceiveBufferSize = this.BufferSize; 29 this._Socket.SendBufferSize = this.BufferSize; 30 this.Buffers = new byte[this.BufferSize]; 31 } 32 33 34 /// <summary> 35 /// 关闭并释放资源 36 /// </summary> 37 /// <param name="msg"></param> 38 public void Close(string msg) 39 { 40 if (!this.IsDispose) 41 { 42 this.IsDispose = true; 43 try 44 { 45 try { this._Socket.Close(); } 46 catch { } 47 IDisposable disposable = this._Socket; 48 if (disposable != null) { disposable.Dispose(); } 49 this.Buffers = null; 50 GC.SuppressFinalize(this); 51 } 52 catch (Exception) { } 53 } 54 } 55 56 57 /// <summary> 58 /// 递归接收消息方法 59 /// </summary> 60 internal void ReceiveAsync() 61 { 62 try 63 { 64 if (!this.IsDispose && this._Socket.Connected) 65 { 66 this._Socket.BeginReceive(this.Buffers, 0, this.BufferSize, SocketFlags.None, out SenderError, this.aCallback, this); 67 CheckSocketError(ReceiveError); 68 } 69 } 70 catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); } 71 catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); } 72 } 73 74 75 76 /// <summary> 77 /// 接收消息回调函数 78 /// </summary> 79 /// <param name="iar"></param> 80 private void ReceiveCallback(IAsyncResult iar) 81 { 82 if (!this.IsDispose) 83 { 84 try 85 { 86 //接受消息 87 ReceiveSize = _Socket.EndReceive(iar, out ReceiveError); 88 //检查状态码 89 if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError) 90 { 91 //判断接受的字节数 92 if (ReceiveSize > 0) 93 { 94 byte[] rbuff = new byte[ReceiveSize]; 95 Array.Copy(this.Buffers, rbuff, ReceiveSize); 96 this.Receive(rbuff); 97 //重置连续收到空字节数 98 ZeroCount = 0; 99 //继续开始异步接受消息 100 ReceiveAsync(); 101 } 102 else 103 { 104 ZeroCount++; 105 if (ZeroCount == 5) { this.Close("错误链接"); } 106 } 107 } 108 } 109 catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); } 110 catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); } 111 } 112 } 113 114 /// <summary> 115 /// 错误判断 116 /// </summary> 117 /// <param name="socketError"></param> 118 /// <returns></returns> 119 bool CheckSocketError(SocketError socketError) 120 { 121 switch ((socketError)) 122 { 123 case SocketError.SocketError: 124 case SocketError.VersionNotSupported: 125 case SocketError.TryAgain: 126 case SocketError.ProtocolFamilyNotSupported: 127 case SocketError.ConnectionAborted: 128 case SocketError.ConnectionRefused: 129 case SocketError.ConnectionReset: 130 case SocketError.Disconnecting: 131 case SocketError.HostDown: 132 case SocketError.HostNotFound: 133 case SocketError.HostUnreachable: 134 case SocketError.NetworkDown: 135 case SocketError.NetworkReset: 136 case SocketError.NetworkUnreachable: 137 case SocketError.NoData: 138 case SocketError.OperationAborted: 139 case SocketError.Shutdown: 140 case SocketError.SystemNotReady: 141 case SocketError.TooManyOpenSockets: 142 this.Close(socketError.ToString()); 143 return true; 144 } 145 return false; 146 } 147 148 /// <summary> 149 /// 发送消息方法 150 /// </summary> 151 internal int SendMsg(byte[] buffer) 152 { 153 int size = 0; 154 try 155 { 156 if (!this.IsDispose) 157 { 158 size = this._Socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out SenderError); 159 CheckSocketError(SenderError); 160 } 161 } 162 catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); } 163 catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); } 164 buffer = null; 165 return size; 166 } 167 }
上面我们事先了socket的异步接受消息,和同步发送消息已经关闭释放资源代码
接受消息net底层提供的接受消息的方法有很多,为什么我们要选择上面所写的呢?那是为了兼容U3D,silverlight, wpf, wp, wf,等程序可执行,不在重复做相同工作。
现在我们来创建一个实现类 TSocketClient
1 public class TSocketClient : TSocketBase 2 { 3 /// <summary> 4 /// 是否是服务器端的资源 5 /// </summary> 6 bool isServer = false; 7 8 /// <summary> 9 /// 客户端主动请求服务器 10 /// </summary> 11 /// <param name="ip"></param> 12 /// <param name="port"></param> 13 public TSocketClient(string ip = "127.0.0.1", int port = 9527) 14 { 15 isServer = false; 16 this._Socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 17 this._Socket.Connect(ip, port); 18 this.SetSocket(); 19 this.ReceiveAsync(); 20 } 21 /// <summary> 22 /// 这个是服务器收到有效链接初始化 23 /// </summary> 24 /// <param name="socket"></param> 25 public TSocketClient(Socket socket) 26 { 27 isServer = true; 28 this._Socket = socket; 29 this.SetSocket(); 30 this.ReceiveAsync(); 31 } 32 33 /// <summary> 34 /// 收到消息后 35 /// </summary> 36 /// <param name="rbuff"></param> 37 public override void Receive(byte[] rbuff) 38 { 39 Console.WriteLine("Receive Msg:" + System.Text.UTF8Encoding.Default.GetString(rbuff)); 40 if (isServer) 41 { 42 this.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Client!")); 43 } 44 } 45 }
因为是测试示例,所以我把服务器和客户端实现类写成了,只是用来不同的构造函数来区分,是客户端还是服务器的标识
接下来我们测试一下代码
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 TCPListener tcp = new TCPListener(); 6 TSocketClient client = new TSocketClient(); 7 client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!")); 8 Console.ReadLine(); 9 } 10 }
运行结果看出,我们连接成功并且发送消息成功。