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

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

在计算机网络通信中,粘包是指在传输过程中,发送方发送的多个小数据包被接收方粘合在一起,形成一个大的数据包。这种现象通常出现在使用流式传输协议(如TCP)进行数据传输的情况下。

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

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


缓冲区大小限制: 接收方的缓冲区有限,可能无法及时处理到达的多个小数据块,导致合并成一个大的数据块。

延迟 ACK: 接收方可能延迟发送应答信号(ACK),使得发送方继续发送数据,导致数据合并。

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);
    
 
}


相关文章
|
3月前
|
网络协议 安全 网络安全
网络编程:基于socket的TCP/IP通信。
网络编程:基于socket的TCP/IP通信。
210 0
|
18天前
|
网络协议 Linux 应用服务中间件
Socket通信之网络协议基本原理
【10月更文挑战第10天】网络协议定义了机器间通信的标准格式,确保信息准确无损地传输。主要分为两种模型:OSI七层模型与TCP/IP模型。
|
1月前
|
网络协议 Linux 网络性能优化
Linux基础-socket详解、TCP/UDP
综上所述,Linux下的Socket编程是网络通信的重要组成部分,通过灵活运用TCP和UDP协议,开发者能够构建出满足不同需求的网络应用程序。掌握这些基础知识,是进行更复杂网络编程任务的基石。
77 1
|
2月前
|
网络协议 Linux 应用服务中间件
Socket通信之网络协议基本原理
【9月更文挑战第14天】网络协议是机器间交流的约定格式,确保信息准确传达。主要模型有OSI七层与TCP/IP模型,通过分层简化复杂网络环境。IP地址全局定位设备,MAC地址则在本地网络中定位。网络分层后,数据包层层封装,经由不同层次协议处理,最终通过Socket系统调用在应用层解析和响应。
|
3月前
|
网络协议 Java
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
这篇文章全面讲解了基于Socket的TCP网络编程,包括Socket基本概念、TCP编程步骤、客户端和服务端的通信过程,并通过具体代码示例展示了客户端与服务端之间的数据通信。同时,还提供了多个案例分析,如客户端发送信息给服务端、客户端发送文件给服务端以及服务端保存文件并返回确认信息给客户端的场景。
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
|
2月前
|
网络协议 Linux
TCP 和 UDP 的 Socket 调用
【9月更文挑战第6天】
|
3月前
|
网络协议
socket编程(2) -- TCP通信
socket编程(2) -- TCP通信
38 0
|
30天前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
21 0
|
4月前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
48 4
|
4月前
|
网络协议 Python
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
【7月更文挑战第26天】在网络的数字宇宙中,Python Socket编程是开启网络世界大门的钥匙。本指南将引领你从基础到实战,成为网络世界的建筑师。
62 2