【cdk的使用】CC++ TCP 粘包 拆包 及解决方案

【cdk的使用】CC++ TCP 粘包 拆包 及解决方案,第1张

Github地址: https://github.com/wujin1989/cdk

TCP因为没有边界,所以会有粘包的问题。


看下面代码:

server.c

#include "cdk.h"
#include 

#define BUFSIZE    20

void routine(sock_t s) {
	
	int  ret;
	char rbuf[BUFSIZE];

	while (true) {
		memset(rbuf, 0, BUFSIZE);
		ret = recv(s, rbuf, BUFSIZE, MSG_WAITALL);
		if (ret <= 0) {
			abort();
		}
	}
}

int main(void) {
	
	sock_t s;

	s = cdk_tcp_listen("0.0.0.0", "9999");
	cdk_tcp_netpoller(s, routine, false);
	return 0;
}

client.c

#include "cdk.h"

#define BUFSIZE     2

int main(void) {

	int     ret;
	sock_t  c;
	char    sbuf[BUFSIZE];

	c = cdk_tcp_dial("192.168.0.105", "9999");

	for (int i = 0; i < 10; i++) {
	
		cdk_sprintf(sbuf, BUFSIZE, "%d", i);
		ret = send(c, sbuf, BUFSIZE, 0);
		if (ret <= 0) {
			abort();
		}
	}
	while (true);
	return 0;
}

在client端用wireshark抓包如下:

client.c代码里明明每次发送2个字节数据,发送10次,但从上面抓包来看,tcp合并了client发送的数据包,这个就是TCP发送数据时的粘包。


怎么避免发送时的TCP粘包呢?修改client.c代码,添加TCP_NODELAY选项如下:

#include "cdk.h"

#define BUFSIZE     2

int main(void) {

	int     ret;
	sock_t  c;
	char    sbuf[BUFSIZE];

	c = cdk_tcp_dial("192.168.0.105", "9999");

	for (int i = 0; i < 10; i++) {
	
		cdk_sprintf(sbuf, BUFSIZE, "%d", i);
		cdk_tcp_nodelay(c, true);
		ret = send(c, sbuf, BUFSIZE, 0);
		if (ret <= 0) {
			abort();
		}
	}
	while (true);
	return 0;
}

在client再次抓包,如下:

看起来,NODELAY选项可以解决发送数据的粘包现象。


但是接收数据还是会有可能导致粘包,因为接收端根本不知道每次读多少数据。


接下来看下TCP拆包,TCP的拆包原因是发送数据大于MSS导致的,server还用之前代码,client看下面代码:

client.c

#include "cdk.h"
#include 

#define BUFSIZE     537

int main(void) {

	int     ret;
	sock_t  c;
	char    sbuf[BUFSIZE];

	memset(sbuf, 1, BUFSIZE);
	c = cdk_tcp_dial("192.168.0.105", "9999");

	cdk_tcp_nodelay(c, true);
	ret = send(c, sbuf, BUFSIZE, 0);
	if (ret <= 0) {
		abort();
	}
	
	while (true);
	return 0;
}

上面代码,发送一个537个字节的数据,但是因为cdk内部设置了MSS为536。


所以当发送一个大于MSS(536)的数据时,TCP会进行拆包,用wireshark抓包,如下图:

可以看到,发送数据被分成两个包发送,一个536字节,一个1字节。



这个就是TCP的拆包现象。


如何解决TCP的粘包和拆包呢?

  • 粘包解决方案:
    1. 发送和接收定长数据包。



    2. 发送消息带有分隔符。



    3. 发送消息带头信息,头信息里包含数据的长度。


    (cdk采用这种方案)

  • 拆包解决方案:
    发送数据不要超过MSS。


具体实现,可以参考cdk。


怎么样?tcp粘包,拆包是不是很容易。


快来尝试下吧。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/580051.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-11
下一篇 2022-04-11

发表评论

登录后才能评论

评论列表(0条)

保存