异步Server Socket无法处理多条消息问题求助
问题分析与修复方案
看了你的代码,问题主要出在ReadCallback方法的逻辑顺序和后续接收的处理上,咱们一步步拆解:
1. 数据接收与处理的顺序完全搞反了
你现在的代码是先调用BeginReceive,再把刚收到的数据追加到StringBuilder里,这会导致:
- 第一次接收的39字节消息,其实是在第二次进入ReadCallback时才被处理(因为第一次调用BeginReceive后,后续的接收触发才会处理之前的数据)
- 后续的消息因为接收和处理的时序混乱,根本没被正确累积和解析
2. 仅在特定条件下才继续监听后续消息
你的代码里只有当fields[1] == "0"时才再次调用BeginReceive,如果后续消息的fields[1]不是0,服务器就停止监听了,自然收不到后续消息。
3. 没有正确判断单条消息的完整性
Socket是基于流的,不是基于消息的,你不能假设一次BeginReceive就能拿到完整的一条消息。虽然你第一条消息刚好39字节被一次接收,但后续消息可能被拆分包,或者多条消息连在一起发送,这时候你的代码会把多条消息混在一起解析,直接导致逻辑错误。
修正后的代码与关键改动
修正ReadCallback方法
private void ReadCallback(IAsyncResult Ar) { // Retrieve the state object and the handler socket var state = (StateObject)Ar.AsyncState; var handler = state.WorkSocket; try { var bytesRead = handler.EndReceive(Ar); if (bytesRead > 0) { // 第一步:先把收到的数据追加到缓冲区,顺序不能反! state.Sb.Append(Encoding.ASCII.GetString(state.Buffer, 0, bytesRead)); var content = state.Sb.ToString(); // 第二步:判断当前是否已经收到一条完整的消息 // 这里假设你的消息是以\r\n作为结束符(从你的TrimEnd('\r', '\n')推测) if (content.EndsWith("\r\n")) { // 处理完整的消息 Msg.Debug($"Read {content.Length} bytes from socket. \n Data : {content}"); var fields = content.TrimEnd('\r', '\n').Split(',').ToList(); var paymentDetails = ProcessPaymentResponse(fields); if (paymentDetails != null) { ResponseQueue.Enqueue(paymentDetails); ResponseResetSignal.Set(); } // 重置StringBuilder,准备接收下一条消息 state.Sb.Clear(); } // 第三步:不管当前消息是否完整,都要继续监听下一次接收 // 这是保证能收到后续消息的关键! handler.BeginReceive(state.Buffer, 0, StateObject.BUFFER_SIZE, 0, ReadCallback, state); } else { // bytesRead为0表示客户端关闭了连接 Msg.Debug("Client disconnected"); handler.Shutdown(SocketShutdown.Both); handler.Close(); } } catch (Exception e) { Msg.Debug($"Read error: {e.ToString()}"); handler.Shutdown(SocketShutdown.Both); handler.Close(); } }
关键改动说明
- 调整数据处理顺序:先把收到的字节转成字符串追加到
StringBuilder,再处理,确保每一次接收的数据都被正确累积。 - 增加消息完整性判断:通过检查消息是否以
\r\n结尾(你原代码里用了TrimEnd,推测这是你的消息结束符),确保只有收到完整的一条消息时才进行业务处理,避免解析不完整的消息。 - 强制持续监听:不管当前消息是否处理完成,只要客户端还没断开,就再次调用
BeginReceive,保证服务器能一直接收后续的消息。 - 增加异常处理:避免单个连接的异常导致整个服务器崩溃,同时在客户端断开时正确关闭Socket。
额外建议
- 如果你确定每条消息的长度是固定的(比如都是39字节),也可以通过累积字节数来判断消息完整性,比判断结束符更高效。
- 异步Socket的状态管理要注意,
StateObject里的Buffer和Sb要确保是每个连接独立的,你的代码看起来已经做到了,这点没问题。
内容的提问来源于stack exchange,提问作者NinjaArekku
相关产品推荐
相关产品推荐

