【 tulaoshi.com - 编程语言 】
                             
                            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.Length0 && 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(recv0) 
                { 
    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 
        { 
 &nbs