在利用Socket 进行Tcp/Ip 编程的时候,免不了要进行数据的发送和接收,而数据的接收,用得最多的就是 Socket 的同步函数 Receive (或它的重载): public int Receive ( byte[] buffer, int offset, int size, SocketFlags socketFlags ) 或者是异步函数 BeginReceive( 或它的重载): public IAsyncResult BeginReceive ( byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, Object state ) 这里,我想说的是异步函数 BeginReceive()。 使用了异步函数BeginReceive(),伴随而来的就是要定义一个 AsyncCallback 类型的函数(如下面取名为ReceiveEnd的函数),在这个函数里面,我们最少要做的事情时调用 Socket 的 EndReceive() 函数。 protected void ReceiveEnd(IAsyncResult ar){ Socket client = (Socket)ar.AsyncState; int recvLen = client.EndReceive(ar); if ( recvLen > 0){ /**//* 接收到了数据 */ client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveEnd), client); /**//* 继续接收数据*/ } else{ client.Close(); } }
在Msdn 2005 的 ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref10/html/M_System_Net_Sockets_Socket_BeginReceive_3_2b547d4d.htm 基本上就是上面这个意思,但是现在问题来了: 如果我定义的 buffer 的长度为 10,但我发送的数据长度为12或者8,那么,函数就不会走到 else 的部分,而是阻塞在函数中的 BeginReceive()调用。 开始,我的想法是在发送的数据尾部增加一个特殊的字符(串),然后,在接收的时候判断有没有接收到这个字符(串)(我查阅了网上一些资料,还真有一些是这么做的!),但是,这种做法始终有一个毛病:那就是发送端发送的正文里面不能含有这个字符(串),否则,正文中在这个字符(串)后面的正文就会被丢掉。 所以,我想还是只能通过 Socket 自己的内部机制来实行,也就是想办法使程序走到 else 的部分。 经过测试: 在客户端发送完数据后,使用 Socket.Shutdown(SocketShutdown.Send ),或者Socket.Close()可以使程序走到 else 部分。 但是,这也带来了一个问题: 如果我定义的buffer 的长度为10,我发送的数据的长度也刚好为10,那么,函数在客户端不用Shutdown或Close的情况下,就已经走到了else 部分,然后 服务端的Socket 被 Close,等到客户端使用 Shutdown()或Close() 的时候,服务端的连接 Socket 已经是不可用了,而这个时候调用 EndReceive 操作,会引发异常。 所以,我认为在调用 EndReceive 前,先要判断 Socket 是否可用。(这个结论尚未测试) 同时,我测试将Socket.Shutdown(SocketShutdown.Send ),改为Socket.Shutdown(SocketShutdown.Receive ),并不能引发函数走到 else 部分,所以,我认为Socket 的Shutdown(SocketShutdown.Send )和Close()会引发客户端与服务端的一次数据传输。