Socket实现模拟TCP通信粘包问题

发布时间:2024年01月24日

在计算机网络通信中,粘包是指在传输过程中,发送方发送的多个小数据包被接收方粘合在一起,形成一个大的数据包。这种现象通常出现在使用流式传输协议(如TCP)进行数据传输的情况下。
具体来说,TCP是一种面向连接的协议,它通过将数据划分为小的数据块(通常称为段)进行传输。发送方将这些数据块发送到网络,而接收方则负责将它们重新组装成原始的数据。然而,由于网络的不确定性和各种因素,接收方有时会在处理数据时将多个小数据块合并成一个大的数据块,从而产生粘包现象。


造成粘包的原因可能是多方面的,其中一些常见的因素包括:

  1. 缓冲区大小限制: 接收方的缓冲区有限,可能无法及时处理到达的多个小数据块,导致合并成一个大的数据块。
  2. 延迟 ACK: 接收方可能延迟发送应答信号(ACK),使得发送方继续发送数据,导致数据合并。
  3. Nagle算法: Nagle算法会将小的数据块合并成更大的数据块一起发送,以提高网络利用率,但这也可能引发粘包问题。

为了解决粘包问题,通常采取以下策略:

  • 消息长度前缀: 在每个数据包前添加消息长度信息,接收方通过这个信息来准确地拆分数据包。
  • 消息边界: 使用特定的消息边界符或标记来标识数据包的边界。
  • 固定长度的消息: 确定一个固定的消息长度,确保每个数据包都符合这个长度。
  • 使用应用层协议: 利用应用层协议进行消息的封装和解析,如使用JSON或XML格式。

这些方法有助于在数据传输过程中有效地处理粘包问题。选择哪种方法取决于具体的应用场景和需求。

分包解决粘包问题------------------------下一篇博客

完整代码:

server:

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

int main(int, char**){
    //1.创建套接字
    int listen_sock=socket(AF_INET,SOCK_STREAM,0);

    if (listen_sock==-1)
    {
        std::cerr<<"Fiald to create socket"<<std::endl;
        return 1;
    }
    

    //2.绑定IP地址
    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));

    server_addr.sin_addr.s_addr=INADDR_ANY;
    server_addr.sin_family=AF_INET;
    server_addr.sin_port=htons(9999);

    if(bind(listen_sock,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1)
    {
        std::cerr<<"Fiald to bind socket"<<std::endl;
        return 1;
    }
    //3.监听套接字

    if (listen(listen_sock,5)==-1)
    {
        std::cerr<<"Fiald to listen socket"<<std::endl;
        return 1;
    }
    
    std::cout<<"server is listening"<<std::endl;

    //4.接受客户端的连接

    struct sockaddr_in client_addr;
    socklen_t client_addr_len=sizeof(client_addr);

    int client_sock=accept(listen_sock,(struct sockaddr*)&client_addr,&client_addr_len);

    if (client_sock==-1)
    {
        std::cerr<<"Fiald to accept socket"<<std::endl;
        return 1;
    }
    std::cout<<"a client connected"<<std::endl;

    //5.数据交互
    
    //接受消息
    while (1)
    {
        char buffer[1024];
        int read_size=read(client_sock,buffer,sizeof(buffer));
    
        if (read_size<0) 
        {
            std::cerr<<"Fiald to read"<<std::endl;
            close(client_sock);
            close(listen_sock);
            exit(0);
        }
        std::cout<<"Received msg :"<<buffer<<std::endl;
    }
    // std::cout<<"Received to client :"<<buffer<<std::endl;
    // std::string res_msg="Hello Client!";
    // int wr=write(client_sock,res_msg.c_str(),res_msg.length());

    // if (wr==-1)
    // {
    //     std::cerr<<"Fiald to write"<<std::endl;
    //     return 1;
    // }
    
    close(client_sock);
    close(listen_sock);
}

client:

#include <iostream>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(){

    //1.创建socket
    int client_sock=socket(AF_INET,SOCK_STREAM,0);
    if (client_sock==-1)
    {
        std::cerr<<"Faild to create socket"<<std::endl;
        return -1;
    }

    //2.连接服务器

    struct sockaddr_in server_addr;
    server_addr.sin_family=AF_INET;
    //server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
    server_addr.sin_port=htons(9999);

    if(connect(client_sock,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1){
        std::cerr<<"Faild to connect socket"<<std::endl;
        return -1;
    }

    std::cout<<"Connected to server"<<std::endl;

    //3.数据交互

    //发送消息
    
    std::string msg1="hi";
    std::string msg2="jack";

    if(write(client_sock,msg1.c_str(),msg1.length())==-1){
        std::cerr<<"Faild to write "<<std::endl;
        return -1;
    }

    if(write(client_sock,msg2.c_str(),msg2.length())==-1){
        std::cerr<<"Faild to write "<<std::endl;
        return -1;
    }

    //接受消息

    // char buffer[1024];
    // if(read(client_sock,buffer,sizeof(buffer))==-1){
    //     std::cerr<<"Faild to read"<<std::endl;
    //     return -1;
    // }

    // printf("Receive to server :%s",buffer);

    close(client_sock);
    

}
文章来源:https://blog.csdn.net/festaw/article/details/135741272
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。