Socket开发异常总结
Socket异常开发总结
事情概况:今天早上手机充值业务突然停止,客户端又不断提交充值订单上来,短时间出现大量客户投诉,经检查,后在同事Aaron的帮助下,查找出问题原因
首先看一下充值系统架构,手机充值Win Service 会每稍钟从数据库里查询出一条没有提交充值的订单去充值。结构类图概要如下
其中充值的类里是去查询订单,送给SocketHelp的Submit方法去充值
主要程序如下
查询Win service

{
private readonly Timer _submitTimer;
public TopupService3()
{
_submitTimer = new Timer(1000);
_submitTimer.Elapsed += SubmitTimerElapsed;
_verifyTimer = new Timer(5 * 60 * 1000);
_verifyTimer.Elapsed += VerifyTimerElapsed;
}
protected override void OnStart(string[] args)
{
_submitTimer.Start();
}
protected override void OnStop()
{
_submitTimer.Stop();
}
internal void SubmitTimerElapsed(object sender, ElapsedEventArgs e)
{
_submitTimer.Stop();
try
{
//查询提交充值
}
catch (SqlException sqlException)
{
}
catch (Exception exception)
{
}
finally
{
_submitTimer.Start();
}
}
}
提交充值的SocketHelp

{
#region 手机充值
public static string Submit()
{
try
{
IPAddress ip = IPAddress.Parse(Host);
var ipe = new IPEndPoint(ip, Port); //把ip和端口转化为IPEndPoint实例
DFSubmitLog.Debug("建立sockets连接");
c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建一个Socket
DFSubmitLog.Debug("Connecting......");
c.Connect(ipe); //连接到服务器
byte[] bs = Encoding.UTF8.GetBytes(upOrderContent);
c.Send(bs, bs.Length, 0); //发送测试信息
string recvStr = "";
var recvBytes = new byte[1024];
Thread.Sleep(SocketTimeout);
int bytes = c.Receive(recvBytes, recvBytes.Length, 0);
recvStr += Encoding.UTF8.GetString(recvBytes, 0, bytes);
c.Close();
return recvStr;
}
catch (ArgumentNullException e)
{
return "";
}
catch (SocketException e)
{
return "";
}
finally
{
if (c != null)
{
}
}
}
以上程序的Socket部份有问题,就是在Socket发送信息出去以后,程序就相当于停在那了,没有接收信息。此时不知道是发送的过程中出了问题,还是接收的过程中出了问题,总之程序是没有获取到异常。引用Aaron的原话是Socket处于无限期等待当中,即在通讯过程中,由于客户端是周期性地向服务器请求数据,若客户端的请求指令或是服务端发来的数据包丢失的话,那么客户端将一直等待,陷入假死状态。
针对这个问题,把Socket程序修改成同步Socket,代码如下

{
#region 手机充值
public static string Submit(Order record, string productInfo)
{
try
{
IPAddress ip = IPAddress.Parse(Host);
IPEndPoint ipe = new IPEndPoint(ip, Port);
using (Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
clientSocket.ReceiveTimeout = SocketTimeout;
clientSocket.SendTimeout = SocketTimeout;
DFSubmitLog.Debug("Connecting......");
clientSocket.Connect(ipe);
byte[] bs = Encoding.UTF8.GetBytes(upOrderContent);
clientSocket.Send(bs, bs.Length, 0);
string recvStr = String.Empty;
byte[] recvBytes = new byte[1024];
Thread.Sleep(SocketTimeout);
int bytes = clientSocket.Receive(recvBytes, recvBytes.Length, 0);
recvStr = Encoding.UTF8.GetString(recvBytes, 0, bytes);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
return recvStr;
}
}
catch (ArgumentNullException e)
{
return String.Empty;
}
catch (SocketException e)
{
return string.Empty ;
}
catch (Exception e)
{
return string.Empty;
}
}
}
指定了,发送数据时间,接收数据时间,超过这个时间了就引发socket异常
修改了程序以后,我把其中变量SocketTimeout设置成500,即500毫秒,由于这个时间还是不够长,在程序起动的时候会引发 :SocketException: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败
后来我把SocketTimeout设置成2000,即2秒钟就没有问题,程序可以正常运行
相关Socket类的MSND地址是:
http://msdn.microsoft.com/zh-cn/library/attbb8f5(v=VS.80).aspx
其中关于Socket类的几个属性资料摘录如下
1. 当数据发送和数据接收完成之后,可使用 Shutdown 方法来禁用 Socket。在调用 Shutdown 之后,可调用 Close 方法来释放与 Socket 关联的所有资源
2. Socket.SendTimeout 属性
获取或设置一个值,该值指定之后同步 Send 调用将超时的时间长度。
命名空间:System.Net.Sockets属性值
超时值(以毫秒为单位)。如果将该属性设置为 1 到 499 之间的值,该值将被更改为 500。默认值为 0,指示超时期限无限大。指定 -1 还会指示超时期限无限大。
3 Socket.ReceiveTimeout 属性
获取或设置一个值,该值指定之后同步 Receive 调用将超时的时间长度。
命名空间:System.Net.Sockets
程序集:System(在 system.dll 中)
超时值(以毫秒为单位)。默认值为 0,指示超时期限无限大。指定 -1 还会指示超时期限无限大。
异常
--------------------------------------------------------------------------------
异常类型 条件
SocketException
试图访问套接字时发生错误。
ObjectDisposedException
Socket 已关闭。
ArgumentOutOfRangeException
为设置操作指定的值小于 -1。
--------------------------------------------------------------------------------
此选项仅适用于同步 Receive 调用。如果超过超时期限,Receive 方法将引发 SocketException。
其它参考文摘
http://blog.163.com/gfmq_312/blog/static/17823682200951711112373/
在通讯过程中,由于客户端是周期性地向服务器请求数据,若客户端的请求指令或是服务端发来的数据包丢失的话,那么客户端将一直等待,陷入假死状态。由于默认为无超时,所以一定要记得设定客户端接收的超时时间,若服务器端无相应,客户端应该抛出异常,而不是毫无意义的等待
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人