前面我们讲了流套接字的发送接收,这一章我们来学习下在数据报套接字上发送和接收数据。
由于底层协议的不同,数据报套接字是UDP协议,UDP是无连接、不可靠的数据报协议。
如图:
在这种通信方式中,客户不与服务建立连接,它只是通过sendto向服务程序发送数据报,同时服务程序也不接收来自客户的连接,它只是调用recvfrom函数,这个函数等待来自某个客户的数据,并随接收到的数据报一起返回客户的地址,服务程序由此可以回应客户。使用数据报套接字,可以将数据集中为一个包,为每个包单独的指定目的地址,并且每个包独立的进行通信。
接下来我们来看下sendto和recvfrom函数的定义:
ssize_t sendto (int __fd, const void *__buf, size_t __n, int __flags, __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
ssize_t recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
这两个函数的前三个参数和read和write函数的参数相同(有不清楚的可以看我前面第五十一章),对于recvfrom,如果所接收的包的实际长度大于参数n,则得到该包的前n个字节,而数据包的剩余部分被丢弃,无法在读到此数据包的剩余部分,因此,当采用数据报协议时,必须总是知道数据包的预期长度。
参数flags和send和recv函数中的flags相同(可以看我第五十二章)。
recvfrom的参数addr和addr_len,在函数返回时,他们给出套接字地址结构告诉是谁发送的数据报。如果不想知道这个信息,可以指定addr和addr_len为空指针。
sendto的最后两个参数类似于connect,当发送数据报时,要在此套接字地址结构中填入协议地址以指明数据报发送给谁。
注意:sendto的最后一个参数是整型值,recvfrom的最后一个参数是指向整数的指针。
我们来看下程序:
客户端:
服务端: