UDP是无连接不可靠的数据报协议,不需要建立连接。
/*
fd,buf,n分别是描述符,缓冲区,读写字节数。
flag:暂时为0
__addr:接收者数据报协议地址结构,告诉往哪里发,类似connect后面参数。
__addr_len:结构地址长度
*/
ssize_t sendto (int __fd, const void *__buf, size_t __n,
int __flags, __CONST_SOCKADDR_ARG __addr,
socklen_t __addr_len);
/*
fd,buf,n分别是描述符,缓冲区,读写字节数。
flag:暂时为0
__addr:返回发送者协议地址结构,告诉哪个连接了我,类似accept后面参数。
__addr_len:值-结果参数。
addr和len都可以为NULL,表示不关心发送者协议地址。
*/
ssize_t recvfrom (int __fd, void *__restrict __buf, size_t __n,
int __flags, __SOCKADDR_ARG __addr,
socklen_t *__restrict __addr_len);
client:
void client_echo(FILE *fp , int sockfd , SA *servaddr , socklen_t servlen)
{
int n;
char sendline[MAXLINE] , recvline[MAXLINE + 1];
while(fgets(sendline , MAXLINE , fp) != NULL){
Sendto(sockfd , sendline , strlen(sendline) , 0 , servaddr , servlen);
n = Recvfrom(sockfd , recvline , MAXLINE , 0 , NULL , NULL);//接收服务器数据,并不关心服务器地址
recvline[n] = 0;
fputs(recvline , stdout);
}
}
int main(int argc, char **argv)//客户程序
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: a.out " );
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);//创建UDP套接字
bzero(&servaddr, sizeof(servaddr));//地址结构清0
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(4099);//服务器端口
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);//服务器IP地址
client_echo(stdin , sockfd , (SA *)&servaddr , sizeof(servaddr));//处理
exit(0);
}
server:
UDP层含有一个FIFO数据报缓冲队列,进程revfrom时,缓冲区以将数据报FIFO方式返回给进程,这样,进程就可以以此从缓冲区读好缓冲的数据。所以UDP服务器是迭代服务器,内核为你做了好多事情,排好队等着你调用系统函数读取为你准备好的数据。
void server_echo(int sockfd , SA *cliaddr , socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];//缓冲区
while(1){
len = clilen;//记录长度
n = Recvfrom(sockfd , mesg , MAXLINE , 0 , cliaddr , &len);//接受数据,返回填写了cliaddr结构
Sendto(sockfd , mesg , n , 0 , cliaddr , len);//发送出去
}
}
int main(int argc, char **argv)//UDP服务器程序
{
int sockfd;//服务器fd
struct sockaddr_in servaddr , cliaddr;
/*×××××××××××××××××××服务器端套路开始××××××××××××××××××××*/
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);//创建UDP套接字创建
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;//服务器IP地址为网卡IP地址
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(4099);
Bind(sockfd, (SA *) &servaddr, sizeof(servaddr));//绑定本机IP地址和端口,设置结构体成员而已
/********************UDP服务器端套路结束*********************/
server_echo(sockfd , (SA *)&cliaddr , sizeof(cliaddr));//强制转换是因为历史原因。
exit(0);
}
1、数据报丢失:UDP是不可靠的,数据报丢失之后,客户或者服务器都将阻塞在recvfrom函数,可以暂时给recvfrom设置超时处理。但是假如是银行转账,那么这种简单的处理显然不可靠。
2、验证接收到的响应: