SMPP短信发送报错:Socket已关闭无法收发数据求助
SMPP短信发送应用Socket异常修复方案
错误核心原因
异常System.Net.Sockets.SocketException (0x80004005)的本质是:Socket已通过Shutdown调用关闭了接收/发送方向,但代码仍尝试在该Socket上执行BeginReceive操作。即使表面认为Socket处于开启状态,底层连接已终止,且Shutdown标记已生效。
结合提供的代码,直接触发点是处理Unbind_Resp后,Socket已被关闭,但回调流程仍执行了后续的BeginReceive,同时其他场景下缺乏Socket状态检查就发起异步接收调用。
具体修复步骤
1. 修复Unbind_Resp处理分支
在receiveCallback的Unbind_Resp分支中,调用disconnect(client)后添加return,终止回调流程,避免执行后续的无效BeginReceive:
case 0x80000006: logMessage(LogLevels.LogSteps, "Unbind_Resp"); connectionState= ConnectionStates.SMPP_UNBINDED; disconnect(client); return; // 终止回调流程,跳过后续BeginReceive调用
2. 增加Socket状态前置检查
在调用client.BeginReceive前,添加Socket连接状态与业务状态的双重检查,避免对已失效的Socket发起操作:
// 替换原有的BeginReceive调用,先执行状态检查 if (client != null && client.Connected && connectionState == ConnectionStates.SMPP_BINDED) { client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(receiveCallback), state); } else { logMessage(LogLevels.LogWarnings, "Socket已断开或未绑定,取消异步接收调用"); }
3. 完善disconnect方法的状态清理
确保disconnect方法彻底清理Socket资源与业务缓存,避免残留无效状态:
private void disconnect(Socket client) { if (client == null) return; try { if (client.Connected) { client.Shutdown(SocketShutdown.Both); } } catch (Exception ex) { logMessage(LogLevels.LogErrors, "关闭Socket时出错: " + ex.Message); } finally { client.Close(); connectionState = ConnectionStates.SMPP_UNBINDED; // 清理异步事件与状态码缓存 lock(events) { events.Clear(); } lock(statusCodes) { statusCodes.Clear(); } } }
4. 确保状态变量的线程安全
用volatile修饰connectionState,保证多线程环境下状态读取的一致性:
private volatile ConnectionStates connectionState;
额外注意事项
- 检查
tryToReconnect方法的实现,确保重新连接时会创建全新的Socket实例,而非复用已关闭的Socket对象。 - 校验
smppClient.CanSend的判断逻辑,确保其与connectionState的状态保持一致,避免出现误判导致的无效发送请求。
内容的提问来源于stack exchange,提问作者Hizbullah Watandost
相关产品推荐
相关产品推荐

