好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Socket编程 (异步通讯) (Tcp,Udp)Part2

Socket编程 (异步通讯) (Tcp,Udp)Part2

Socket编程 (异步通讯) (Tcp,Udp) - Part2

Socket编程(异步通讯)(Tcp,Udp)

  上一章主要展示了Socket的Tcp\Udp两种协议下的基本通讯方式,属于同步通讯。至于一个服务器对应多个客户端,或者对应多个请求,我们采用的是多线程的方式来解决此问题。然而本章节我们将有更好的方式去实现它: Socket在Tcp\Udp两种协议下的异步通讯方式。

基于Tcp协议异步:

   BeginAccept 方法和 EndAccept 方法

  包含在 System.Net.Sockets 命名空间下 。异步Tcp使用 BeginAccept方法开始接受新的客户端连接请求,该方法中 系统自动利用线程池创建需要的线程,并在操作完成时利用异步回调机制调用提供给它的方法,同时返回相应的状态参数,然后方可利用EndAccept方法结束该连接请求.

   BeginRecive 方法和 EndRecive 方法

  异步Tcp使用BeginRecive方法和开始接受客户端发送的的消息,该方法如上同理,接受完毕后调用回调函数传递相应的状态参数。利用EndRecive方法接受接受消息。

  至于 BeginSend方法和EndSend方法、 BeginConnect 方法和 End Connect 方法 与上类似。

下面我们来看看如何在Tcp协议下进行客户端与服务器端之间的通讯:

服务器端:   

 using   System;
  using   System.Collections.Generic;
  using   System.Text;
  #region  命名空间
 using   System.Net;
  using   System.Net.Sockets;
  using   System.Threading;
  #endregion 

 namespace   AsynServerConsole
{
      ///   <summary> 
     ///   Tcp协议异步通讯类(服务器端)
      ///   </summary> 
     public   class   AsynTcpServer
    {
          #region  Tcp协议异步监听
         ///   <summary> 
         ///   Tcp协议异步监听
          ///   </summary> 
         public   void   StartListening()
        {
              //  主机IP 
            IPEndPoint serverIp =  new  IPEndPoint(IPAddress.Parse( "  127.0.0.1  " ),  8686  );
            Socket tcpServer  =  new   Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            tcpServer.Bind(serverIp);
            tcpServer.Listen(  100  );
            Console.WriteLine(  "  异步开启监听...  "  );
            AsynAccept(tcpServer);
        }
          #endregion 

         #region  异步连接客户端
         ///   <summary> 
         ///   异步连接客户端
          ///   </summary> 
         ///   <param name="tcpServer"></param> 
         public   void   AsynAccept(Socket tcpServer)
        {
            tcpServer.BeginAccept(asyncResult  => 
            {
                Socket tcpClient  =  tcpServer.EndAccept(asyncResult);
                Console.WriteLine(  "  server<--<--{0}  "  , tcpClient.RemoteEndPoint.ToString());
                AsynSend(tcpClient,   "  收到连接...  " ); //  发送消息 
                 AsynAccept(tcpServer);
                AsynRecive(tcpClient);
            },   null  );
        }
          #endregion 

         #region  异步接受客户端消息
         ///   <summary> 
         ///   异步接受客户端消息
          ///   </summary> 
         ///   <param name="tcpClient"></param> 
         public   void   AsynRecive(Socket tcpClient)
        {
              byte [] data =  new   byte [ 1024  ];
              try  
            {
                tcpClient.BeginReceive(data,   0  , data.Length, SocketFlags.None,
                asyncResult  => 
                {
                      int  length =  tcpClient.EndReceive(asyncResult);
                    Console.WriteLine(  "  server<--<--client:{0}  "  , Encoding.UTF8.GetString(data));
                    AsynSend(tcpClient,   "  收到消息...  "  );
                    AsynRecive(tcpClient);
                },   null  );
            }
              catch   (Exception ex)
            {
                Console.WriteLine(  "  异常信息:  "  , ex.Message);
            }
        }
          #endregion 

         #region  异步发送消息
         ///   <summary> 
         ///   异步发送消息
          ///   </summary> 
         ///   <param name="tcpClient">  客户端套接字  </param> 
         ///   <param name="message">  发送消息  </param> 
         public   void  AsynSend(Socket tcpClient,  string   message)
        {
              byte [] data =  Encoding.UTF8.GetBytes(message);
              try  
            {
                tcpClient.BeginSend(data,   0 , data.Length, SocketFlags.None, asyncResult => 
                {
                      //  完成发送消息 
                     int  length =  tcpClient.EndSend(asyncResult);
                    Console.WriteLine(  "  server-->-->client:{0}  "  , message);
                },   null  );
            }
              catch   (Exception ex)
            {
                Console.WriteLine(  "  异常信息:{0}  "  , ex.Message);
            }
        }
          #endregion  
    }
} 

客户端:

 using   System;
  using   System.Collections.Generic;
  using   System.Text;
  #region  命名空间
 using   System.Net;
  using   System.Net.Sockets;
  using   System.Threading;
  #endregion 

 namespace   AsynClientConsole
{
      ///   <summary> 
     ///   Tcp协议异步通讯类(客户端)
      ///   </summary> 
     public   class   AsynTcpClient
    {
          #region  异步连接
         ///   <summary> 
         ///   Tcp协议异步连接服务器
          ///   </summary> 
         public   void   AsynConnect()
        {
              //  主机IP 
            IPEndPoint serverIp =  new  IPEndPoint(IPAddress.Parse( "  127.0.0.1  " ),  8686  );
            Socket tcpClient  =  new   Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            tcpClient.BeginConnect(serverIp, asyncResult  => 
            {
                tcpClient.EndConnect(asyncResult);
                Console.WriteLine(  "  client-->-->{0}  "  , serverIp.ToString());
                AsynSend(tcpClient,   "  我上线了...  "  );
                AsynSend(tcpClient,   "  第一次发送消息...  "  );
                AsynSend(tcpClient,   "  第二次发送消息...  "  );
                AsynRecive(tcpClient);
            },   null  );
        }
          #endregion 

         #region  异步接受消息
         ///   <summary> 
         ///   异步连接客户端回调函数
          ///   </summary> 
         ///   <param name="tcpClient"></param> 
         public   void   AsynRecive(Socket tcpClient)
        {
              byte [] data =  new   byte [ 1024  ];
            tcpClient.BeginReceive(data,   0 , data.Length, SocketFlags.None, asyncResult => 
            {
                  int  length =  tcpClient.EndReceive(asyncResult);
                Console.WriteLine(  "  client<--<--server:{0}  "  , Encoding.UTF8.GetString(data));
                AsynRecive(tcpClient);
            },   null  );
        }
          #endregion 

         #region  异步发送消息
         ///   <summary> 
         ///   异步发送消息
          ///   </summary> 
         ///   <param name="tcpClient">  客户端套接字  </param> 
         ///   <param name="message">  发送消息  </param> 
         public   void  AsynSend(Socket tcpClient,  string   message)
        {
              byte [] data =  Encoding.UTF8.GetBytes(message);
            tcpClient.BeginSend(data,   0 , data.Length, SocketFlags.None, asyncResult => 
            {
                  //  完成发送消息 
                 int  length =  tcpClient.EndSend(asyncResult);
                Console.WriteLine(  "  client-->-->server:{0}  "  , message);
            },   null  );
        }
          #endregion  
    }
} 

通讯效果如下图:

服务器:

客户端:

上面我们完成了基于Tcp协议下的Socket通讯,那么Udp协议下的通讯我们将以什么样的形式来通讯呢?毕竟Udp协议下是无连接模式。

基于Udp协议的异步通讯:

  其实与Tcp协议具有的方法类似,但由于Udp协议是无连接模式,我们所用到方法就无BeginConnect和EndConnect方法。我们所要做的就是收发消息的处理。

  在Udp协议的异步通讯中,我们需要注意一下几个编程点:

  1.在EndRecive方法中,由于无状态返回模式,不能返回发送端的Remote,所以我们需要在该方法中获取活动端的Remote,然后利用EndRecive方法结束接受该消息接受。

  2.客户端由于无需Connect到服务器端,但是需要先向服务器端发送一个请求如Send一些消息。让服务器端确定自己Remote,然后可利用Recive方法接收其他终端发送过来的消息。

下面将演示Udp协议下异步通讯:

服务器端:

 using   System;
  using   System.Collections.Generic;
  using   System.Text;
  #region  命名空间
 using   System.Net;
  using   System.Net.Sockets;
  using   System.Threading;
  #endregion 

 namespace   AsynServerConsole
{
      ///   <summary> 
     ///   Udp协议异步通讯类(服务器端)
      ///   </summary> 
     public   class   AsynUdpServer
    {
          #region  容器对象
         ///   <summary> 
         ///   容器对象
          ///   </summary> 
         public   class   StateObject
        {
              //  服务器端 
             public  Socket udpServer =  null  ;
              //  接受数据缓冲区 
             public   byte [] buffer =  new   byte [ 1024  ];
              //  远程终端 
             public   EndPoint remoteEP;
        }

          public   StateObject state;
          #endregion 

         #region  服务器绑定终端节点
         public   void   ServerBind()
        {
              //  主机IP 
            IPEndPoint serverIp =  new  IPEndPoint(IPAddress.Parse( "  127.0.0.1  " ),  8686  );
            Socket udpServer  =  new   Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            udpServer.Bind(serverIp);
            Console.WriteLine(  "  server ready...  "  );
            IPEndPoint clientIp  =  new  IPEndPoint(IPAddress.Any,  0  );
            state  =  new   StateObject();
            state.udpServer  =  udpServer;
            state.remoteEP  =  (EndPoint)clientIp;
            AsynRecive();
        }
          #endregion 

         #region  异步接受消息
         public   void   AsynRecive()
        {
            state.udpServer.BeginReceiveFrom(state.buffer,   0 , state.buffer.Length, SocketFlags.None,  ref   state.remoteEP,
                  new  AsyncCallback(ReciveCallback),  null  );
        }
          #endregion 

         #region  异步接受消息回调函数
         public   void   ReciveCallback(IAsyncResult asyncResult)
        {
              if   (asyncResult.IsCompleted)
            {
                  //  获取发送端的终节点 
                IPEndPoint ipep =  new  IPEndPoint(IPAddress.Any,  0  );
                EndPoint remoteEP  =  (EndPoint)ipep;
                state.udpServer.EndReceiveFrom(asyncResult,   ref   remoteEP);
                Console.WriteLine(  "  server<--<--client:{0}  "  , Encoding.UTF8.GetString(state.buffer));
                  //  向发送端通知:收到消息 
                state.remoteEP =  remoteEP;
                AsynSend(  "  收到消息  "  );
                  //  继续接受消息 
                 AsynRecive();
            }
        }
          #endregion 

         #region  异步发送消息
         public   void  AsynSend( string   message)
        {
            Console.WriteLine(  "  server-->-->client:{0}  "  , message);
              byte [] buffer =  Encoding.UTF8.GetBytes(message);
            state.udpServer.BeginSendTo(buffer,   0  , buffer.Length, SocketFlags.None, state.remoteEP,
                  new  AsyncCallback(SendCallback),  null  );
        }
          #endregion 

         #region  异步发送消息回调函数
         public   void   SendCallback(IAsyncResult asyncResult)
        {
              //  消息发送完毕 
             if   (asyncResult.IsCompleted)
            {
                state.udpServer.EndSendTo(asyncResult);
            }
        }
          #endregion  
    }
} 

客户端:

 using   System;
  using   System.Collections.Generic;
  using   System.Text;
  #region  命名空间
 using   System.Net;
  using   System.Net.Sockets;
  using   System.Threading;
  #endregion 

 namespace   AsynClientConsole
{
      ///   <summary> 
     ///   Udp协议异步通讯类(客户端)
      ///   </summary> 
     public   class   AsynUdpClient
    {
          #region  容器对象
         ///   <summary> 
         ///   容器对象
          ///   </summary> 
         public   class   StateObject
        {
              //  客户端套接字 
             public  Socket udpClient =  null  ;
              //  接收信息缓冲区 
             public   byte [] buffer =  new   byte [ 1024  ];
              //  服务器端终节点 
             public   IPEndPoint serverIp;
              //  远程终端节点 
             public   EndPoint remoteEP;
        }

          public   StateObject state;
          #endregion 

         #region  客户端初始化
         public   void   InitClient()
        {
            state  =  new   StateObject();
            state.udpClient  =  new   Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            state.serverIp  =  new  IPEndPoint(IPAddress.Parse( "  127.0.0.1  " ),  8686  );
            state.remoteEP  = (EndPoint)( new  IPEndPoint(IPAddress.Any,  0  ));
              //  此处注意:
              //    由于当前是客户端,所以没有绑定终节点
              //    不可直接接收消息,必须先向其他终端发送信息告知本机终节点 
            AsynSend( "  第1次发送消息  "  );
            AsynSend(  "  第2次发送消息  "  );
            AsynRecive();
        }
          #endregion 

         #region  异步接收来自其他终端发送的消息
         public   void   AsynRecive()
        {
            state.udpClient.BeginReceiveFrom(state.buffer,   0 , state.buffer.Length, SocketFlags.None,  ref   state.remoteEP,
                  new  AsyncCallback(ReciveCallback),  null  );
        }
          #endregion 

         #region  异步接收来自其他终端发送的消息回调函数
         public   void   ReciveCallback(IAsyncResult asyncResult)
        {
              //  信息接收完成 
             if   (asyncResult.IsCompleted)
            {
                state.udpClient.EndReceiveFrom(asyncResult,   ref   state.remoteEP);
                Console.WriteLine(  "  client<--<--{0}:{1}  "  , state.remoteEP.ToString(), Encoding.UTF8.GetString(state.buffer));
                AsynRecive();
            }
        }
          #endregion 

         #region  异步发送消息
         public   void  AsynSend( string   message)
        {
            Console.WriteLine(  "  client-->-->{0}:{1}  "  , state.serverIp.ToString(), message);
              byte [] buffer =  Encoding.UTF8.GetBytes(message);
            state.udpClient.BeginSendTo(buffer,   0  , buffer.Length, SocketFlags.None, state.serverIp,
                  new  AsyncCallback(SendCallback),  null  );
        }
          #endregion 

         #region  异步发送消息回调函数
         public   void   SendCallback(IAsyncResult asyncResult)
        {
              //  消息发送完成 
             if   (asyncResult.IsCompleted)
            {
                state.udpClient.EndSendTo(asyncResult);
            }
        }
          #endregion  
    }
} 

通讯效果如下图:

服务器:

客户端:

总结:基于异步模式的通讯无须采用多线程来服务多个客户端以及多个请求,这样的通讯模式效率更高。

  同步上面Tcp效果展示图,我们发现客户端分几次连续发送的消息被服务器端一次接收了,读成了一条数据,而这就是Socket通讯基于Tcp协议下发生的 粘包 问题,下面一种我们将着重对Tcp协议的通讯信息封包,拆包以解决上面问题。

  同样Udp协议通讯下属于无连接模式通讯,客户端只管将消息发送出去,或者由于网络原因,而造成的 丢包 问题,下一章也将采用一定的方式解决。

最后附上源码: Socket-Part2.zip

 作者: 曾庆雷 
出处: http://www.cnblogs.com/zengqinglei 
本页版权归作者和博客园所有,欢迎转载,但未经作者同意必须保留此段声明, 且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利 

 

 

 

标签:  Socket ,  Tcp ,  Udp ,  Socket通讯

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Socket编程 (异步通讯) (Tcp,Udp)Part2的详细内容...

  阅读:52次

上一篇: bpm流程平台

下一篇:memcache 和appfabric