Chapter 4 Using UDP Sockets
Sending and Receiving with UDP Sockets
ssize_t sendto(int socket, const void* msg, size_t msgLength, int flags,
const struct sockaddr* destAddr, socklen_t addrLen);
ssize_t recvfrom(int socket, void* msg, size_t msgLength, int flags,
struct sockaddr* srcAddr, socklen_t* addrLen);
sendto()的前四个参数与send()的完全相同,只是在后面添加了目标地址及其长度大小,
因为UDP没有connect()操作,所以要在发送时指明目标地址
recvfrom()的前四个参数与recv()的相同,并在之后添加了两个参数用于接受消息的来源地址。
注意recvfrom()中的addrLen参数是一个输入/输出参数,在输入时表示srcAddr地址缓冲区的大小,
在输出时表示实际复制到地址缓冲区中的地址的大小
TCP与UDP的一个区别就是UDP会保留边界信息,这就意味着一次recvfrom()调用最多只会接受来自
一个sendto()发送的数据。而不同次调用的recvfrom()接受的数据永远不可能来自同一次sendto()发送
(除非使用MSG_PEEK标识)。
而TCP中一个recv()可能接受的是多个send()发送的数据,或多个recv()接受来自一个send()发送的数据。
当send()返回时,调用者只知道数据被放入的发送缓冲区,数据可能会也可能不会实际传输到目标地址。
由于UDP没有错误处理机制,所以不需要缓冲区对发送失败数据进行重传,这就是说当sendto()返回时,
数据已经传输或正在传输到目标地址
在数据被发送到目标服务器但是在recv()或recvfrom()被调用前,数据被保存在一个FIFO的接受缓冲区队列。
所有接受到的数据在这个缓冲区中是一个连续的序列。由于recvfrom()要返回数据的源地址,所以UDP发送的消息
需要保留边界信息。如果调用recvfrom()时使用的接受数据缓冲区大小n小于FIFO队列中第一数据块的大小,则
recvfrom()只会接受到该块数据的前n个字节,而剩余的字节则会被自动舍弃且调用着无法感知。
所以在使用recvfrom()时要使用比接受数据大的缓冲区才不会导致数据丢失。
UDP中recvfrom()可以返回的最大字节数为65507 bytes
如果在recvfrom()调用时使用MSG_PEEK标识,则在调用后数据必然会保存在FIFO接受缓冲区队列中,
这样就可以多次重复获取同一sendto()发送的数据。如果在发送数据的头部写入数据块的大小信息,
则可以使用这用方法提前探测数据块的真实大小,然后使用合适的缓冲区大小接受数据,从而保证没有数据丢失
Connecting a UDP Socket
也可使用connect()函数连接UDP Socket然后使用send()与recv()通信
