我是靠谱客的博主 高高外套,最近开发中收集的这篇文章主要介绍TCP粘包解决方案TCP粘包解决方案,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

TCP粘包解决方案

黏包的在客户端发送频率低的情况下粘包不明显,下面是原来的服务器中epoll一个事件可读的回调函数recvdata(event_infor *infor),当调用这个函数然后recv()函数读缓冲区的数据,指定大小为BUFF_MAX-1,而BUFF_MAX我设置为1024,一般单次接收数据小于这个值,所以基本上就是读取了所有缓冲区数据,接收过程:收到数据->epoll可读->调用回调函数->读取缓冲区所有数据->空缓冲区等待下一次接收。在处理客户端发来的聊天消息时还没有发生粘包现象,处理文件传输时一直粘包,问题分析是客户端高速循环调用send()发送数据,也就是说服务器其实recv()多条数据,比如说发送{"code":1}{"code":2}服务器读一次可能是{"code":1}{"co
原服务器代码:

void Server::recvdata(event_infor *infor) {
    int n = recv(infor->fd, infor->buff, BUFF_MAX - 1, 0);
    if (n > 0) { //收到的数据
        infor->buff[n] = '';
        LOG(INFO) << infor->ip << " 发来一条消息: " << infor->buff;
        _messageQueue->push(infor->buff, infor);
    } else if (n == 0) {
        LOG(INFO) << "fd: " << infor->fd << " 连接关闭";
        close(infor->fd);
        infor->status = false;
    } else {
        close(infor->fd);
        infor->status = false;
        LOG(INFO) << "fd: " << infor->fd << " 连接关闭";
    }
    bzero(infor->buff, BUFF_MAX - 1);
}

解决办法见下:

//结构体定义
struct MessageStruct{
    int jsonLen;
    char json[0]; //不能换成char *json
};

客户端代码:

string data = "{"code":0,"data":{"passwd":"123456","name":"daimiaopeng"}}";
    int len = sizeof(MessageStruct) + data.size();
    MessageStruct *messageStruct = static_cast<struct MessageStruct *>(malloc(len));
    messageStruct->jsonLen = data.size();
    strncpy(messageStruct->json, data.c_str(), data.size());
    //也可以用memcpy(),这里是string->char* 而不是char*->char*
    for (int i = 0; i < 1000; i++) {
        send(sockfd, messageStruct, len, 0);
        }
    free(messageStruct);

改进后的服务器代码:

void Server::recvdata(event_infor *infor) {
    MessageStruct messageStruct;
    //读取结构体
    int n = recv(infor->fd, &messageStruct, sizeof(MessageStruct), 0);
    if (n > 0) { //收到的数据
        //获取结构体中的json长度字段
        char *jsonData = static_cast<char *>(malloc(messageStruct.jsonLen));
        //再读json数据
        if (jsonData== nullptr)
            return;
        recv(infor->fd, jsonData, messageStruct.jsonLen, 0);
        _messageQueue->push(string(jsonData, messageStruct.jsonLen), infor);
        free(jsonData);
    } else if (n == 0) {
        LOG(INFO) << "fd: " << infor->fd << " 连接关闭";
        close(infor->fd);
        infor->status = false;
    } else {
        close(infor->fd);
        infor->status = false;
        LOG(INFO) << "fd: " << infor->fd << " 连接关闭";
    }
}

总的来说是通过定义一个结构体然后二进制发送,读messageStruct的大小数据,sizeof(messageStruct)大小就是int类型的大小,为4,实际上后面还跟了数据,char json[0]不占用空间,而char *json是占用8个字节的,所以不能用char *json代替char json[0]这里是个坑注意一下,转换完成读取jsonLen的值,再读jsonLen大小的数据这样就完成分包了。这里比较难理解,建议网上多看几篇通过结构体解决粘包的文章,结合本文的代码理解。

最后

以上就是高高外套为你收集整理的TCP粘包解决方案TCP粘包解决方案的全部内容,希望文章能够帮你解决TCP粘包解决方案TCP粘包解决方案所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部