Socket粘包解决办法

本文介绍了如何在Qt和C++环境中处理TCP Socket的粘包问题。通过先读取数据长度,然后根据长度读取实际数据,或者读取包含长度信息的结构体来避免粘包现象。示例代码展示了使用read()函数读取数据并处理粘包的策略。

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

1.Qt
变量说明:
char msg : 用于存储从socket读取的数据
head.length:这个变量也是右socket传过来,第一次先传长度(或包含长度的结构体)
int recvNum:用于存储read socket数据的实际长度;
(QTcpSocket
mp_qTcpSocket; ->这个是指用于通讯的socket)

    char* msg = new char[head.length];
    int remainLen = head.length;//记录总长度,以及之后未读数据的长度
    int recvNum = 0;//用于记录read实际从缓冲区读取到的数据长度
    int offset = 0;//read读取数据后内存地址的指向的位置
    while (remainLen > 0) {
       //msg+offset指的是内存中指针的位置,第一次从0开始,之后每次都从上次读取数据总长度后面继续读取数据
        recvNum = mp_qTcpSocket->read(msg + offset, remainLen);
        if (recvNum == -1) {
            //断开socket连接(判断errno,socket不可用需要重新断开重连)
            tcp_disconnect();
        } else if (recvNum == 0) {
            //对端的连接断开,继续等待其他socket连接
            qDebug() << "recvNum == 0" << endl;
            continue;
        } else {
            //正常接收数据,返回从缓冲区读取到的数据
            //未读取数据长度 = 之前socket收到的数据总长度 - 本次实际从缓冲区读取到的数据长度
            remainLen = remainLen - recvNum;
            //跟新已经读取了数据的位置
            offset = offset + recvNum;
        }
    }

2.C++
ssize_t Client::readData(int fd, void* userbuf, size_t length)
{
//socket数据的总长度
size_t nleft = length;
//下面while循环中每次实际读取到的数据长度
ssize_t nread = 0;
//存储数据
char* bufp = (char*)userbuf;
while (nleft > 0) {
std::cout<<“nleft:”<<nleft<<std::endl;
nread = read(fd, bufp, nleft);
if (nread < 0) {
std::cout<< "read error: " << strerror(errno) << std::endl;
if (errno == EINTR) {
nread = 0;
} else {
return -1;
}
} else if (nread == 0) {
break; // EOF
}

//成功从缓冲区读取数据
nleft -= nread; //剩下未读取数据长度 = 总数据长度 - 本次读取数据长度
bufp += nread; //存储数据内存指针往后移动读取到的数据长度,以便下次读取从未读取数据的内存地址开始读取数据
}
//返回数据的长度
return length - nleft;
}

用法:
int len = 0;
static char gbuffer[819600] = {0};
memset(gbuffer, 0, sizeof(gbuffer));

=================================================================
//先读取数据长度,再读取数据
uint32_t msg_length = 0;
len = readData(sockfd, &msg_length, sizeof(uint32_t));//与socket另一端配合,先读取数据长度(另一端也要同步先发送数据长度)

=================================================================
//先读取一个结构体,再读取数据(结构体中需要包含长度,其他的值可以自行定义)
typedef struct dataT{
int data_id;
unsigned long time_stamp;
int buffer_size;
}qdataT_t;
qdataT_t m_recvData;
memset(&m_recvData, 0 , sizeof(m_recvData));

readData(socket_fd,&m_recvData,androdHeadLen);
auto error = readData(android_fd,img_buf,m_recvData.buffer_size);
if (error < 0)
{
std::cout << strerror(error);
continue;
}

=================================================================

if (len > 0)
{
int nread = readData(sockfd, gbuffer, msg_length);//将数据读取到gbuffer数组中

	//正常读取数据后的处理
	。。。。

}
else if (len == 0)
{
//另一端的客户端断开连接
std::cout<<“server socket close”<<std::endl;
//等待其他socket连接
continue;
}
else if (len = -1)
{
//本身socket出现问题,必须重启
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值