非阻塞socket判断connect是否成功的方法

本文介绍了如何在非阻塞模式下,通过fcntl设置socket为非阻塞,然后使用connect调用并处理EINPROGRESS错误,再利用select监视可写状态,最后通过getsockopt获取连接错误状态来判断connect是否成功。

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

<span style="font-size: 14px;">方法一:</span>

/*客户端设置非阻塞,然后判断链接是否成功*/
int SocketConnectWithTimeout
(
    int                 mySocket,          
    struct mySocketaddr     *adrs,        
    int                 adrsLen,        
    struct timeval      *timeVal        
)
{
    int     flag;
    fd_set  writeFds;
    int     remotPeerAdressLen;
    struct  mySocketaddr remotPeerAdress;
    
    if(timeVal == NULL)
    {
        return (connect(mymySocket, adrs, adrsLen));
    }
    	
    flag = fcntl(mySocket, F_GETFL, 0); 
    fcntl(mySocket, F_SETFL, flag | O_NONBLOCK);//修改当前的flag标志为给阻塞
	
    //对于非阻塞式套接字,如果调用connect函数会之间返回-1(表示出错),且错误为EINPROGRESS,表示连接建立
    if(connect(mySocket, adrs, adrsLen) < 0)
    {
       //当使用非阻塞模式的时候,如果链接没有被立马建立,则connect()返回EINPROGRESS
    	if(errno == EINPROGRESS)
    	{
		//select是一种IO多路复用机制,它允许进程指示内核等待多个事件的任何一个发生,并且在有一个或者多个事件发生或者经历一段指定的时间后才唤醒它。
	    //connect本身并不具有设置超时功能,如果想对套接字的IO操作设置超时,可使用select函数。此时我们使用不断的检测writeFds来判断链接的建立?
    	    FD_ZERO(&writeFds);
    	    FD_SET((unsigned int)mySocket, &writeFds); 
    
            if(select(FD_SETSIZE, (fd_set *)NULL, &writeFds, (fd_set *)NULL, timeVal) > 0)
            {
				//select()成功了,查看mySocketet是否可写(关键)
            	if (FD_ISSET ((unsigned int)mySocket, &writeFds))
            	{
				//已经可写了,此时我们要通过使用getpeername()判断是否真正的链接成功,如果返回值不是-1;
				//说明connect()成功了。
            	    remotPeerAdressLen = sizeof (remotPeerAdress);
            	    if(getpeername (mySocket, &remotPeerAdress, &remotPeerAdressLen) != ERROR)
            	    {
            	        return OK;
            	    }
            	    else
            	    {
            	        return ERROR;
            	    }
            	}
    	    }
    	}
    	else
    	{
			return ERROR;
    	}
    }

    fcntl(mySocket, F_SETFL, flag);//恢复标志位为阻塞
}

方法二:

1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完成(有的系统用FNEDLAY也可).

2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧行还没有完成. 

3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,如果可写

   用getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int)); 来得到error的值,如果为零,则connect成功.



<think>好的,我现在需要帮助用户解决如何在Qt中判断TcpSocket发送数据是否成功的问题。首先,我得回想一下Qt中TCP通信的相关知识。用户提到了Qt的QTcpSocket类,所以应该涉及这个类的使用方法。 用户的问题是关于发送数据后如何判断是否成功。根据之前学过的内容,Qt的网络模块主要通过信号和槽机制来处理异步操作。发送数据通常使用write方法,但write的返回值可能只是表示数据被写入本地缓冲区,并不一定已经发送到网络。因此,直接判断write的返回值可能不够准确。 接下来,我需要考虑如何确认数据是否真正发送成功。记得Qt的QTcpSocket有bytesWritten信号,这个信号在数据实际被写入网络时会触发,参数是已经写入的字节数。或许可以通过连接这个信号来跟踪发送进度。另外,可能需要结合waitForBytesWritten方法,在同步操作中等待数据写入。 然后,错误处理也是关键。QTcpSocket会有errorOccurred信号,可以捕获发送过程中的错误,比如网络中断、连接关闭等。此外,检查socket的状态,比如是否仍然处于ConnectedState,也可能有帮助。 用户提供的引用中,引用[5]提到发送失败可能由网络延迟或阻塞引起,特别是大数据传输时。这说明需要考虑网络状况,可能需要设置超时机制,避免无限等待。 可能的解决方案步骤包括:使用write方法并检查返回值是否与预期数据大小一致;使用waitForBytesWritten等待数据写入,并处理超时;监听bytesWritten信号累计已发送的字节数;处理错误信号,记录错误信息;检查socket连接状态。 需要注意异步和同步处理的不同场景。比如在异步模式下,使用信号和槽来跟踪发送进度,而在同步模式下,使用waitFor方法并设置超时时间。 还需要考虑数据分片的情况,比如发送的数据大于缓冲区大小时,可能需要分多次发送,这时候累计发送的字节数就很重要了。引用[1]提到粘包和半包的问题,虽然用户的问题是关于发送成功判断,但数据分片处理也可能影响发送结果的判断。 最后,综合这些方法,给出一个示例代码,展示如何结合write、waitForBytesWritten、bytesWritten信号和错误处理来实现发送成功与否的判断。同时,提醒用户处理网络异常和资源释放的问题。</think>在Qt中判断QTcpSocket发送数据是否成功,可以通过以下方法实现: ### 一、基础判断方法 1. **检查`write()`返回值** 发送数据后立即检查`write()`的返回值,若返回值等于待发送数据长度,说明数据已成功写入本地缓冲区: ```cpp qint64 bytesWritten = socket->write(data); if(bytesWritten == data.size()) { // 数据已写入本地缓冲区 } ``` 但需注意这仅表示数据进入Qt的发送缓冲区,不代表数据已到达接收端[^5]。 2. **使用`waitForBytesWritten()`方法** 在同步操作中强制等待数据发送完成: ```cpp if(socket->waitForBytesWritten(3000)) { // 3秒超时 // 数据已写入操作系统缓冲区 } else { // 超时或发生错误 } ``` ### 二、高级状态跟踪 3. **通过`bytesWritten()`信号跟踪进度** 实时监控实际发送字节数: ```cpp connect(socket, &QTcpSocket::bytesWritten, [total = data.size()](qint64 bytes){ static qint64 sent = 0; sent += bytes; if(sent >= total) qDebug() << "All data sent"; }); ``` 4. **错误处理机制** 监听错误信号并检查连接状态: ```cpp connect(socket, &QTcpSocket::errorOccurred, [](QAbstractSocket::SocketError){ qDebug() << "Send error:" << socket->errorString(); }); if(socket->state() != QAbstractSocket::ConnectedState) { qDebug() << "Connection lost"; } ``` ### 三、完整示例代码 ```cpp bool sendData(QTcpSocket* socket, const QByteArray &data) { qint64 total = 0; qint64 bytesToWrite = data.size(); while(total < bytesToWrite) { qint64 written = socket->write(data.constData() + total, bytesToWrite - total); if(written <= 0) { qDebug() << "Write failed:" << socket->errorString(); return false; } total += written; if(!socket->waitForBytesWritten(3000)) { // 等待3秒 qDebug() << "Timeout or error:" << socket->errorString(); return false; } } return true; } ``` ### 四、注意事项 - **网络异常处理**:建议配合心跳机制检测连接状态 - **大数据分片**:单次发送数据建议不超过4KB,避免MTU分片问题[^1] - **编码问题**:使用`.toUtf8()`而非`.toLatin1()`避免中文乱码[^2] - **线程安全**:建议在独立线程处理网络I/O操作[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值