zoukankan      html  css  js  c++  java
  • socket 异步通信的一些问题

      socket通信在使用时被封装很简单,像操作文件一样简单,正是因为简单里面好多细节需要深入研究一下。

      windows下通信有select和iocp方式,select是传统方式,在socket里使用receive send这种方式出现,iocp是一种高效的方式,不会产生过多线程,被socket使用beginreceive和endreceive和这种异步委托方式实现。

      

          在开发中,最麻烦的是写接收服务(receive),因为发送方总是不可控的,一个稳定receive服务,需要了解,连接,接收机制,关闭,数据缓冲,错误处理。当然还有最麻烦的包边界问题。连接BeginAccept 是一个新连接必然进入的方法主要是EndAccept得到一个工作的socket(且叫它worksocket,就是与指定客户连接的一个socket),这个worksocket远程地址就是连接的客户端口发出的地址。 这时workSocket != null && workSocket.Connected 是true的。beginReceive 是在接收端循环接收的异步方式(只要这个worksocket不断)它会一直徘徊在beginReceive 和EndReceive中,beginreceive用来从端口缓冲区读到指定缓冲区,(socket通信有二个缓冲区),缓冲区不可能无限的大,所以每次可以读到最大也就是指定缓冲区尺寸<=EndReceive返回的值。

      

        socket关闭,有以下三种情况。

        一,如果客户端口直接关闭,这时服务端在EndReceive时直接抛错,不回有0的返回,只会抛出一个远程连接被关闭了。

        二、如果客户端口调用shutdown 与close而服务端口EndReceive 返回 0(返回0说明远程已经关闭了)这时必须worksocket.shutdown和close方法,如果不及时关闭                      一直返回0,这个连接一直不会断。在beginreceiv中不要用Connected判断,这个状态一直是false,还有Available也是不准的,

            三、如果服务端把一个worksocket先给关闭了(不是整个socket),而客户没有在这之前关闭,程序有崩溃的风险。

        一个高效的发送是客户发送端一直发,而不管状态,(接收状态通过异步方式)

        

     1  while (B!= ConsoleKey.Q)
     2             {
     3                 if (B == ConsoleKey.R)
     4                 {
     5                     for (int i = 0; i < 50; i++)
     6                     {
     7                         byte[] bytes = Encoding.UTF8.GetBytes("欢迎你"+i.ToString());
     8                         sender.Send(bytes);
     9                         sender.BeginReceive();
    10                     }
    11                 }
    12                 else if (B == ConsoleKey.C)
    13                 {
    14                     sender.Close();
    15                  
    16                 }
    17 
    18                 B = Console.ReadKey().Key;
    19             }

        接收端异步接收,异步发回状态。也可以同步发回。

        

     1  try
     2             {
     3                 cnt = wsocket.EndReceive(result);
     4               
     5                 if (cnt == 0)
     6                 {
     7                     Console.WriteLine(cnt);
     8                     wsocket.Shutdown(SocketShutdown.Both);
     9                     wsocket.Close();
    10                 }
    11                 else
    12                 {
    13                    
    14                     string str = Encoding.UTF8.GetString(receiveBuf, 0, cnt);
    15                     Console.WriteLine(str);
    16                     workSocket.Send(Encoding.UTF8.GetBytes("服务收到"+str));
    17                      
    18                     wsocket.BeginReceive(receiveBuf, 0, receiveBuf.Length, SocketFlags.None, EndReceive, workSocket);
    19                 }
    20                
    21             }
    22             catch (Exception oe)
    23             {
    24                 Console.WriteLine(oe.Message);
    25             }

    最后一点客户端并发的发送,服务端接收的数据可能需要解决粘包问题,这个问题,有二种方式处理,一、特殊字符 二、定义包的协议。

        

        

  • 相关阅读:
    从马琳决赛被翻盘想到的
    C语言中的位运算
    瑞星杀毒软件所有监控已禁用!
    回来了,重新开始
    使用 javascript 标记高亮关键词
    我的webgis客户端引擎AIMap
    RPM 命令大全
    终结IE6下背景图片闪烁问题
    linux下挂载硬盘光驱和U盘
    在JavaScript中实现命名空间
  • 原文地址:https://www.cnblogs.com/shouhongxiao/p/3688905.html
Copyright © 2011-2022 走看看