问题遇到的现象和发生背景
用异步通信搭建了一个IOCP模型,这个框架应该是目前来说性能最完善的,但在使用中发现,会时不时出现receive超时的情况。非常疑惑。
话不多说,帖代码:
首先是非阻塞的startaccept:
///
/// 从客户端开始接受一个连接操作
///
private void StartAccept(SocketAsyncEventArgs asyniar)
{
try
{
if (asyniar == null)
{
asyniar = new SocketAsyncEventArgs();
asyniar.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
}
else
{
//socket must be cleared since the context object is being reused
asyniar.AcceptSocket = null;
}
_maxAcceptedClients.WaitOne();
_maxAcceptedTerms.WaitOne();
if (!_serverSock.AcceptAsync(asyniar))
{
ProcessAccept(asyniar);
//如果I/O挂起等待异步则触发AcceptAsyn_Asyn_Completed事件
//此时I/O操作同步完成,不会触发Asyn_Completed事件,所以指定BeginAccept()方法
}
}
catch(Exception ex)
{
myLog("StartAccept() --> 错误:" + ex.Message.ToString());
}
}
然后是processaccept:
///
// / 监听Socket接受处理
///
/// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>
private void ProcessAccept(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
Socket sock = e.AcceptSocket;//和客户端关联的socket
if (sock.Connected)
{
try
{
Interlocked.Increment(ref _clientCount);//原子操作加1
AsyncUserToken userToken = _userTokenPool.Pop();
userToken.ConnectSocket = sock;
//** 连接来了,生成设备对象
Interlocked.Increment(ref _TermCount);//原子操作加1
CDev Term = _userTermPool.Pop();
Term.myAsyncUserToken = userToken;
Term.myDBSTR = DBInfo;
Interlocked.Increment(ref IDinServer);//原子操作加1
Term.IDinServer = IDinServer;
Term.PowerOn();
//** TODO:这里应该产生一个usertoken和设备的映射表
dic_Async_Term.AddOrUpdate(userToken, Term, (key, oldValue) => Term);
//******************************
myLog(String.Format("客户 {0} 连入, 共有 {1} 个连接。",
sock.RemoteEndPoint.ToString(), _clientCount));
SendMessageToMainThread(0, System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") +
String.Format("客户 {0} 连入, 共有 {1} 个连接。",
sock.RemoteEndPoint.ToString(), _clientCount));
SendMessageToMainThread(2, dic_Async_Term.Count().ToString());
if (dic_Async_Term.ContainsKey(userToken))
{
dic_Async_Term[userToken].myLog(">>>>>>> 投递接收请求....");
}
myLog("ProcessAccept() --> 等待信号,投递接收请求");
//mAsync.WaitOne();
myLog("ProcessAccept() --> 获得信号,投递接收请求");
if (!sock.ReceiveAsync(userToken.ReceiveEventArgs))//投递接收请求
{
myLog(sock.RemoteEndPoint.ToString() + "同步完成,调用回调函数");
if (dic_Async_Term.ContainsKey(userToken))
{
dic_Async_Term[userToken].myLog("同步接收完成,调用回调函数");
}
ProcessReceive(userToken.ReceiveEventArgs);
SendMessageToMainThread(2, _clientCount.ToString());
}
myLog("ProcessAccept() --> 信号投递完成,释放信号");
//mAsync.Set();
}
#region
catch (SocketException ex)
{
myLog(String.Format("接收客户 {0} 数据出错, 异常信息: {1} 。",
sock.RemoteEndPoint, ex.ToString()));
SendMessageToMainThread(0, String.Format("接收客户 {0} 数据出错, 异常信息: {1} 。",
sock.RemoteEndPoint, ex.ToString()));
//TODO 异常处理
}
#endregion
//投递下一个接受请求
StartAccept(e);
}
}
}
在这里,当投递接受请求后,当IO完成接收事件,回调用回调函数IOCOMPLETE,
///
/// 当Socket上的发送或接收请求被完成时,调用此函数
///
/// <param name="sender">激发事件的对象</param>
/// <param name="e">与发送或接收完成操作相关联的SocketAsyncEventArg对象</param>
private void OnIOCompleted(object sender, SocketAsyncEventArgs e)
{
// Determine which type of operation just completed and call the associated handler.
AsyncUserToken userToken = e.UserToken as AsyncUserToken;
lock (userToken)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
ProcessAccept(e);
break;
case SocketAsyncOperation.Receive:
if (dic_Async_Term.ContainsKey(userToken))
{
myLog("IOComplete() --> " + dic_Async_Term[userToken].myTermAddr +
" 投递接收完成,触发ProcesReceive()");
dic_Async_Term[userToken].myLog("IOComplete() --> " + dic_Async_Term[userToken].myTermAddr +
" 投递接收完成,触发ProcesReceive()");
}
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
}
}
}
问题在于,当开始投递,到投递完成,去ProcessReceive时,会发现TOKEN的事件返回为超时TIMEOUT,
private void ProcessReceive(SocketAsyncEventArgs e)
{
AsyncUserToken userToken = e.UserToken as AsyncUserToken;
try
{
Socket sock = userToken.ConnectSocket;
if (userToken.ReceiveEventArgs.BytesTransferred > 0 && userToken.ReceiveEventArgs.SocketError == SocketError.Success)
{ .............................................
不知道IOCP在投递接收请求,到接收完成间,到底发生了什么,为什么会产生超时,怎么避免呢?