有TCP的基础,学习UDP是很快的。
与TCP程序设计相比较,UDP少了connect、listen以及accept。因为UDP协议是无连接的,不像TCP需要维护连接的状态。
建立通讯套解字过程和TCP协议含义相同,不过建立的套接字类型为数据报套接字(SOCK_DGRAM).
recvfrom()函数:
ssize_t recvfrom(int sock,void *buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);
参数释义:
from指向本地的数据结构struct sockaddr_in的指针,接收数据时发送方的地址信息放在这个结构中。
fromlen表示第四个参数所指定的内容的长度,可以使用sizeof(struct sockaddr_in)来获得。
返回值:出错返回-1。
sendto函数:
ssize_t recvfrom(int sock,const void *buf,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);
使用这两个函数的时候要分清楚其中的指针参数。
to指向本地的数据结构struct sockaddr_in的指针,发送数据时接收方的地址信息放在这个结构中。
来两个简单的小栗子:
//UDP_S
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define PORT_SERVER 8000
#define BUF_LEN 256
void static udpServer_echo(int s,struct sockaddr *client)
{
int n;
char buff[BUF_LEN];
socklen_t len;
while(1)
{
len = sizeof(*client);
n = recvfrom(s,buff,BUF_LEN,0,client,&len);
sendto(s,buff,n,0,client,len);
}
}
int main()
{
int s;
struct sockaddr_in addr_serv,addr_client;
s = socket(PF_INET,SOCK_DGRAM,0);
memset(&addr_serv,0,sizeof(addr_serv));
addr_serv.sin_family = PF_INET;
addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
addr_serv.sin_port = htons(PORT_SERVER);
bind(s,(struct sockaddr *)&addr_serv,sizeof(addr_serv));
udpServer_echo(s,(struct sockaddr *)&addr_client);
return 0;
}
//UDP_C
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#define PORT_SERVER 8000
#define BUF_LEN 256
void static udpServer_echo(int s,struct sockaddr *to)
{
struct sockaddr_in from;
char buff[BUF_LEN] = "UDP TEST";
socklen_t len = sizeof(*to);
sendto(s,buff,BUF_LEN,0,to,len);
n = recvfrom(s,buff,BUF_LEN,0,(struct sockaddr *)&from,&len);
printf("recved:%s\n",buff);
}
int main()
{
int s;
struct sockaddr_in addr_serv;
s = socket(PF_INET,SOCK_DGRAM,0);
memset(&addr_serv,0,sizeof(addr_serv));
addr_serv.sin_family = PF_INET;
addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
addr_serv.sin_port = htons(PORT_SERVER);
bind(s,(struct sockaddr *)&addr_serv,sizeof(addr_serv));
udpServer_echo(s,(struct sockaddr *)&addr_serv);
return 0;
}
UDP程序设计是常见的几个问题:
1、UDP报文丢失数据
这个是很正常的,追求速度自然要牺牲质量了。
但是上面那个例子来说,如果客户端发送的数据丢失,服务器会一直等待,直到客户端的合法数据到来;如果服务器发送的数据丢失,客户端则会一直阻塞等待服务器的合法数据到来。
在程序运行的过程中是不允许出现这种情况的,所以可以设置超时时间来判断是否有数据到来。
对于数据丢失的原因,并不能简单的找出来。
UDP报文丢失的对策还有:a、像三次握手一样,收到了说一声,但是未免太麻烦。
b、使用流水号,三发一至。
反正这两个办法都会拖慢速度。
2、UDP发送过程中的乱序
UDP协议的数据经过路由器的时候造成了数据顺序的混乱,这也是很正常的,谁让人家本来就不安全嘛。
对于UDP数据乱序的对策:
对于乱序的问题可以在数据段中加入数据报号的方法,这样在接收到数据的时候只需要对号码进行简单的排序就可以恢复秩序。
3、UDP缺乏流量控制
这个倒不是说会消耗很多的上网流量啊。
UDP没有TCP的滑动窗口的概念,在接收数据的缓冲区满之后,如果用户没有及时取出,则后来的数据会覆盖之前的数据而导致数据的丢失。
解决方法一般有两个,一个就是增大缓冲区,一个是采用数据单独处理,及时处理掉缓冲区中的数据。