水中锋 2021-12-27 08:49 采纳率: 100%
浏览 72
已结题

socket服务器与客户端连接2小时以上无数据传输,服务器会主动断开客户端连接

问题背景:我们研制了一台设备,并开发了设备控制软件,设备内置主控板,运行平台为win7 64bit,本地控制软件采用MFC开发。上位机软件通过网络控制设备实现业务功能,采用的是TCP协议。设备本地控制软件用SCOKET搭建了服务器,监听本地5025端口,接收来自上位机socket客户端的连接,背景介绍完毕。
问题描述:上位机是24小时不停的运行,通过SOECKET完成初始化后,大部分时间是不与设备进行通信的,与设备收发数据时间紧紧几秒钟,间隔时间可能几个小时也可能几天。如果上位机在初始化完成后2小时内不与客户端进行任何数据交互,那么设备控制软件会主动断开连接,造成通信失败。

设备端socket代码

InitTcpServer()
{
    WORD wVersionRequested;//版本号
    wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字
    WSADATA wsaData;
    //初始化Winsock
    int err;
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return;
    }
    if (LOBYTE(wsaData.wVersion) != 1 || 
        HIBYTE(wsaData.wVersion) != 1)
    {
        return;
    }//判断高低字节是不是1,如果不是1.1的版本则退出 

    //创建套接字
    m_Server = socket(AF_INET, SOCK_STREAM, 0);
    //Socket地址结构体的创建
    struct sockaddr_in seraddr;
    int serport=5025;
    memset(&seraddr,0,sizeof(seraddr));
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(serport);
    seraddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    //绑定套接字到服务器地址结构
    err=bind(m_Server, (SOCKADDR*)&seraddr, sizeof(SOCKADDR));//If no error occurs, bind returns zero.
    if(err!=0)
    {
        MessageBox("Bind Error!");
        exit(-3);
    }
    //监听套接字
    err=listen(m_Server,5);
    if(err!=0)
    {
        MessageBox("Listen Error!");
        exit(-2);
    }
    //套接字clisock上接收到数据时,向窗口发送自定义消息RECEIVE_EVENT
    WSAAsyncSelect(m_Server,GetSafeHwnd(),ACCEPT_EVENT,FD_ACCEPT|FD_READ|FD_CLOSE);
}

尝试解决: 出现这个问题后,在网上查询了SOCKET相关内容,socket默认有7200秒的超时时间,如果7200秒内没有数据通信,服务器就会主动断开连接。网上找的解决办法是启动心跳包功能,socket默认keepalive是不开启的,需要用户主动开启。于是我在原基础上增加了启动心跳包的代码:

InitTCPServer()
{
    WORD wVersionRequested;//版本号
    wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字
    WSADATA wsaData;
    //初始化Winsock
    int err;
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return;
    }
    if (LOBYTE(wsaData.wVersion) != 1 || 
        HIBYTE(wsaData.wVersion) != 1)
    {
        return;
    }//判断高低字节是不是1,如果不是1.1的版本则退出 

    //创建套接字
    m_Server = socket(AF_INET, SOCK_STREAM, 0);
    //////////////////////////////////////////////////////////////////////////
    tcp_keepalive live,liveout;  
    live.keepaliveinterval=5000; //5秒发一次探测报文,发5次没有回应,就断开
    live.keepalivetime=30000;//超过30s没有数据,就发送控测包
    live.onoff=TRUE;  
    int Opt = 1;
    int iRet = setsockopt(m_Server,SOL_SOCKET,SO_KEEPALIVE,(char *)&Opt,sizeof(int));  
    if(iRet == 0)
    {
        DWORD dw;
        if(::WSAIoctl(m_Server,SIO_KEEPALIVE_VALS,
            &live,sizeof(live),&liveout,sizeof(liveout),
            &dw,NULL,NULL)== SOCKET_ERROR)
        {
        }  
    }
    //////////////////////////////////////////////////////////////////////////
    //Socket地址结构体的创建
    struct sockaddr_in seraddr;
    int serport=5025;
    memset(&seraddr,0,sizeof(seraddr));
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(serport);
    seraddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY); 
    //绑定套接字到服务器地址结构
    err=bind(m_Server, (SOCKADDR*)&seraddr, sizeof(SOCKADDR));//If no error occurs, bind returns zero.
    if(err!=0)
    {
        MessageBox("Bind Error!");
        exit(-3);
    }
    //监听套接字
    err=listen(m_Server,5);
    if(err!=0)
    {
        MessageBox("Listen Error!");
        exit(-2);
    }

    //套接字clisock上接收到数据时,向窗口发送自定义消息RECEIVE_EVENT
    WSAAsyncSelect(m_Server,GetSafeHwnd(),ACCEPT_EVENT,FD_ACCEPT|FD_READ|FD_CLOSE);
}


测试了几天,仍然是每2小时服务器会主动断开客户端连接。
我们也想过不用长连接来实现设备控制,紧紧在需要控制的时候在连接设备,这是确实可以解业务层面的问题,但问题没有真正解决,确实如鲠在喉。

  • 写回答

1条回答 默认 最新

  • 力口月巴犭苗 2021-12-28 11:44
    关注

    建议你自己写一个心跳,不依赖tcp的那套东西,每隔一分钟或者几十秒发送一次,客户端发送过去,服务端再返回回来,报文弄小点就行,如果超过一定时间双方任意一方没有收到心跳,则断开连接重连.
    tcp长链接非常依赖网络环境,你路由器重启下有可能就会断开连接,如果是物联网就更不稳定了,所以还是交在自己手里吧

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 2月19日
  • 已采纳回答 2月11日
  • 创建了问题 12月27日

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器