网络协议
UDP客户端的默认函数调用顺序
UDP连接的特点
- UDP中的服务器端和客户端没有连接
- UDP服务器端和客户端均只需1个套接字
基于UDP的数据I/O函数
发送函数
Linux
填写地址并传输数据时调用的UDP相关函数:
#include <sys/socket.h>
ssize_t sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen);
//成功时返回传输的字节数,失败时返回-1。
- sock:用于传输数据的UDP套接字文件描述符。
- buff:保存待传输数据的缓冲地址值。
- nbytes:待传输的数据长度,以字节为单位。
- flags:可选项参数,若没有则传递0。
- to:存有目标地址信息的sockaddr结构体变量的地址值。
- addrlen:传递给参数to的地址值结构体变量长度。
Windows
#include <winsock2.h>
int sendto(SOCKET s,const char* buff,int len,int flags,const struct sockaddr *to,int tolen);
//成功时返回传输的字节数,失败时返回SOCKET_ERROR。
接收函数
Linux
#include <sys/socket.h>
ssize_t recvfrom(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *from,socklen_t addrlen);
//成功时返回传输的字节数,失败时返回-1。
- sock:用于接收数据的UDP套接字文件描述符。
- buff:保存待接收数据的缓冲地址值。
- nbytes:待接收的数据长度,以字节为单位。
- flags:可选项参数,若没有则传递0。
- from:存有发送地址信息的sockaddr结构体变量的地址值。
- addrlen:传递给参数from的地址值结构体变量长度。
注:UDP不同于TCP,不存在请求连接和受理过程,因此在某种意义上无法明确区分服务端和客户端,只是因提供服务而称为服务器端。
Windows
#include <winsock2.h>
int recvfrom(SOCKET s,char* buff,int len,int flags,struct sockaddr *from,int* fromlen);
//成功时返回传输的字节数,失败时返回SOCKET_ERROR。
UDP客户端套接字的地址分配
UDP调用sendto函数自动分配IP和端口号(IP用主机IP,端口号选未分配任意端口号),因此UDP客户端中通常无须额外的地址分配过程。
已连接UDP套接字与未连接UDP套接字
通过sendto函数传输数据的过程大致可分为以下3个阶段。
- 第1阶段:向UDP套接字注册目标IP和端口号。
- 第2阶段:传输数据。
- 第3阶段:删除UDP套接字中注册的目标地址信息。
每次调用sendto函数时重复上述过程,每次都变更目标地址,因此可以重复利用统一UDP套接字向不同目标传输数据。这种未注册目标地址信息的套接字称为未连接套接字,反之注册了目标地址的套接字称为连接套接字。
UDP默认属于未连接套接字。但是要与同一主机进行长时间通信时,将UDP套接字变成已连接套接字会提高效率。
创建已连接UDP套接字
创建已连接UDP套接字的过程只需针对UDP套接字调用connect函数。
sock = socket(PF_INET,SOCK_DGRAM,0);
memset(&adr,0,sizeof(adr));
adr.sin_family = AF_INET;
adr.sin_addr.s_adr = ....
adr.sin_port = ....
connect(sock,(struct sockaddr *)&adr,sizeof(adr));