源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

常用类之TCP连接类-socket编程

  • 时间:2020-11-05 19:29 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:常用类之TCP连接类-socket编程
tcp一般用于维持一个可信任的连接,比起udp更为安全可靠,在vs.net,分别有tcpclient和udpclient以及tcplistener,一般开发中基本可以满足需要,但是这个有个很大的弊端,对于维持一个时间较长的,相互交互的来说,数据处理不是很明朗,vs/net中还有一个socket类,用他来做一个客户/服务器段,同时在接发数据的时候,能相互独立,这需要一个异步通讯过程 先实现服务器段: using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; // State object for reading client data asynchronously namespace TcpServer { public class StateObject  {     // Client  socket.     public Socket workSocket = null;     // Size of receive buffer.     public const int BufferSize = 1024;     // Receive buffer.     public byte[] buffer = new byte[BufferSize];     // Received data string.     public StringBuilder sb = new StringBuilder();   } public class AsynchronousSocketListener  {     // Thread signal.     public static ManualResetEvent allDone = new ManualResetEvent(false);     private static Socket listener;     private int _port=9010;     public AsynchronousSocketListener()      {     }     public  void StopListening()      {         listener.Close();      }     public int Port     {         set         {         _port=value;         }     }     public  void StartListening()      {         // Data buffer for incoming data.         byte[] bytes = new Byte[1024];         // Establish the local endpoint for the socket.         // The DNS name of the computer         // running the listener is "host.contoso.com".         IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());         IPAddress ipAddress = ipHostInfo.AddressList[0];         IPEndPoint localEndPoint = new IPEndPoint(ipAddress, _port);         // Create a TCP/IP socket.         listener = new Socket(AddressFamily.InterNetwork,             SocketType.Stream, ProtocolType.Tcp );         // Bind the socket to the local endpoint and listen for incoming connections.         try          {             listener.Bind(localEndPoint);             listener.Listen(100);             while (true)              {                 // Set the event to nonsignaled state.                 allDone.Reset();                 // Start an asynchronous socket to listen for connections.                 Console.WriteLine("接收连接..");                 listener.BeginAccept(                      new AsyncCallback(AcceptCallback),                     listener );                 // Wait until a connection is made before continuing.                 allDone.WaitOne();             }         }          catch (Exception e)          {             Console.WriteLine(e.ToString());         }         Console.WriteLine("\nPress ENTER to continue...");         Console.Read();     }     private void AcceptCallback(IAsyncResult ar)      {         // Signal the main thread to continue.         allDone.Set();         // Get the socket that handles the client request.         Socket listener = (Socket) ar.AsyncState;         Socket handler = listener.EndAccept(ar);         // Create the state object.         StateObject state = new StateObject();         state.workSocket = handler;         handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,             new AsyncCallback(ReadCallback), state);     }     private  void ReadCallback(IAsyncResult ar)      {         String content = String.Empty;         // Retrieve the state object and the handler socket         // from the asynchronous state object.         StateObject state = (StateObject) ar.AsyncState;         Socket handler = state.workSocket;         int bytesRead=0 ;         // Read data from the client socket.         if(handler.Connected )         {             try             {                 bytesRead = handler.EndReceive(ar);             }             catch(Exception ex)             {                 handler.Close();              }             if (bytesRead > 0)              {                 // There  might be more data, so store the data received so far.                 // Check for end-of-file tag. If it is not there, read                  // more data.                 content = Encoding.ASCII.GetString(                     state.buffer,0,bytesRead);                 if (content.Length>0 && content.EndsWith("<EOF>")  )                  {                     // All the data has been read from the                      // client. Display it on the console.                     Console.WriteLine("从客户端收到 {0} bytes 数据. \n Data : {1}",                         content.Length, content );                     // Echo the data back to the client.                     Send(handler, "-数据确认,已经收到-<EOF>");                 }                  else                  {                     // Not all data received. Get more.                     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,                         new AsyncCallback(ReadCallback), state);                 }             }         }     }     private void Send(Socket handler, String data)      {         // Convert the string data to byte data using ASCII encoding.         byte[] byteData = Encoding.UTF8.GetBytes(data);         // Begin sending the data to the remote device.         handler.BeginSend(byteData, 0, byteData.Length, 0,             new AsyncCallback(SendCallback), handler);     }     private void SendCallback(IAsyncResult ar)      {         try          {             // Retrieve the socket from the state object.             Socket handler = (Socket) ar.AsyncState;             // Complete sending the data to the remote device.             int bytesSent = handler.EndSend(ar);             Console.WriteLine("发送 {0} bytes 到客户端.", bytesSent);             handler.Shutdown(SocketShutdown.Both);             handler.Close();         }          catch (Exception e)          {             Console.WriteLine(e.ToString());         }     }      } } 具体调用如下: string p="";             AsynchronousSocketListener _server=new AsynchronousSocketListener();             _server.StartListening();             if((p=Console.ReadLine().ToLower() )!="exit" )             {                 _server.StopListening();              } 紧接着实现客户端,客户端稍微复杂点,用一个session类来维持一个会话过程,coder类实现多种编码,Datagram类定义一个具体的数据报文,默认为64个字节大小, using System; using System.Collections;  using System.Runtime.InteropServices; using System.Diagnostics; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading;  using System.Data;  using System.Xml;  using System.Xml.XPath;  namespace Client {     #region 通讯对象     public delegate void NetEvent(object sender, NetEventArgs e);     public class CSocket     {         #region 字段                /// <summary>         /// 客户端与服务器之间的会话类         /// </summary>         private Session _session;         /// <summary>         /// 客户端是否已经连接服务器         /// </summary>         private bool _isConnected = false;         private bool _isEcho = false;         private StringBuilder sb=new StringBuilder();          /// <summary>         /// 接收数据缓冲区大小64K         /// </summary>         public const int DefaultBufferSize = 64*1024;         /// <summary>         /// 报文解析器         /// </summary>         private DatagramResolver _resolver;         /// <summary>         /// 通讯格式编码解码器         /// </summary>         private Coder _coder;                  /// <summary>         /// 接收数据缓冲区         /// </summary>         private byte[] _recvDataBuffer = new byte[DefaultBufferSize];         public  ManualResetEvent allDone = new ManualResetEvent(false);         #endregion         #region 事件定义         //需要订阅事件才能收到事件的通知,如果订阅者退出,必须取消订阅         /// <summary>         /// 已经连接服务器事件         /// </summary>         /// <summary>         /// 接收到数据报文事件         /// </summary>           public event NetEvent ReceivedDatagram;           public event NetEvent DisConnectedServer;     public event NetEvent ConnectedServer;         /// <summary>         /// 连接断开事件         /// </summary>         #endregion         #region 属性         /// <summary>         /// 返回客户端与服务器之间的会话对象         /// </summary>         public Session ClientSession         {             get             {                 return _session;             }         }         /// <summary>         /// 返回客户端与服务器之间的连接状态         /// </summary>         public bool IsConnected         {             get             {                 return _isConnected;             }         }         public bool IsEchoBack         {             get             {                 return _isEcho;             }         }         /// <summary>         /// 数据报文分析器         /// </summary>         public DatagramResolver Resovlver         {             get             {                 return _resolver;             }             set             {                 _resolver = value;             }         }         /// <summary>         /// 编码解码器         /// </summary>         public Coder ServerCoder         {             get             {                 return _coder;             }         }         #endregion         #region 公有方法         /// <summary>         /// 默认构造函数,使用默认的编码格式         /// </summary>         public CSocket()         {             _coder = new Coder( Coder.EncodingMothord.gb2312 );         }                 /// <summary>         /// 构造函数,使用一个特定的编码器来初始化         /// </summary>         /// <param name="_coder">报文编码器</param>         public CSocket( Coder coder )         {             _coder = coder;         }         /// <summary>         /// 连接服务器         /// </summary>         /// <param name="ip">服务器IP地址</param>         /// <param name="port">服务器端口</param>         public virtual void Connect( string ip, int port)         {             if(IsConnected)             {                             Close();             }             Socket newsock= new Socket(AddressFamily.InterNetwork,                 SocketType.Stream, ProtocolType.Tcp);             IPEndPoint iep = new IPEndPoint( IPAddress.Parse(ip), port);             newsock.BeginConnect(iep, new AsyncCallback(Connected), newsock);         }         /// <summary>         /// 发送数据报文         /// </summary>         /// <param name="datagram"></param>         public virtual void Send( string datagram)         {             try             {                 if(datagram.Length ==0 )                 {                     return;                 }                  allDone.WaitOne();                 //获得报文的编码字节                 byte [] data = _coder.GetEncodingBytes(datagram);                 _session.ClientSocket.BeginSend( data, 0, data.Length, SocketFlags.None,                 new AsyncCallback( SendDataEnd ), _session.ClientSocket);             }             catch(Exception ex)             {                 Console.WriteLine(ex.ToString() );              }         }         /// <summary>         /// 关闭连接         /// </summary>         public virtual void Close()         {             if(!_isConnected)             {                 return;             }             _session.Close();             _session = null;             _isConnected = false;         }         #endregion          #region 受保护方法         /// <summary>         /// 数据发送完成处理函数         /// </summary>         /// <param name="iar"></param>         protected virtual void SendDataEnd(IAsyncResult iar)         {             try             {                 Socket remote = (Socket)iar.AsyncState;                 int sent = remote.EndSend(iar);             }             catch(Exception ex)             {                 Console.WriteLine(ex.ToString() );              }         }         /// <summary>         /// 建立Tcp连接后处理过程         /// </summary>         /// <param name="iar">异步Socket</param>         protected virtual void Connected(IAsyncResult iar)         {             Socket socket = (Socket)iar.AsyncState;             //返回一个与之廉洁的连接             socket.EndConnect(iar);             //创建新的会话             _session = new Session(socket);             _isConnected = true;             allDone.Set();                          try             {                 _session.ClientSocket.BeginReceive(_recvDataBuffer, 0,                      DefaultBufferSize, SocketFlags.None,                     new AsyncCallback(RecvData), socket);}             catch(Exception ex)             {                 socket.Close();              }         }         /// <summary>         /// 数据接收处理函数         /// </summary>         /// <param name="iar">异步Socket</param>         public string recevie()         {             return this.sb.ToString()  ;         }         protected virtual void RecvData(IAsyncResult iar)         {             Socket remote = (Socket)iar.AsyncState;             try             {                 string receivedData="" ;                 int recv = remote.EndReceive(iar);                 if(recv>0)                 {     receivedData = System.Text.Encoding.UTF8.GetString(_recvDataBuffer,0,recv )    ;                     if(receivedData.EndsWith("<EOF>")  )                     {                         _isEcho=true;                         sb.Append(receivedData);                          this._session.Datagram=  receivedData;                         if(ReceivedDatagram==null)                         {                         ReceivedDatagram(this,new NetEventArgs(_session)  ) ;                         }                         Console.WriteLine(string.Format("{0},来自{1}",receivedData,_session.ClientSocket.RemoteEndPoint.ToString()  ) ) ;                         this.allDone.Set();                                                 }                     else                     {                         Console.WriteLine("listen");                          _session.ClientSocket.BeginReceive(_recvDataBuffer, 0, DefaultBufferSize, SocketFlags.None,                             new AsyncCallback(RecvData), _session.ClientSocket);                     }                 }                                           }             catch(SocketException ex)             {                 Console.WriteLine(ex.ToString() );              }         }         #endregion     }     /// <summary>     /// 通讯编码格式提供者,为通讯服务提供编码和解码服务     /// 你可以在继承类中定制自己的编码方式如:数据加密传输等     /// </summary>     public class Coder     {         /// <summary>         /// 编码方式         /// </summary>         private EncodingMothord _encodingMothord;         protected Coder()         {         }         public Coder(EncodingMothord encodingMothord)         {             _encodingMothord = encodingMothord;         }         public enum EncodingMothord         {             gb2312=0,             Default ,             Unicode,             UTF8,             ASCII,         }         /// <summary>         /// 通讯数据解码         /// </summary>         /// <param name="dataBytes">需要解码的数据</param>         /// <returns>编码后的数据</returns>         public virtual string GetEncodingString( byte [] dataBytes,int size)         {             switch( _encodingMothord )              {                 case EncodingMothord.gb2312:                 {                     return Encoding.GetEncoding("gb2312").GetString(dataBytes,0,size);                 }                 case EncodingMothord.Default:                 {                     return Encoding.Default.GetString(dataBytes,0,size);                 }                 case EncodingMothord.Unicode:                 {                     return Encoding.Unicode.GetString(dataBytes,0,size);                 }                 case EncodingMothord.UTF8:                 {                     return Encoding.UTF8.GetString(dataBytes,0,size);                 }                 case EncodingMothord.ASCII:                 {                     return Encoding.ASCII.GetString(dataBytes,0,size);                 }                 default:                 {                     throw( new Exception("未定义的编码格式"));                 }             }         }         /// <summary>         /// 数据编码         /// </summary>         /// <param name="datagram">需要编码的报文</param>         /// <returns>编码后的数据</returns>         public virtual byte[] GetEncodingBytes(string datagram)         {             switch( _encodingMothord)              {                 case EncodingMothord.gb2312:                 {                     return Encoding.GetEncoding("gb2312").GetBytes(datagram);                 }                 case EncodingMothord.Default:                 {                     return Encoding.Default.GetBytes(datagram);                 }                 case EncodingMothord.Unicode:                 {                     return Encoding.Unicode.GetBytes(datagram);                 }                 case EncodingMothord.UTF8:                 {                     return Encoding.UTF8.GetBytes(datagram);                 }                 case EncodingMothord.ASCII:                 {                     return Encoding.ASCII.GetBytes(datagram);                 }                 default:                 {                     throw( new Exception("未定义的编码格式"));                 }             }         }     }     /// <summary>     /// 数据报文分析器,通过分析接收到的原始数据,得到完整的数据报文.     /// 继承该类可以实现自己的报文解析方法.     /// 通常的报文识别方法包括:固定长度,长度标记,标记符等方法     /// 本类的现实的是标记符的方法,你可以在继承类中实现其他的方法     /// </summary>     public class DatagramResolver     {         /// <summary>         /// 报文结束标记         /// </summary>         private string endTag;         /// <summary>         /// 返回结束标记         /// </summary>         string EndTag         {             get             {                 return endTag;             }         }         /// <summary>         /// 受保护的默认构造函数,提供给继承类使用         /// </summary>         protected DatagramResolver()         {         }         /// <summary>         /// 构造函数         /// </summary>         /// <param name="endTag">报文结束标记</param>         public DatagramResolver(string endTag)         {             if(endTag == null)             {                 throw (new ArgumentNullException("结束标记不能为null"));             }             if(endTag == "")             {                 throw (new ArgumentException("结束标记符号不能为空字符串"));             }             this.endTag = endTag;         }         /// <summary>         /// 解析报文         /// </summary>         /// <param name="rawDatagram">原始数据,返回未使用的报文片断,         /// 该片断会保存在Session的Datagram对象中</param>         /// <returns>报文数组,原始数据可能包含多个报文</returns>         public virtual string [] Resolve(ref string rawDatagram)         {             ArrayList datagrams  = new ArrayList();             //末尾标记位置索引             int tagIndex =-1;             while(true)             {                 tagIndex = rawDatagram.IndexOf(endTag,tagIndex+1);                 if( tagIndex == -1 )                 {                     break;                 }                 else                 {                     //按照末尾标记把字符串分为左右两个部分                     string newDatagram = rawDatagram.Substring(                         0, tagIndex+endTag.Length);                     datagrams.Add(newDatagram);                     if(tagIndex+endTag.Length >= rawDatagram.Length)                     {                         rawDatagram="";                         break;                     }                     rawDatagram = rawDatagram.Substring(tagIndex+endTag.Length,                         rawDatagram.Length - newDatagram.Length);                     //从开始位置开始查找                     tagIndex=0;                 }             }             string [] results= new string[datagrams.Count];             datagrams.CopyTo(results);             return results;         }     }     /// <summary>     /// 客户端与服务器之间的会话类     ///      /// 版本:  1.1     /// 替换版本: 1.0     ///      /// 说明:     ///    会话类包含远程通讯端的状态,这些状态包括Socket,报文内容,     ///    客户端退出的类型(正常关闭,强制退出两种类型)     /// </summary>     public class Session:ICloneable     {         #region 字段         /// <summary>         /// 会话ID         /// </summary>         private SessionId _id;         /// <summary>         /// 客户端发送到服务器的报文         /// 注意:在有些情况下报文可能只是报文的片断而不完整         /// </summary>         private string _datagram;         /// <summary>         /// 客户端的Socket         /// </summary>         private Socket _cliSock;         /// <summary>         /// 客户端的退出类型         /// </summary>         private ExitType _exitType;         /// <summary>         /// 退出类型枚举         /// </summary>         public enum ExitType         {             NormalExit ,             ExceptionExit         };         #endregion         #region 属性         /// <summary>         /// 返回会话的ID         /// </summary>         public SessionId ID         {             get             {                 return _id;             }         }         /// <summary>         /// 存取会话的报文         /// </summary>         public string Datagram         {             get             {                 return _datagram;             }             set             {                 _datagram = value;             }         }         /// <summary>         /// 获得与客户端会话关联的Socket对象         /// </summary>         public Socket ClientSocket         {             get             {                 return _cliSock;             }         }         /// <summary>         /// 存取客户端的退出方式         /// </summary>         public ExitType TypeOfExit         {             get             {                 return _exitType;             }             set    
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部