Socket 异步接受

  herein , i just wanner illuminate two problems.

  first ,i want to show how to use the beginReceive and then   if i have a big buffer to receive a short string,why i get the string exceptional.

  now , follow me to see it

 

  code:

  we write a class as transferring data object

  class state

 {

    public   Socket  _mySocket{set;get;}

   byte[] _buff{set;get;}

   

}

 we invoke the function beginreceive like this

 _myListenSocket.beginreceive(buff,0,buff.length,sockettype.none,endreceivecallback,stateobject);

 

in the endreceivecallback ,we code like this

state mystate = ar.AsyncState as state;

socket mySocket = myState.sokcet;

byte[] mybuff = myState.buff;

int ret =mySocket.EndReceive(ar);

then problem 2 has coming  ,check my code carefully

mystring = Encoding.utf8.getstring(buff,0,buff.length);

so  we have got the string :这个是测试程序/0/0....

when we run the test program ,just got exceptional string that we don't want;

 

now ,we analyse this situation

first ,we definitely didn't clear the buff ,if we get the msg "这个是测试程序" at the  previous time and now we had received msg "压力测试",we get "压力测试试程序" at last!

but now you perhaps ask me when we change the length from the size of buff  to receiving the real length ,we don't clear the buffer also,why the reslut is ok; do a pretty work!

actually,it did the same thing the two invoke methods;just the method 2 ,we display the length we assigned;

 

so we definitely did not clear the buffer

 

at last we should invoke the beginreceive  in endreceivecallback;

 

now  there is a problem about close the socket using to receive msg

 

if we want to close the socket ,we must do it like this

code:

void CloseSocket()

{

   if(AcceptSocket != null&& AcceptSocket.Connected)

{

     AcceptSocket.Shutdown(SocketShutdown.Both);

    AcceptSocket.Close();

    AcceptSocket = null;

}

 }

 

when we need use the socket ,we judge it whether equal null

 

if(AcceptSocket == null)

return;

int ret = tempAcceptSocket.EndReceive(ar);

...

 

 

 

在C#的Socket异步编程中,使用 `BeginReceive` 和 `EndReceive` 进行异步数据接收时,如果在第二次发送数据后没有触发回调函数,通常是由以下几个原因导致的: ### 1. 未重新调用 `BeginReceive` 在异步接收数据时,`BeginReceive` 方法只触发一次接收操作。一旦数据被接收并进入回调函数,如果未在回调函数中再次调用 `BeginReceive`,则后续的数据发送将不会触发新的接收回调。这是最常见的问题之一。例如: ```csharp private void ReceiveCallback(IAsyncResult ar) { StateObject state = (StateObject)ar.AsyncState; Socket handler = state.WorkSocket; int bytesRead = handler.EndReceive(ar); if (bytesRead > 0) { // 处理接收到的数据 // ... // 继续发起下一次异步接收 handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); } } ``` 如果在回调函数中没有再次调用 `BeginReceive`,则后续的数据将无法被接收,也就不会触发新的回调[^4]。 --- ### 2. 缓冲区大小不足或未正确管理接收状态 在异步接收数据时,如果没有正确管理缓冲区或状态对象(如 `StateObject`),可能导致数据接收不完整或接收操作提前结束。例如,如果接收缓冲区太小,而发送方发送的数据包较大,可能会导致部分数据未被接收,进而影响后续的接收逻辑。 确保每次接收操作都使用独立的缓冲区或正确复用缓冲区,并且状态对象(如 `StateObject`)能够正确跟踪接收的进度和数据长度。 --- ### 3. Socket连接状态异常 如果在第二次发送数据时,Socket连接已经断开或处于非活动状态,`BeginReceive` 将不会触发回调。可以通过检查 `Socket.Connected` 属性或捕获 `SocketException` 来确认连接状态。 此外,在接收回调中应检查 `EndReceive` 的返回值。如果返回值为 0,表示连接已关闭,此时应释放相关资源并终止接收流程: ```csharp int bytesRead = handler.EndReceive(ar); if (bytesRead == 0) { // 连接已关闭 handler.Shutdown(SocketShutdown.Both); handler.Close(); return; } ``` 确保在网络中断或连接关闭时有适当的处理逻辑,避免程序进入“静默失败”状态[^1]。 --- ### 4. 异步操作未正确释放或重复调用 如果在回调函数中重复调用了 `BeginReceive` 或者在未完成当前异步操作前再次调用,可能会导致异常或未定义行为。应确保每次异步接收操作在完成之前不会被重复调用,并且在异常发生时正确释放资源。 例如,在异常处理中: ```csharp private void ReceiveCallback(IAsyncResult ar) { try { StateObject state = (StateObject)ar.AsyncState; Socket handler = state.WorkSocket; int bytesRead = handler.EndReceive(ar); if (bytesRead > 0) { // 处理数据 // ... // 重新开始接收 handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); } } catch (SocketException ex) { // 处理Socket异常 Console.WriteLine("SocketException: " + ex.Message); } catch (Exception ex) { // 处理其他异常 Console.WriteLine("Exception: " + ex.Message); } } ``` --- ### 5. 数据包格式不一致导致接收逻辑错误 在网络通信中,如果发送方和接收方的数据包格式不一致(例如未按约定在前4字节表示包长度),接收方可能无法正确解析数据,导致后续接收逻辑失效。接收方应首先接收包头(如4字节长度信息),然后根据长度接收完整数据包: ```csharp // 首先接收包头(4字节) client.BeginReceive(buffer, 0, 4, SocketFlags.None, new AsyncCallback(ReceivePackHeadCallback), state); ``` 在 `ReceivePackHeadCallback` 中解析包长度后,再发起接收包体的异步操作: ```csharp private void ReceivePackHeadCallback(IAsyncResult ar) { StateObject state = (StateObject)ar.AsyncState; int bytesRead = state.WorkSocket.EndReceive(ar); if (bytesRead == 4) { int packetLength = BitConverter.ToInt32(state.Buffer, 0); // 接收包体 state.WorkSocket.BeginReceive(state.Buffer, 4, packetLength - 4, SocketFlags.None, new AsyncCallback(ReceivePackDataCallback), state); } } ``` 如果未按此流程处理,可能导致接收逻辑无法继续触发回调[^4]。 --- ### 总结 C#中 `BeginReceive` 在第二次发送后不触发回调的主要原因包括: - 未在回调函数中重新调用 `BeginReceive`; - 缓冲区或状态对象管理不当; - 连接状态异常; - 异步操作重复调用或资源未正确释放; - 数据包格式不一致导致接收逻辑错误。 通过确保每次接收操作完成后重新发起异步接收、正确管理状态和连接、处理异常情况,并遵循标准的数据包接收流程,可以有效解决该问题。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值