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             }

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