在使用TCP编写的应用程序和使用UDP编写的应用程序之间存在一些本质的差异,其原因在于这两个传输层之间的差异:UDP是无连接不可靠的数据报协议,非常不同于TCP提供的面向连接的可靠字节流。然而相比TCP,有些场合确实更适合使用UDP,使用UDP编写的一些常见的应用程序有:DNS(域名系统)、NFS(网络文件系统)和SNMP(简单网络管理协议)。
上图给出了典型的UDP客户端/服务器程序的函数调用。客户不与服务器建立连键,而是只管使用sendto函数给服务器发送数据包,其中必须指定目的地(即服务器的地址作为参数)。类似的,服务器不接受来自客户的连接,而是只管调用recvfrom函数,等待来自某个客户的数据到达。recvfrom将与所连接的数据报一道返回客户的协议地址,因此服务器可以把响应发送给正确的客户。
recvfrom函数和sendto函数:
函数原型:
ssize_t recvfrom(int sockfd,void * buff,size_t nbytes,int flags,struct sockaddr * from,sock_len addrlen);
ssize_t sendto(int sockfd,const void *buff,size_t nbytes,int flags,const struct sockaddr *to,socklen_t addrlen)
前三个参数sockfd、buff和nbytes等同于read和write函数的三个参数:描述符、指向读入或写入缓冲区的指针和读写字节数。
sendto的to参数指向一个含有数据报接收者的协议地址(例如IP地址及端口号)的套接字地址结构,其大小由addrlen参数指定。recvfrom的from参数指向一个将由该函数返回时填写的数据报发送者的协议地址的套接字地址结构,而在该套接字地址结构中填写的字节数则放在addrlen参数中返回给调用者。注意,sendto的最后一个参数是一个整数值,而recvfrom的最后一个参数是一个指向整数值的指针。
下面给出一个简单的UDP例子:
服务器:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
int main()
{
int sockSer = socket(AF_INET, SOCK_DGRAM, 0);
if(sockSer == -1)
perror("socket");
int yes = 1;
setsockopt(sockSer,SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(int));
struct sockaddr_in addrSer;
addrSer.sin_family = AF_INET;
addrSer.sin_port = htons(5050);
addrSer.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t addrlen = sizeof(struct sockaddr);
int res = bind(sockSer,(struct sockaddr*)&addrSer, addrlen);
if(res == -1)
perror("bind");
char sendbuf[256];
char recvbuf[256];
struct sockaddr_in addrCli;
while(1)
{
recvfrom(sockSer,recvbuf,256,0,(struct sockaddr*)&addrCli, &addrlen);
printf("Cli:>%s\n",recvbuf);
printf("Ser:>");
scanf("%s",sendbuf);
if(strncmp(sendbuf,"quit",4) == 0)
break;
sendto(sockSer,sendbuf,strlen(sendbuf)+1,0,(struct sockaddr*)&addrCli, addrlen);
}
return 0;
}
<span style="font-size:18px;">客户端:</span>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
int main()
{
int sockCli = socket(AF_INET, SOCK_DGRAM, 0);
if(sockCli == -1)
perror("socket");
struct sockaddr_in addrSer;
addrSer.sin_family = AF_INET;
addrSer.sin_port = htons(5050);
addrSer.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t addrlen = sizeof(struct sockaddr);
char sendbuf[256];
char recvbuf[256];
struct sockaddr_in addrCli;
while(1)
{
printf("Cli:>");
scanf("%s",sendbuf);
if(strncmp(sendbuf,"quit",4) == 0)
{
break;
}
sendto(sockCli,sendbuf,strlen(sendbuf)+1,0,(struct sockaddr*)&addrSer, addrlen);
recvfrom(sockCli,recvbuf,256,0,(struct sockaddr*)&addrSer, &addrlen);
printf("Ser:>%s\n",recvbuf);
}
return 0;
}
其执行结果:
该程序实现客户端与服务器一对一的通信。。。