我们有一个Windows服务,已经在生产中愉快地运行了一年多。就在最近,它开始给它带来麻烦。我没有套接字编程的经验,但我必须尝试找到问题的原因 - 太棒了!
该服务安装在中央服务器上。它“监听”来自全国各地商店的大约400台服务器的数据。
启动时,服务会获取收集数据所需的商店列表以及商店服务器的ipaddress。然后循环遍历列表并执行以下代码:
IPEndPoint lep = new IPEndPoint(lipa.AddressList[lipa.AddressList.GetUpperBound(0)], (int)portNumber);
PosListener posListener = new PosListener(lep,this.pendingBacklog,storeTable,messageList);
PosListner的构造函数如下:
internal PosListener(IPEndPoint lep, int pendingBacklog, Hashtable storeTable, ArrayList messageList) : base(lep.Address.AddressFamily,SocketType.Stream,ProtocolType.Tcp)
{
ITraceState trState = PosApplication.Trace.StartProc("PosListener");
try
{
// Setup listener
this.ngcIPAddress = lep.Address.ToString();
this.ngcPort = lep.Port;
this.storeTable = storeTable;
this.storeLock = new ReaderWriterLock();
this.messageList = messageList;
this.messageLock = new ReaderWriterLock();
this.handlerList = new ArrayList();
this.handlerLock = new ReaderWriterLock();
this.asyncCallback = new AsyncCallback(this.CallbackAccept);
this.Bind(lep);
this.Listen(pendingBacklog);
// Start listening
PosApplication.PosSocketsEventLog.WriteEntry("Starting Listener on NGC Port "+this.ngcIPAddress+":"+this.ngcPort);
PosApplication.Trace.WriteDebug("Starting Listener on NGC Port "+this.ngcIPAddress+":"+this.ngcPort);
this.BeginAccept(this.asyncCallback,null);
}
catch (Exception e)
{
ExceptionManager.Publish(e);
}
finally
{
trState.EndProc();
}
}
我的理解是,只要在被监视的套接字上发现流量,构造函数就会注册CallbackAccept方法。
此回调方法粘贴在下面:
private void CallbackAccept(IAsyncResult ar)
{
ITraceState trState = PosApplication.Trace.StartProc("CallbackAccept");
try
{
// Get the socket that handles the client connection
Socket connection = this.EndAccept(ar);
// Start listening for the next client connection
this.BeginAccept(this.asyncCallback,null);
string storeIPAddress = ((IPEndPoint)connection.RemoteEndPoint).Address.ToString();
int storePort = ((IPEndPoint)connection.RemoteEndPoint).Port;
PosApplication.Trace.WriteDebug("Listener "+this.ngcIPAddress+":"+this.ngcPort+" received connection request from "+storeIPAddress+":"+storePort);
// Check the remote end point has a recognised Store IP Address
this.storeLock.AcquireReaderLock(-1);
bool isAcceptable;
try
{
isAcceptable = this.storeTable.Contains(storeIPAddress);
}
finally
{
this.storeLock.ReleaseReaderLock();
}
// Close connection and throw exception if the remote end point
// does not have a recognised Store IP Address
if (!isAcceptable)
{
connection.Shutdown(SocketShutdown.Both);
connection.Close();
CrmServiceException ce = new CrmServiceException(
"Client",
"ConfigurationError",
"PosSocketsService.UnSupportedStoreIPAddress",
PosApplication.Trace,
this.ngcIPAddress,
this.ngcPort.ToString(),
storeIPAddress,
storePort.ToString());
throw ce;
}
// Setup a connection handler
this.handlerLock.AcquireWriterLock(-1);
try
{
IPosHandler posHandler = PosApplication.ConstructIPosHandler(this,connection);
this.handlerList.Add(posHandler);
}
finally
{
this.handlerLock.ReleaseWriterLock();
}
}
catch (ObjectDisposedException)
{
// this object has been disposed by another thread
}
catch (SocketException e)
{
ExceptionManager.Publish(e);
PosApplication.Trace.WriteDebug("Unexpected Socket Exception Closing Listener "+this.ngcIPAddress+":"+this.ngcPort);
this.Dispose();
}
catch (Exception e)
{
ExceptionManager.Publish(e);
}
finally
{
trState.EndProc();
}
}
例外的细节如下:
异常类型: System.Net.Sockets.SocketException
ErrorCode:10054
消息:现有连接是 被远程主机强行关闭
SocketErrorCode:ConnectionReset
NativeErrorCode:10054
数据: System.Collections.ListDictionaryInternal
TargetSite:System.Net.Sockets.Socket EndAccept(Byte [] ByRef,Int32 ByRef, System.IAsyncResult)
HelpLink:NULL
来源:系统
StackTrace信息
在 System.Net.Sockets.Socket.EndAccept(字节[]&安培; 缓冲区,Int32& bytesTransferred, IAsyncResult asyncResult)
在 System.Net.Sockets.Socket.EndAccept(IAsyncResult的 asyncResult)
在 Fujitsu.eCrm.Seoul.PosSocketsService.PosListener.CallbackAccept(IAsyncResult的 ar)in C:\的Inetpub \ wwwroot的\ PosSocketsService \ PosListener.cs:行 109
第109行如下:
Socket connection = this.EndAccept(ar);
我们看到的行为是POSListners都是在服务启动时启动的。然后在短暂的一段时间后,每一个都被关闭 - 同样的10054异常被提出。
监听器似乎是由监控端口上出现的数据触发的,但是当回调方法尝试创建套接字以便读取数据时 - 窗口无法建立套接字。
有人可以建议采取哪些措施来尝试找出问题的根本原因吗?
答案 0 :(得分:5)
发生这种情况是因为您的某个客户端因您的服务器断开连接(如果您愿意的话,非常不合适)。
举一个例子,在典型的GUI上应该有Connect / Disconnect按钮。但是,如果用户突然连接并关闭应用程序,则套接字将没有时间终止与服务器的连接。当防火墙启动或存在线路连接问题时,可能会发生这种情况。
在任何情况下,我建议您通过自己关闭套接字(服务器端)来处理带有特定错误代码的SocketException。
答案 1 :(得分:2)
这个设计对我来说很奇怪。你正在发出400个单独的听众,afai可以告诉你。通常套接字服务器会发出一个listen,然后使用发送的一些标识数据或源IP来区分传入的客户端连接(“哪个服务器刚连接?”)。
我看不出这里究竟出了什么问题,但我质疑这个设计。我的猜测是服务器上的资源限制,也许自代码工作以来服务器负载配置文件已经改变。