由于在项目中用TCP比较多,也发现TCP在频繁数据传输的应用中存在拥塞的缺点。考虑到UDP在这方面存在优点,抽出时间专门测试一下UDP的编程使用和TCP的区别,以使下次设计应用层协议时正确选择传输层协议
1、 UDP每次操作都是针对一个数据包,而TCP操作数据流
发送方调用3次sendto 发送大小都为64B 的数据包:
数据包A:a_HelloWorld。
数据包B:b_HelloWorld。
数据包C:c_HelloWorld。
情况一
接收方调用2次recvfrom
接收长度参数为4时:
第1次,接收到数据包A:a_He
第2次,接收到数据包B:b_He
情况二
接收方调用3次recvfrom
接收长度参数为1024时
第1次,接收到数据包A:a_HelloWorld。
第2次,接收到数据包B:b_HelloWorld。
第3次,接收到数据包C:c_HelloWorld。
上述两种情况与TCP有很大区别,
第一种情况,若是TCP调用2次recv,接收大小为4,
将会接收到“a_HelloW”,剩下的数据将留着socket的接收缓存中
而在UDP中,仅数据包C留着socket接收缓存中
第二种情况,若是TCP调用3次recv,接收大小为1024,
仅第1次即会把3个数据包接收完,第2、3次调用都不会接收到数据(阻塞或接收0个)。
2、 发送速率 大于 接收速率
发送端每1s调用sendto发送数据包A到接收端,而接收端每3秒调用recvfrom接收数据包A。此时当接收缓存满时,接收端将出现掉包的情况。但发送端和接收端都是不知道丢包发生了的。
3、 UDP协议中有校验和(2B)
用于增加传输的可靠性,校验和不对将丢包(并不重传)
//接收端源文件
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<netinet/in.h>
#include<sys/socket.h>
int main(void)
{
int rsck = socket(AF_INET, SOCK_DGRAM, 0);
if(rsck < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in r_addr, s_addr;
int r_len = sizeof(r_addr);
int s_len = sizeof(s_addr);
bzero(&r_addr, r_len);
r_addr.sin_family = AF_INET;
r_addr.sin_port = htons(5678);
r_addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("192.168.1.124");
int sinsize = 1;
setsockopt(rsck, SOL_SOCKET, SO_REUSEADDR, &sinsize, sizeof(int));
int ret = bind(rsck, (struct sockaddr*)&r_addr, r_len);
if(ret < 0)
{
// fprintf(stdout, "bind receive socket fail : %s\n", errorn);
perror("bind");
}
char rbuf[1024];
while(1)
{
usleep(10000);
ret = recvfrom(rsck, rbuf, 5, 0, (struct sockaddr*)&s_addr, &s_len);
printf("%d:%s\n", ret,rbuf);
}
char sbuf[64] = "nice!!";
sendto(rsck, sbuf, sizeof(sbuf), 0, (struct sockaddr*)&s_addr, s_len);
close(rsck);
return 0;
}
//发送端源文件
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
int main(void)
{
int ssck = socket(AF_INET, SOCK_DGRAM, 0);
if(ssck < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in dest_addr, src_addr;
int dest_len = sizeof(dest_addr);
int src_len = sizeof(src_addr);
bzero(&dest_addr, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(5678);
dest_addr.sin_addr.s_addr = inet_addr("192.168.188.229");
char sbuf[64] = "Hello, i am send";
int i=0;
char tmp[16];
while(1)
{
sprintf(tmp, "[%d]", i++);
strncpy(sbuf, "Hello, i am send", 64);
strncat(sbuf, tmp, 64);
//sleep(1);
int slen = sendto(ssck, sbuf, sizeof(sbuf), 0, \
(struct sockaddr*)&dest_addr,dest_len);
printf("slen = %d , chars : %s\n", slen, sbuf);
}
recvfrom(ssck, sbuf, sizeof(sbuf), 0, (struct sockaddr*)&src_addr, &src_len);
printf("%s\n", sbuf);
close(ssck);
return 0;
}