你的位置:首页 > ASP.net教程

[ASP.net教程]C# Socket系列二 简单的创建 socket 通信


看了系列一 我们开启了对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             else103             {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       try155       {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   }

 

运行结果看出,我们连接成功并且发送消息成功。