zoukankan      html  css  js  c++  java
  • C# Socket

      C# Socket异步通讯是如何实现的呢?C# Socket异步通讯客户端设计的思路是什么呢?那么本文就向你介绍具体的内容。

      C# Socket异步通讯客户端实现源码

      C# Socket异步通讯客户端之主程序:

      1. public static int Main(String[] args)  
      2. {  
      3.  
      4. IPAddress ipAddress = IPAddress.Parse("192.168.1.104");  
      5. int port = 20000;  
      6. IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);  
      7.  
      8. // 生成一个TCP/IP socket.  
      9. Socket client = new Socket(AddressFamily.InterNetwork,  
      10. SocketType.Stream, ProtocolType.Tcp);  
      11.  
      12. // 与目标终端连接.  
      13. client.BeginConnect(remoteEP,  
      14. new AsyncCallback(ConnectCallback), client);  
      15. //等待,直到连接程序完成。在ConnectCallback中适当位置有connecDone.Set()语句  
      16. connectDone.WaitOne();  
      17.  
      18. // 发送数据到远程终端.  
      19. Send(client, "This is a test<EOF>");  
      20. sendDone.WaitOne();  
      21.  
      22. // 接收返回数据.  
      23. Receive(client);  
      24. receiveDone.WaitOne();  
      25.  
      26. // Write the response to the console.  
      27. Console.WriteLine("Response received : {0}", response);  
      28.  
      29. // Release the socket.  
      30. client.Shutdown(SocketShutdown.Both);  
      31. client.Close();  
      32.  
      33. return 0;  
      34.  

      C# Socket异步通讯客户端之连接部分Callback:

      1. private static void ConnectCallback(IAsyncResult ar)  
      2. {  
      3.  
      4. // 从state对象获取socket.  
      5. Socket client = (Socket)ar.AsyncState;  
      6.  
      7. // 完成连接.  
      8. client.EndConnect(ar);  
      9.  
      10. Console.WriteLine("Socket connected to {0}",  
      11. client.RemoteEndPoint.ToString());  
      12.  
      13. // 连接已完成,主线程继续.  
      14. connectDone.Set();  

      C# Socket异步通讯客户端之数据接收:

      1.    private static void Receive(Socket client)  
      2. {  
      3.  
      4. // 构造容器state.  
      5. StateObject state = new StateObject();  
      6. state.workSocket = client;  
      7.  
      8. // 从远程目标接收数据.  
      9. client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
      10. new AsyncCallback(ReceiveCallback), state);  
      11.     
      12. }  
      13.  
      14. private static void ReceiveCallback(IAsyncResult ar)  
      15. {  
      16.  
      17. // 从输入参数异步state对象中获取state和socket对象  
      18. StateObject state = (StateObject)ar.AsyncState;  
      19. Socket client = state.workSocket;  
      20.  
      21. //从远程设备读取数据  
      22. int bytesRead = client.EndReceive(ar);  
      23.  
      24. if (bytesRead > 0)  
      25. {  
      26. // 有数据,存储.  
      27. state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));  
      28.  
      29. // 继续读取.  
      30. client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
      31. new AsyncCallback(ReceiveCallback), state);  
      32. }  
      33. else 
      34. {  
      35. // 所有数据读取完毕.  
      36. if (state.sb.Length > 1)  
      37. {  
      38. response = state.sb.ToString();  
      39. }  
      40. // 所有数据读取完毕的指示信号.  
      41. receiveDone.Set();  
      42. }  
      43.  

      C# Socket异步通讯客户端之发送数据:

      1. private static void Send(Socket client, String data)  
      2. {  
      3. // 格式转换.  
      4. byte[] byteData = Encoding.ASCII.GetBytes(data);  
      5.  
      6. // 开始发送数据到远程设备.  
      7. client.BeginSend(byteData, 0, byteData.Length, 0,  
      8. new AsyncCallback(SendCallback), client);  
      9. }  
      10.  
      11. private static void SendCallback(IAsyncResult ar)  
      12. {  
      13.  
      14. // 从state对象中获取socket  
      15. Socket client = (Socket)ar.AsyncState;  
      16.  
      17. // 完成数据发送.  
      18. int bytesSent = client.EndSend(ar);  
      19. Console.WriteLine("Sent {0} bytes to server.", bytesSent);  
      20.  
      21. // 指示数据已经发送完成,主线程继续.  
      22. sendDone.Set();  
      23.  

      C# Socket异步通讯客户端的实现源码内容就基本向你介绍到这里,希望对你了解和学习C# Socket异步通讯有所帮助。

       

      其实只要用到Socket联接,基本上就得使用Thread,是交叉使用的。
      C#封装的Socket用法基本上不算很复杂,只是不知道托管之后的Socket有没有其他性能或者安全上的问题。
      在C#里面能找到的最底层的操作也就是socket了,概念不做解释。
      程序模型如下:
      WinForm程序 : 启动端口侦听;监视Socket联接情况;定期关闭不活动的联接;
      Listener:处理Socket的Accept函数,侦听新链接,建立新Thread来处理这些联接(Connection)。
      Connection:处理具体的每一个联接的会话。

      1:WinForm如何启动一个新的线程来启动Listener:
             //start the server
              private void btn_startServer_Click(object sender, EventArgs e)
              {
                  //this.btn_startServer.Enabled = false;
                  Thread _createServer = new Thread(new ThreadStart(WaitForConnect));
                  _createServer.Start();
              }
              //wait all connections
              private void WaitForConnect()
              {
                  SocketListener listener = new SocketListener(Convert.ToInt32(this.txt_port.Text));
                   listener.StartListening();
              }
      因为侦听联接是一个循环等待的函数,所以不可能在WinForm的线程里面直接执行,不然Winform也就是无法继续任何操作了,所以才指定一个新的线程来执行这个函数,启动侦听循环。
      这一个新的线程是比较简单的,基本上没有启动的参数,直接指定处理函数就可以了。
      2:Listener如何启动循环侦听,并且启动新的带有参数的线程来处理Socket联接会话。
      先看如何建立侦听:(StartListening函数)
      IPEndPoint localEndPoint = new IPEndPoint(_ipAddress, _port);
              // Create a TCP/IP socket.
              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(20);//20 trucks

                      // Start listening for connections.
                      while (true)
                      {
                         // here will be suspended while waiting for a new connection.
                          Socket connection = listener.Accept();
                          Logger.Log("Connect", connection.RemoteEndPoint.ToString());//log it, new connection
                      ……
                 }
               }……
      基本步骤比较简单:
      建立本机的IPEndPoint对象,表示以本机为服务器,在指定端口侦听;
      然后绑定到一个侦听Socket上;
      进入while循环,等待新的联接;
      如果有新的联接,那么建立新的socket来对应这个联接的会话。
         值得注意的就是这一句联接代码:listener.Accept()。执行这一句的时候,程序就在这个地方等待,直到有新的联检请求的时候程序才会执行下一句。这是同步执行,当然也可以异步执行。
       
         新的联接Socket建立了(Accept之后),对于这些新的socket该怎么办呢?他们依然是一个循环等待,所以依然需要建立新的Thread给这些Socket去处理会话(接收/发送消息),而这个Thread就要接收参数了。
         Thread本身是不能接收参数的,为了让它可以接收参数,可以采用定义新类,添加参数作为属性的方法来解决。
         因为每一个Socket是一个Connection周期,所以我定义了这么一个类public class Connection。这个类至少有这样一个构造函数public Connection(Socket socket); 之所以这么做,就是为了把Socket参数传给这个Connection对象,然后好让Listener启动这个Thread的时候,Thread可以知道他正在处理哪一个Socket。
          具体处理的方法:(在Listener的StartListening函数,ocket connection = listener.Accept();之后)
          Connection gpsCn = new Connection(connection);
                          //each socket will be wait for data. keep the connection.
                          Thread thread = new Thread(new ThreadStart(gpsCn.WaitForSendData));
                          thread.Name = connection.RemoteEndPoint.ToString();
                          thread.Start();
       如此一来,这个新的socket在Accept之后就在新的Thread中运行了。
         3:Connection的会话处理
         建立了新的Connection(也就是socket),远程就可以和这个socket进行会话了,无非就是send和receive。
         现在先看看怎么写的这个线程运行的Connection. WaitForSendData函数
          while (true)
                  {
                      bytes = new byte[1024];
                      string data = "";
                      //systm will be waiting the msg of receive envet. like Accept();
                      //here will be suspended while waiting for socket income msg.
                      int bytesRec = this._connection.Receive(bytes);
                      _lastConnectTime = DateTime.Now;
                      if (bytesRec == 0)//close envent
                      {
                          Logger.Log("Close Connection", _connection.RemoteEndPoint.ToString());
                          break;
                      }
                      data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
                      //…….handle your data.
                   }
      可以看到这个处理的基本步骤如下:
         执行Receive函数,接收远程socket发送的信息;
         把信息从字节转换到string;
         处理该信息,然后进入下一个循环,继续等待socket发送新的信息。
      值得注意的有几个:
         1:Receive函数。这个函数和Listener的Accept函数类似。在这个地方等待执行,如果没有新的消息,这个函数就不会执行下一句,一直等待。
         2:接收的是字节流,需要转化成字符串
         3:判断远程关闭联接的方式
         4:如果对方的消息非常大,还得循环接收这个data。
      4:如何管理这些联接(thread)
      通过上边的程序,基本上可以建立一个侦听,并且处理联接会话。但是如何管理这些thread呢?不然大量产生thread可是一个灾难。
      管理的方法比较简单,在Listener里面我定义了一个静态的哈希表(static public Hashtable Connections=new Hashtable();),存储Connection实例和它对应的Thread实例。而connection中也加入了一个最后联接时间的定义(private DateTime _lastConnectTime;)。在新链接建立的时候(Listener的Accept()之后)就把Connection实例和Thread实例存到哈希表中;在Connection的Receive的时候修改最后联接时间。这样我们就可以知道该Connection在哪里,并且会话是否活跃。
      然后在Winform程序里头可以管理这些会话了,设置设置超时。

  • 相关阅读:
    跟我一起学算法——贪心算法
    跟我一起学算法——最大流
    跟我一起学算法——红黑树
    设计模式总结
    敏捷开发模型
    TCP安全,SYN Flooding 和 nmap
    ICMP和重定向攻击
    IP安全,DDoS攻击、tearDrop攻击和微小IP碎片攻击
    Netfilter,获取http明文用户名和密码
    Linux常用网络命令
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1776879.html
Copyright © 2011-2022 走看看