看了系列一 我们开启了对socket tcp的监听状态,那么这一章我们来讲解怎么创建socket的通信代码
我新建一个类 TSocketBase
public abstract class TSocketBase { //封装socket internal Socket _Socket; //回调 private AsyncCallback aCallback; //接受数据的缓冲区 private byte[] Buffers; //标识是否已经释放 private volatile bool IsDispose; //10K的缓冲区空间 private int BufferSize = 10*1024; //收取消息状态码 private SocketError ReceiveError; //发送消息的状态码 private SocketError SenderError; //每一次接受到的字节数 private int ReceiveSize = 0; //接受空消息次数 private byte ZeroCount = 0; public abstract void Receive(byte[] rbuff); public void SetSocket() { this.aCallback = new AsyncCallback(this.ReceiveCallback); this.IsDispose = false; this._Socket.ReceiveBufferSize = this.BufferSize; this._Socket.SendBufferSize = this.BufferSize; this.Buffers = new byte[this.BufferSize]; } /// <summary> /// 关闭并释放资源 /// </summary> /// <param name="msg"></param> public void Close(string msg) { if (!this.IsDispose) { this.IsDispose = true; try { try { this._Socket.Close(); } catch { } IDisposable disposable = this._Socket; if (disposable != null) { disposable.Dispose(); } this.Buffers = null; GC.SuppressFinalize(this); } catch (Exception) { } } } /// <summary> /// 递归接收消息方法 /// </summary> internal void ReceiveAsync() { try { if (!this.IsDispose && this._Socket.Connected) { this._Socket.BeginReceive(this.Buffers, 0, this.BufferSize, SocketFlags.None, out SenderError, this.aCallback, this); CheckSocketError(ReceiveError); } } catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); } catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); } } /// <summary> /// 接收消息回调函数 /// </summary> /// <param name="iar"></param> private void ReceiveCallback(IAsyncResult iar) { if (!this.IsDispose) { try { //接受消息 ReceiveSize = _Socket.EndReceive(iar, out ReceiveError); //检查状态码 if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError) { //判断接受的字节数 if (ReceiveSize > 0) { byte[] rbuff = new byte[ReceiveSize]; Array.Copy(this.Buffers, rbuff, ReceiveSize); this.Receive(rbuff); //重置连续收到空字节数 ZeroCount = 0; //继续开始异步接受消息 ReceiveAsync(); } else { ZeroCount++; if (ZeroCount == 5) { this.Close("错误链接"); } } } } catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); } catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); } } } /// <summary> /// 错误判断 /// </summary> /// <param name="socketError"></param> /// <returns></returns> private bool CheckSocketError(SocketError socketError) { switch ((socketError)) { case SocketError.SocketError: case SocketError.VersionNotSupported: case SocketError.TryAgain: case SocketError.ProtocolFamilyNotSupported: case SocketError.ConnectionAborted: case SocketError.ConnectionRefused: case SocketError.ConnectionReset: case SocketError.Disconnecting: case SocketError.HostDown: case SocketError.HostNotFound: case SocketError.HostUnreachable: case SocketError.NetworkDown: case SocketError.NetworkReset: case SocketError.NetworkUnreachable: case SocketError.NoData: case SocketError.OperationAborted: case SocketError.Shutdown: case SocketError.SystemNotReady: case SocketError.TooManyOpenSockets: this.Close(socketError.ToString()); return true; } return false; } /// <summary> /// 发送消息方法 /// </summary> internal int SendMsg(byte[] buffer) { int size = 0; try { if (!this.IsDispose) { size = this._Socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out SenderError); CheckSocketError(SenderError); } } catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); } catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); } buffer = null; return size; } }
上面我们事先了socket的异步接受消息,和同步发送消息已经关闭释放资源代码
接受消息net底层提供的接受消息的方法有很多,为什么我们要选择上面所写的呢?那是为了兼容U3D,silverlight, wpf, wp, wf,等程序可执行,不在重复做相同工作。
现在我们来创建一个实现类 TSocketClient
public class TSocketClient : TSocketBase { /// <summary> /// 是否是服务器端的资源 /// </summary> private bool isServer = false; /// <summary> /// 客户端主动请求服务器 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> public TSocketClient(string ip = "127.0.0.1", int port = 9527) { isServer = false; this._Socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this._Socket.Connect(ip, port); this.SetSocket(); this.ReceiveAsync(); } /// <summary> /// 这个是服务器收到有效链接初始化 /// </summary> /// <param name="socket"></param> public TSocketClient(Socket socket) { isServer = true; this._Socket = socket; this.SetSocket(); this.ReceiveAsync(); } /// <summary> /// 收到消息后 /// </summary> /// <param name="rbuff"></param> public override void Receive(byte[] rbuff) { Console.WriteLine("Receive Msg:" + System.Text.UTF8Encoding.Default.GetString(rbuff)); if (isServer) { this.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Client!")); } } }
因为是测试示例,所以我把服务器和客户端实现类写成了,只是用来不同的构造函数来区分,是客户端还是服务器的标识
接下来我们测试一下代码
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 }
运行结果看出,我们连接成功并且发送消息成功。