Linux Socket 分包 和 粘包 问题 - 解决方案

Linux Socket编程中的TCP粘包问题解决方案 TCP协议为了保证传输效率,可能会将多次send调用发送的数据合并在一个TCP报文中发送出去。这样,接收方在读取时就可能遇到粘包问题,即无法直接从字节流中识别出各个独立的数据包。粘包问题是TCP编程中常见的问题之一,通过合理设计协议格式,可以有效避免或解决粘包问题,保证数据传输的准确性。希望本文能为您提供一些处理粘包问题的思路和方法。✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进❤欢迎关注我的知乎:对error视而不见代码获取、问题探讨及文章转载可私信。 阅读详情

分包和粘包在TCP网络编程中是非常常见的,分包会造成 接收端 接收的数据不全的问题,粘包会造成接收多余的数据的文件。

这里做一个举例,例如客户端A要发送字符串“helloworld”给服务器B,A是一次性发送,但TCP有可能会将其分成两个包去发送,如分成“hello”和“world”,当服务器不知道数据已经被分成两个包去发送了,它只是接收也一个包,即只接收了“hello”,造成数据接收不全的问题!

或者说,当发送的数据过小时,却连续发送多次时,TCP会将他们同时打包,一起发送,接收时如果也是一次性接收,那么就会接收了多余的数据了!


目录

一、TCP分包

二、TCP粘包

三、分包和粘包的解决方案

1. 组合数据关键代码

2. 解析数据关键代码

四、示例

client.c

server.c

编译运行测试

五、总结


一、TCP分包

场景:发送方发送字符串”helloworld”,接收方却分别接收到了两个数据包:字符串”hello”和”world”;

发送端发送了数量较多的数据,接收端读取数据时候数据分批到达,造成一次发送多次读取;

造成分包的原因:

TCP是以段(Segment)为单位发送数据的,建立TCP链接后,有一个最大消息长度(MSS).如果应用层数据包超过MSS,就会把应用层数据包拆分,分成两个段来发送.

这个时候接收端的应用层就要拼接这两个TCP包,才能正确处理数据。

相关的,路由器有一个MTU( 最大传输单元)一般是1500字节,除去IP头部20字节,留给TCP的就只有MTU-20字节。所以一般TCP的MSS为MTU-20=1460字节;

当应用层数据超过1460字节时,TCP会分多个数据包来发送。

二、TCP粘包

场景:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”;

发送端发送了几次数据,接收端一次性读取了所有数据,造成多次发送一次读取;通常是网络流量优化,把多个小的数据段集满达到一定的数据量,从而减少网络链路中的传输次数;

造成TCP粘包的原因:

TCP为了提高网络的利用率,会使用一个叫做Nagle的算法.该算法是指,发送端即使有要发送的数据,如果很少的话,会延迟发送.如果应用层给TCP传送数据很快的话,就会把两个应用层数据包“粘”在一起,TCP最后只发一个TCP数据包给接收端.

三、分包和粘包的解决方案

发送数据前,给数据附加固定的头部长度:

1. 包标识:  包头部的特殊标识,用来标识包的开始;

2. 数据长度:数据包的大小,固定长度,2、4 或者8字节;

3. 数据内容:数据内容,长度为数据头定义的长度大小;

假设包标识是FBEB,即,如果发送的数据是helloworld,则组合发送的数据为:FBEB10helloworld

实际操作如下:

a)发送端:先发送包表示和长度,再发送数据内容。

b)接收端:先解析本次数据包的大小N,再读取N个字节,这N个字节就是一个完整的数据内容。

具体流程如下:

按照这种思路,就可以解决分包和粘包的问题了!

1. 组合数据关键代码

#define DATA_LEN_BYTES  4
const char *TAG = "FBEB";

char *message = "helloworld";

int ms_len = strlen(message);  
int tag_len = strlen(TAG);

// 组装数据包
char *buf = (char*)malloc(ms_len + tag_len + DATA_LEN_BYTES);
memset(buf, '\0', ms_len + tag_len + DATA_LEN_BYTES);

strcpy(buf, TAG);
*((int *)(buf + tag_len)) = ms_len;
memcpy(buf + tag_len + DATA_LEN_BYTES, message, ms_len);

这样组合出来的数据就是符合上面我们规定的那样了!

解析再按相应规则进行解析就可以得到数据了!

2. 解析数据关键代码

#define DATA_LEN_BYTES  4
const char *TAG = "FBEB";

int tag_len = strlen(TAG);
char buf[1024] = { '\0' };


// 1. 首先接收头部信息
read(client_sock, buf, tag_len + DATA_LEN_BYTES);


// 2. 通过strncmp比较,即可得知数据开始部分是否是我们定义的标识
if (strncmp(buf, TAG, tag_len) == 0) { /* 符合条件 */ }


// 3. 获得实际数据的大小
int dataLen = *((int *)(buf + tag_len));


// 4. 循环接收数据,存储到buf中
int count = 0;
int readLen = 0;
while (count < dataLen) {
    readLen = read(client_sock, buf + count, dataLen - count);    // dataLen-count:还需要接收多少数据
    
    count += readLen;    // 统计已经接收了多少数据
}

这样,不管是分包和粘包问题都可以正常的接收了!

四、示例

客户端发送消息给服务器,服务器发送消息给客户端!模拟分包发送!

客户端发送数据给服务器时,将数据拆成三个包发送;服务器发送数据给客户端时,将数据包拆成两个包发送!

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>

#define SERVER_PORT     4567
#define SERVER_IP       "127.0.0.1"
#define DATA_LEN_BYTES  4

const char *TAG = "Jtom";




int read_package(int client_sock, char *buf, unsigned int len) {
    int readLen = 0;    // 当前读取字节数
    int count = 0;      // 已经读取字节数
    
    if (buf == NULL || client_sock < 1) {
        printf("Parameters are wrong!\n");
        return -1;
    }
      
    
    int tag_len = strlen(TAG);

    int ret = read(client_sock, buf, tag_len + DATA_LEN_BYTES);
    if (-1 == ret) {
        fprintf(stderr, "read failed! reason:%s", strerror(errno));
        return ret;
    } else if (0 == ret) {
        printf("1read data return 0!\n");
        return ret;
    }

    // 对TAG进行检查
    if (strncmp(buf, TAG, tag_len) == 0) {
        int dataLen = *((int *)(buf + tag_len));
        //printf("dataLen = %d\n", dataLen);
        
        int failCount = 0;  // 失败重试
        
        // 读取数据部分
        count = 0;
        readLen = 0;
        while (count < dataLen) {
            readLen = read(client_sock, buf + count, dataLen - count);
            printf("readLen = %d\n", readLen);
            if (-1 == readLen) {
                if (5 > failCount) {
                    failCount++;
                    readLen = 0;
                } else {
                    fprintf(stderr, "read failed! reason:%s", strerror(errno));
                    return readLen;
                }
                
            } else if (0 == readLen) {
                if (5 > failCount) {
                    failCount++;
                    readLen = 0;
                } else {
                    printf("2read data return 0!\n");
                    return ret;
                } 
            }
            
            count += readLen;
        }
        
        return dataLen;
    }
}    



// 线程执行函数
void *my_thread_handle(void *arg) {
    
    char buf[1024] = { '\0' };
    int sockfd = *(int *)arg;
    int failCount = 0;  // 失败重试5次
    
    while (1) {
       // 读取服务器发送回来的信息
        int len = read_package(sockfd, buf, sizeof(buf));
        if (len > 0) {
            buf[len] = '\0';
            printf("receive[%d]: %s", len, buf);
        } else {
            if (5 > failCount) {
                failCount++;
                sleep(1);
            } else {               
                fprintf(stderr, "connect server off!\n");                             
                break;
            }
        }            
        
        if (strncmp(buf, "end", 3) == 0) {
            break;
        }
        memset(buf, '\0', sizeof(buf));
    }
    
    pthread_exit(NULL);
}



int main(int argc, char *argv[]){

    int sockfd;
    char message[1024] = { '\0' };
    struct sockaddr_in servaddr;
    int n;
    char *buf = NULL;


    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&servaddr, '\0', sizeof(struct sockaddr_in));

    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
    servaddr.sin_port = htons(SERVER_PORT);

    int ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if (-1 == ret) {
        printf("connet failed! reason:%s\n", strerror(errno));
        exit(1);
    }
    
    
    // 创建线程取接收客户端发送过来的数据
    pthread_t mythread;
    // 创建线程
    ret = pthread_create(&mythread, 0, my_thread_handle, &sockfd);
    if (0 != ret) {
        printf("create thread failed!\n");
        exit(1);
    }
    
    
    while (1) {
        fgets(message, 1024, stdin);
        
        int ms_len = strlen(message);  
        int tag_len = strlen(TAG);
        
        // 组装数据包
        buf = (char*)malloc(ms_len + tag_len + DATA_LEN_BYTES);
        memset(buf, '\0', ms_len + tag_len + DATA_LEN_BYTES);
        
        strcpy(buf, TAG);
        *((int *)(buf + tag_len)) = ms_len;
        memcpy(buf + tag_len + DATA_LEN_BYTES, message, ms_len);
        
        
        // 先发送头部,即标识符和发送数据的大小
        write(sockfd, buf, tag_len + DATA_LEN_BYTES);
        
        // 模拟发送三个包
        write(sockfd, buf + tag_len + DATA_LEN_BYTES, 1);
        sleep(1);
        write(sockfd, buf + tag_len + DATA_LEN_BYTES + 1, 1);
        sleep(1);
        write(sockfd, buf + tag_len + DATA_LEN_BYTES + 2, ms_len - 2);
        
        if (strncmp(buf + tag_len + DATA_LEN_BYTES, "exit", 4) == 0) {
            free(buf);
            break;
        }
        free(buf);
    }
   

    printf("finished.\n");
    close(sockfd);

    return 0;
}

server.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>        // strerror
#include <ctype.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
 

#define SERVER_PORT     4567
#define SERVER_IP       "127.0.0.1"
#define DATA_LEN_BYTES  4

const char *TAG = "Jtom";



int read_package(int client_sock, char *buf, unsigned int len) {
    int readLen = 0;    // 当前读取字节数
    int count = 0;      // 已经读取字节数
    
    if (buf == NULL || client_sock < 1) {
        printf("Parameters are wrong!\n");
        return -1;
    }
      
    
    int tag_len = strlen(TAG);

    int ret = read(client_sock, buf, tag_len + DATA_LEN_BYTES);
    if (-1 == ret) {
        fprintf(stderr, "read failed! reason:%s", strerror(errno));
        return ret;
    } else if (0 == ret) {
        printf("read data return 0!\n");
        return ret;
    }

    // 对TAG进行检查
    if (strncmp(buf, TAG, tag_len) == 0) {
        int dataLen = *((int *)(buf + tag_len));
        //printf("dataLen = %d\n", dataLen);
        
        int failCount = 0;  // 失败重试
        
        // 读取数据部分
        count = 0;
        readLen = 0;
        while (count < dataLen) {
            readLen = read(client_sock, buf + count, dataLen - count);
            printf("readLen = %d\n", readLen);
            if (-1 == readLen) {
                if (5 > failCount) {
                    failCount++;
                    readLen = 0;
                } else {
                    fprintf(stderr, "read failed! reason:%s", strerror(errno));
                    return readLen;
                }
                
            } else if (0 == readLen) {
                if (5 > failCount) {
                    failCount++;
                    readLen = 0;
                } else {
                    printf("read data return 0!\n");
                    return ret;
                } 
            }
            
            count += readLen;
        }
        
        return dataLen;
    }
}    



// 线程执行函数
void *my_thread_handle(void *arg) {
    
    char buf[1024] = { '\0' };
    int client_sock = *(int *)arg;
    int failCount = 0;
    
    while (1) {
       // 读取服务器发送回来的信息
        int len = read_package(client_sock, buf, sizeof(buf));
        if (len > 0) {
            buf[len] = '\0';
            printf("receive[%d]: %s", len, buf);
        } else {
            if (5 > failCount) {
                failCount++;
                sleep(1);
            } else {
                fprintf(stderr, "connect client off!\n");                             
                break;
            }
        }       
        
        if (strncmp(buf, "end", 3) == 0) {
            break;
        }
        memset(buf, '\0', sizeof(buf));
    }
    
    pthread_exit(NULL);
}
 
 
 
int main(void) {
	
	int ret = 0;
	int sock;	// 通信套接字
	struct sockaddr_in server_addr;
    char message[1024] = { '\0' };
	
	// 1.创建通信套接字
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sock) {
		fprintf(stderr, "create socket error, reason: %s\n", strerror(errno));
		exit(-1);
	}
	
	// 2.清空标签,写上地址和端口号
	bzero(&server_addr, sizeof(server_addr));
	
	server_addr.sin_family = AF_INET;	// 选择协议组ipv4
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);	// 监听本地所有IP地址
	server_addr.sin_port = htons(SERVER_PORT);			// 绑定端口号
	
	// 3.绑定
	ret = bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (-1 == ret) {
		fprintf(stderr, "socket bind error, reason: %s\n", strerror(errno));
		close(sock);
		exit(-2);
	}
	
	// 4.监听,同时监听128个请求
	ret = listen(sock, 128);
	if (-1 == ret) {
		fprintf(stderr, "listen error, reason: %s\n", strerror(errno));
		close(sock);
		exit(-2);
	}
	
	printf("等待客户端的链接\n");
    
    struct sockaddr_in client;
    int client_sock;
    char client_ip[64];
    
    socklen_t client_addr_len;		
    client_addr_len = sizeof(client);
    // 5.接受
    client_sock = accept(sock, (struct sockaddr *)&client, &client_addr_len);
    if (-1 == client_sock) {
        perror("accept error");
        close(sock);
        exit(-3);
    }
    
    // 打印客户端IP地址和端口号
    printf("client ip: %s\t port: %d\n",
            inet_ntop(AF_INET, &client.sin_addr.s_addr, client_ip, sizeof(client_ip)),
            ntohs(client.sin_port));
    
    
    // 创建线程取接收客户端发送过来的数据
    pthread_t mythread;
    // 创建线程
    ret = pthread_create(&mythread, 0, my_thread_handle, &client_sock);
    if (0 != ret) {
        printf("create thread failed!\n");
        exit(1);
    }
    
    
	
	while (1) {
		
		fgets(message, sizeof(message), stdin);
        int ms_len = strlen(message);  
        int tag_len = strlen(TAG);
        
        // 组装数据包
        char *buf = (char*)malloc(ms_len + tag_len + DATA_LEN_BYTES);  
        memset(buf, '\0', ms_len + tag_len + DATA_LEN_BYTES);
        
        strcpy(buf, TAG);
        *((int *)(buf + tag_len)) = ms_len;
        memcpy(buf + tag_len + DATA_LEN_BYTES, message, ms_len);
        
        
        // 先发送头部,即标识符和发送数据的大小
        write(client_sock, buf, tag_len + DATA_LEN_BYTES);
        
        // 模拟发送两个包
        write(client_sock, buf + tag_len + DATA_LEN_BYTES, 1);
        sleep(1);
        write(client_sock, buf + tag_len + DATA_LEN_BYTES + 1, ms_len - 1);
        
        if (strncmp(buf + tag_len + DATA_LEN_BYTES, "exit", 4) == 0) {
            free(buf);
            break;
        }

        free(buf);
	}
	
	// 9.关闭服务器套接字
	close(sock);
    close(client_sock);
	
	return 0;
}

编译运行测试

gcc client.c -lpthread -o client

gcc server.c -lpthread -o server

某一端输入exit退出后,另一端会持续读取6次,如果超过6次,也就结束了,但也还要输入exit退出才行!

五、总结

TCP的分包和粘包相关问题已经列出来了,解决办法也记录下来了;

下次还需要写TCP编程时,需要注意分包和粘包的问题,然后组合数据去发送!

C# 使用TouchSocket实现Tcp协议通讯,并且解决分包、粘包的问题 我们知道如果Socket传输数据太频繁并且数据量级比较大,就很容易出现分包(一个包的内容分成了两份)、粘包(前一个包的内容分成了两份,其中一份连着下一个包的内容)的情况。 粘包的处理方式有很多种,常见的三种是: 每个包都在头部增加一个当前传输包的int4字节大小作为包头。每次接收到数据先读取的包头,确定这一包的实际长度n,当接收够n+4长度的数据就是一个完整的包,再重复读取下一包的包头。(相对... 阅读详情

相关推荐

C#Socket通信,解决粘包和分包问题

源码下载,学习的时候做的,现在可以做到一个服务端对应多个客户端同时接受消息,也解决了分包和粘包的问题,欢迎下载 (16条消息) 网络通信编程学习.7z-C#文档类资源-优快云文库https://download.youkuaiyun.com/download/Trinity_Force/44900216 什么是粘包分包 TCP是面向连接的协议 TCP是点到点的通信 TCP提供可靠的传输服务 TCP协议提供全双工的通信 TCP协议面向字节流进行传输的,可以对用户的数据进行拆分或合并 TCP...

Trinity_Force的博客 1万+

Socket TCP协议解决粘包、半包问题的三种解决方案

什么是粘包、半包问题: 粘包:例如服务端依次将两条消息发送给客户端,我们暂且简单的将这两条消息举例为"Hello"、"Unity",而客户端读取到的内容却是"HelloUn",像这种一次性读取到两条消息中数据内容的情况称之为粘包。 半包:例如服务端发送消息"Hello"给客户端,而客户端依次读取到"Hel","lo"两条消息,这种情况称之为半包。 粘包、半包发生的原因: 粘包:消息发送方发送完完整的消息后,接收方没有及时处理(比如网络开小差,未能及时读...

当代野生程序猿 1万+

(六)深入浅出TCPIP之TCP拥塞控制

目录 什么是网络拥塞 如何避免拥塞 拥塞点 避免拥塞 慢启动算法 算法思想 慢启动解析 启动过程 拥塞避免算法 启动过程 快速重传算法 快速恢复 总结 连环发问: 专栏其他文章: (一)深入浅出TCPIP之理解TCP报文格式和交互流程 (二)深入浅出TCPIP之再识TCP,理解TCP三次握手(上) (三)深入浅出TCPIP之再识TCP,理解TCP四次挥手(上) (四)深入浅出TCPIP之TCP三次握手和四次挥手(下)的抓包分析 (五)深入浅出TC...

yolo模型训练找我,AI游戏合作找我 1198

socket粘(黏)包问题是什么?用python怎么解决?一文解释透透的!

Socket粘包问题是在网络通信中常见的一种情况,它指的是发送方在发送数据时,将多个小的数据包粘成了一个大的数据包,接收方在接收数据时,无法准确区分每个小的数据包的边界,导致数据解析出错,那么如何解决呢??

天河书阁 - VicRestart 2107

VisionPro九点标定实战:从相机拍照到机器人精准抓取的完整流程

本文详细介绍了VisionPro九点标定技术在工业自动化中的应用,从相机拍照到机器人精准抓取的完整流程。通过硬件配置、标定步骤和实战技巧的解析,帮助工程师实现高精度视觉引导系统,提升生产效率。特别适合需要解决二维图像坐标与物理空间转换问题的自动化项目。

weixin_30664051的博客 406

学术版GPT安装教程——保姆版(附带原生GPT注册教程)

学术版GPT图文安装教程

DBenD的博客 2万+

c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包

在TCP协议中,无论发送多少数据,都要在数据前面加上协议头,同时,对方收到数据后,也需要回复ACK表示确认。为了尽可能的利用网络带宽,TCP希望每次都能够以MSS(Maximum Segment Size,最大报文长度)的数据块来发送数据。这一篇文章主要是为下一篇网络编程的服务端与客户端编写做一个引子,介绍一些有关网络编程的基本知识,因为下一篇文章将会给大家介绍在c++网络编程中有关服务端与客户端的编写,本文只做一些理论介绍,大家下篇见!

qq_73924465的博客 2091

CNN卷积神经网络手写数字识别实例及代码详解

本文的代码来自githup的Deep Learning的toolbox,是用Matlab实现的。感谢该toolbox的作者付出和分享。 我在应该该代码进行训练时,出现一些报错,如expand函数应用不对,flipall函数未定义等问题,对这些问题进行了修正,完成网络训练和验证。 本文mnist_uint8.mat的获取可以参照我的另一篇博客:MNIST数据库处理--matlab生成mnist_

VivienFu的专栏 6万+

Linux下的socket编程实践(四)TCP的粘包问题和常用解决方案

TCP粘包问题的产生 由于TCP协议是基于字节流并且无边界的传输协议, 因此很有可能产生粘包问题。此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,但是接收方并不知道要一次接收多少字节的数据,这样接收方就收到了粘包数据。具体

NK_test的博客 5977

MacOS上如何修改jupyter book的默认打开地址以及如何复制文件路径

记点笔记,才换新系统小半年,还是不太熟悉,所以记录一下笔记,感觉之后也会用到,希望能帮到你们。主要内容是:修改jupyter的默认地址以及复制文件路径。

魔仙的博客 1978

从零到一:手把手教你用海康VisionMaster完成第一个字符识别项目(附完整流程与避坑点)

本文详细介绍了如何使用海康VisionMaster完成首个字符识别项目,涵盖从环境搭建、图像预处理到系统集成的完整流程。特别分享了Blob分析配置、字符识别优化等实战技巧,帮助开发者避开常见陷阱,快速掌握VisionMaster的基本操作,提升工业自动化场景下的字符识别效率。

weixin_29313423的博客 664

linux网络编程之socket(五):tcp流协议产生的粘包问题和解决方案

我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),在底层通讯中这些数据可能被拆成很多数据包来发送,但是一个数据包有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。而UDP是面向

Meditation 1万+

保姆级教程:用GlobleLand30数据+GTB3.3软件,一步步搞定MSPA景观格局分析

本文提供GlobleLand30数据结合GTB3.3软件进行MSPA景观格局分析的保姆级教程,涵盖数据预处理、软件操作、结果解读全流程,特别针对零基础用户常见问题提供解决方案,助力研究者高效完成景观生态学分析。

weixin_26757925的博客 450

【Linux】深入理解网络编程:应用层自定义协议、序列化、TCP粘包问题与Socket封装

深入理解网络编程:应用层协议、序列化、TCP粘包问题与Socket封装

可涵的博客 4208

《S32系列芯片——Boot & HSE详解》持续更新中...

专栏总目录,将详细介绍S32系列芯片的Boot功能,最终给出HSE基于IVT的Secure Boot方案!!!

车载系统攻城狮 4383

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Python实战之socket初版 Linux粘包问题

上一篇:Python实战之常见异常以及自定义异常 点击跳转 目录篇:python相关目录篇 点击跳转 下一篇:python实战之paramiko模块 点击跳转 目录 网络理想的7层和现实的4层: socket示例: socket参数 socket实战初版 Linux上的socket粘包问题 网络理想的7层和现实的4层: 1.理想的:应用 表示 会话 传输 网络 数据链路 物理层 ...

Burgess_zheng的博客 480

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【Linux之旅】Linux 应用层自定义协议与序列化:从粘包问题到网络计算器

本文将围绕"网络版计算器"这个具体需求,从协议设计思路出发,引出序列化/反序列化的必要性,用 jsoncpp 实现数据格式转换,再深入 TCP 流式数据的粘包问题并给出 Encode/Decode 方案,最后封装一个完整的通用 Socket 框架。读完本文,你将掌握从零设计一个应用层协议并写成一个完整网络服务的全流程。

2302_80243065的博客 2046

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Linux编程之socket:tcp流协议产生的粘包问题及解决方法

首先说明的是发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位

Mr_weng 1697

python socket send_python socket 连续send,出现粘包问题

使用网上socket代码实现ssh功能,如下:server.py#服务端Linux系统下:处理命令并返回import socketimport os#声明类型,生成socket链接对象server = socket.socket()#监听接收端口元组(本地,端口),绑定要监听的端口server.bind(('localhost',6969))#最大监听数,允许多少人在排队server.listen...

weixin_39645165的博客 361

socket网络编程(五)——粘包拆包问题

目录 1、出现粘包拆包的原因 2、粘包拆包的几种情况 3、处理粘包拆包的方法 3.1、服务端代码 3.2、客户端代码 3.3、公用的部分 今天和大家讲一下socket网络编程中粘包和拆包的问题。 1、出现粘包拆包的原因 假设一个这样的场景,客户端要利用send()函数发送字符“asd”到服务端,连续发送3次,但是服务端休眠10秒之后再去缓冲池中接收。那么请问10秒之后服务端从缓冲区接收到的信息是“asd”还是“asdasdasd”呢?如果大家有去做实验的话,可以知道服务端收到的是“asda

一点 1017

Linux网络 · 传输层TCP(四):粘包问题、连接异常与socket文件映射原理

linux网络 | TCP结束!!!

strive_mianyang的博客 1314

【linux】网络基础(十三)TCP协议,面向字节流,粘包问题,TCP异常情况,打通文件和socket的关系

一、面向字节流 二、粘包问题 三、TCP异常情况 四、打通文件和socket的关系

重铸自身根基的博客 1071

“深入浅出”系列之Linux篇:(13)socket编程实战+TCP粘包解决方案

从日常使用的APP,到背后支撑的各类服务器,网络通信无处不在,而socket作为实现网络通信的关键技术,更是开发者们必须掌握的核心知识。但在socket编程的道路上,TCP粘包问题宛如一只拦路虎,让无数开发者头疼不已。它隐蔽又棘手,导致数据传输混乱,程序运行异常。不过别担心,本文将为你全面剖析socket编程实战细节,并奉上超硬核的TCP粘包解决方案,一次性帮你解决所有难题,带你突破网络编程瓶颈,赶紧跟着文章开启这场技术之旅吧!!!加油!!!

weixin_65589140的博客 795

从Linux内核角度看TCP粘包

TCP粘包原理和解决方案。LInux内核如何收发TCP数据包。

weixin_28673511的博客 855

【Linux】TCP协议【下三】{面向字节流/粘包问题/TCP异常情况/文件和Socket}

【Linux】TCP协议【下三】{面向字节流/粘包问题/TCP异常情况/文件和Socket}

Ape's IT Blog 1391
上一篇: Linux 五种网络IO模式(阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO)
下一篇: Linux 一“文”搞定Shell编程
cpp_learners
博客等级 码龄7年 1526粉丝 274原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值