参照上篇一起阅读更佳:网络协议之TCP/IP协议包
文章目录
UDP为什么不粘包
为什么TCP有粘包,UDP没有粘包?
TCP是面向流连接,数据的“粘包”问题:客户端发送的多个数据包使用了优化算法(Nagle算法),将多次间隔较小、数据量小的数据包,合并成一个大的数据包发送(把发送端的缓冲区填满一次性发送);接收端底层会把TCP段整理排序交给缓冲区,这样接收端应用程序从缓冲区取数据就只能得到整体数据而不知道怎么拆分。也称数据的无边界性,read()/recv()函数不知道数据包的开始或结束标志(实际上也没有任何开始或结束标志),只把它们当做连续的数据流来处理。
UDP协议是面向数据包协议,不会使用合并优化算法。接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息) ,这样对于接收端来说,就容易进行区分处理了。
所以每次发送UDP数据包都是一条消息,它有明显的边界保护,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据(不像TCP协议在recv/read可以指定大小,读取几次把缓冲区读完或者一次读完几次消息)。这样接收端很容易区分处理,传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。也就是说,发送端send了几次,接收端必须recv几次。接收端一次只能接收发送端发出的一个数据包,如果一次接受数据的大小小于发送端一次发送的数据大小,就会丢失一部分数据,即使丢失,接受端也不会分两次去接收。
// client.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <unistd.h>
#define LENGTH 24
int main()
{
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0)
{
perror("socket");
return 2;
}
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(