daiwoo_wang 2022-09-15 19:09 采纳率: 0%
浏览 18
已结题

关于IOCP模型中,receive接收超时的问题

问题遇到的现象和发生背景

用异步通信搭建了一个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在投递接收请求,到接收完成间,到底发生了什么,为什么会产生超时,怎么避免呢?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 9月23日
    • 创建了问题 9月15日

    悬赏问题

    • ¥15 2024-五一综合模拟赛
    • ¥15 下图接收小电路,谁知道原理
    • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
    • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
    • ¥15 手机接入宽带网线,如何释放宽带全部速度
    • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
    • ¥15 ETLCloud 处理json多层级问题
    • ¥15 matlab中使用gurobi时报错
    • ¥15 这个主板怎么能扩出一两个sata口
    • ¥15 不是,这到底错哪儿了😭