win32 socket connect timeout

本文介绍了在Windows环境下使用socket进行TCP客户端连接时,默认采用阻塞模式,并提供了设置非阻塞模式的方法。通过对比两种模式的实现过程和应用场景,旨在帮助开发者更灵活地选择合适的连接方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// widonws: 默认设置socket TCP client connect为阻塞模式
void TcpConnect(char* strIP, UINT nPort)
{
    struct sockaddr_in serverAddress;
    SOCKET hSocket = NULL;

    hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if( hSocket==INVALID_SOCKET)
    {
        return;
    }

    memset(&serverAddress, 0, sizeof(serverAddress));     
    serverAddress.sin_family      = AF_INET;
    serverAddress.sin_addr.s_addr = inet_addr(strIP);   
    serverAddress.sin_port        = htons((short)nPort);      
    int iTimeOut = 3000;
    setsockopt(hSocket,SOL_SOCKET,SO_RCVTIMEO,(char*)&iTimeOut,sizeof(iTimeOut));
    setsockopt(hSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&iTimeOut,sizeof(iTimeOut));    

    if( SOCKET_ERROR==connect(hSocket, (sockaddr*)&serverAddress, sizeof(serverAddress)) )
    {        
        closesocket(hSocket);
        DWORD gle = WSAGetLastError();

        return;
    }

    char buff[] = "hello";
    int sl=::send(hSocket,(char*)buff, sizeof(buff), 0);
    if( sl<0 )
    {
        closesocket(hSocket);
        return ;
    }
    closesocket(hSocket);
}

// widonws: 设置socket TCP client connect非阻塞模式
void SockSelect(char* strIP, UINT nPort)
{
    SOCKET/*int*/ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sockfd < 0) 
    {
        return;
    }
    struct sockaddr_in serv_addr;

    //以服务器地址填充结构serv_addr
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(strIP);
    serv_addr.sin_port = htons(nPort);
    int error = -1;
    int len = sizeof(int);
    timeval tm;
    fd_set set;
    unsigned long ul = 1;
    ioctlsocket(sockfd, FIONBIO, &ul); //设置为非阻塞模式
    bool ret = false;
    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
    {
        tm.tv_sec  = 3;
        tm.tv_usec = 0;
        FD_ZERO(&set);
        FD_SET(sockfd, &set);
        if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)
        {
            getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, /*(socklen_t *)*/&len);
            if(error == 0) 
                ret = true;
            else 
                ret = false;
        } 
        else 
            ret = false;
    }
    else 
        ret = true;
    ul = 0;
    ioctlsocket(sockfd, FIONBIO, &ul); //设置为阻塞模式
    if(!ret) 
    {
        closesocket( sockfd );
        fprintf(stderr , "Cannot Connect the server!/n");
        return;
    }

    fprintf( stderr , "Connected!/n");

    char buff[] = "hello";
    int sl=::send(sockfd,(char*)buff, sizeof(buff), 0);

    closesocket( sockfd );
}

现在就是,当我连接的时候都能正常的读取,但只要我退出程序就会自动输出WIN32_SOCKET: Socket_connect: 192.168.1.199:102 代码如下:#include "iec61850thread.h" #include <QDebug> #include <QDateTime> IEC61850Thread::IEC61850Thread(QObject *parent) : QThread(parent) { ip = "192.168.1.199"; port = 102; dataSetReference = "VFBOXGateway/LLN0$dsAin"; // 连接到 IED(IP 和端口需根据实际情况调整) const char* ip = this->ip.toUtf8().constData(); int port = this->port; // MMS 默认端口 // 1. 创建连接对象 con = IedConnection_create(); // 2. 连接到 IED IedConnection_connect(con, &error, ip, port); // 检查错误信息 if (error != 0) { qDebug() << "Connection error: " << error; flag_connect = false; } else { qDebug() << "Connection successful."; flag_connect = true; } if (error != IED_ERROR_OK) { qDebug() << "连接失败,错误码:" << error; IedConnection_destroy(con); return; } connect(readTimer, &QTimer::timeout, this, &IEC61850Thread::startReading); readTimer->start(2000); } IEC61850Thread::~IEC61850Thread() { } void IEC61850Thread::run() { // 线程的主循环 exec(); } void IEC61850Thread::startReading() { if (isReading) { return; // 如果正在读取,直接返回 } isReading = true; for (int i = 1; i <= 21; ++i) { QString objectReferenceStr; if(i==20){ objectReferenceStr = QString("VFBOXGateway/GGIO1.AnIn402.mag.i"); }else if(i==21){ objectReferenceStr = QString("VFBOXGateway/GGIO1.AnIn403.mag.i"); }else{ // 构造对象引用路径 objectReferenceStr = QString("VFBOXGateway/GGIO1.AnIn%1.mag.i").arg(i); } const char* objectReference = objectReferenceStr.toUtf8().constData(); // 4. 读取值 MmsValue* value = IedConnection_readObject(con, &error, objectReference, IEC61850_FC_MX); if (value) { if (MmsValue_getType(value) == MMS_INTEGER) { int32_t anInValue = MmsValue_toInt32(value); qDebug(
最新发布
04-03
<think>好的,用户遇到了在IEC61850应用中使用C++和QT时,程序退出时出现WIN32_SOCKET: Socket_connect错误的问题。首先,我需要分析可能的原因。根据用户提供的引用信息,特别是引用[3]中提到在同一台计算机上无法接收UDP广播消息,这可能与套接字配置有关。此外,用户提到断开连接后仍输出错误日志,这可能涉及到资源未正确释放或异步操作未处理。 首先,考虑套接字未正确关闭。在C++中,如果套接字没有正确关闭,可能会导致连接残留,触发错误。需要检查IedConnection的断开和销毁流程,确保调用了正确的释放函数,如IedConnection_destroy。 其次,QT的信号和槽机制可能异步处理网络事件。如果主线程退出时,后台仍有未处理的网络操作,可能导致错误。需要确保在断开连接后,等待所有异步操作完成,或者使用QEventLoop进行延迟退出。 另外,引用[1]提到硬件接口的兼容性问题,这里虽然不直接相关,但配置参数的正确性可能影响通信。需要检查IEC61850库的通信参数设置,如超时时间或重试次数,是否正确配置。 引用[3]中的情况提示同一主机上的UDP广播问题,可能套接字选项设置有问题,如SO_REUSEADDR或SO_BROADCAST。需要确认在创建套接字时是否设置了正确的选项,以避免地址冲突或广播限制。 还需要检查是否有多个IedConnection实例未正确释放,导致资源泄漏。确保每次连接后都正确销毁对象,避免悬空指针。 最后,查看库的文档或社区是否有类似问题,可能有已知的解决方案或补丁。例如,某些库版本可能存在已知的关闭问题,升级或应用补丁可能解决。</think>### WIN32_SOCKET Socket_connect错误分析与解决方案 #### 问题定位 在IEC61850协议栈的C++/QT实现中,`WIN32_SOCKET: Socket_connect`错误通常与套接字未正确关闭或异步操作未完全终止有关,尤其是在程序退出时触发。结合引用[3]中提到的UDP广播特性,可能与以下原因相关: 1. **套接字未完全释放**:IedConnection对象未正确调用销毁函数 2. **异步通信残留**:QT事件循环未处理完网络事件时直接退出程序 3. **多线程竞争**:后台线程仍在尝试重连时主线程已终止 4. **协议栈兼容性问题**:IEC61850库与QT网络模块的交互异常 --- #### 分步解决方案 1. **显式释放IedConnection资源** ```cpp // 断开连接时确保执行完整关闭流程 IedConnection_close(connection); IedConnection_destroy(connection); // 必须显式调用 connection = nullptr; // 避免悬空指针 ``` 2. **添加QT事件循环延迟退出** ```cpp // 主窗口关闭事件处理 void MainWindow::closeEvent(QCloseEvent *event) { IedConnection_close(connection); QEventLoop loop; QTimer::singleShot(500, &loop, SLOT(quit())); // 延迟500ms等待资源释放 loop.exec(); event->accept(); } ``` 3. **设置套接字重用选项**(参考引用[3]的广播限制问题) ```cpp // 在创建连接前设置套接字参数 IedConnection_setSocketOption(connection, SO_REUSEADDR, 1); IedConnection_setSocketOption(connection, SO_LINGER, 0); // 强制快速关闭 ``` 4. **检查协议栈版本兼容性** ```bash # 推荐使用libiec61850 1.5+版本,已知修复了以下问题: # - 修复套接字关闭竞争条件 # - 改进QT事件循环集成 ``` 5. **添加错误日志过滤**(临时解决方案) ```cpp // 在QT消息处理中过滤特定错误 qInstallMessageHandler([](QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (!msg.contains("WIN32_SOCKET: Socket_connect")) // 过滤特定错误 defaultMessageHandler(type, context, msg); }); ``` --- #### 验证步骤 1. 使用`netstat -ano | findstr <PORT>`检查程序退出后是否仍有残留连接 2. 在调试器中设置断点观察`IedConnection_destroy`是否被调用 3. 通过Wireshark捕获分析TCP断开握手过程是否完整(FIN/ACK包交换) --- #### 进阶建议 1. **内存检测工具**:使用Valgrind检查资源泄漏 2. **协议栈调试**:启用libiec61850的调试日志 ```cpp IedConnection_setLogLevel(IED_LOG_DEBUG); ``` 3. **跨平台适配**:针对Windows的Winsock特性添加预处理指令 ```cpp #ifdef _WIN32 WSACleanup(); // 确保Winsock资源释放 #endif ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值