第六章 基于UDP的服务器端/客户端

来源:互联网 发布:学编程用不用面面俱到 编辑:程序博客网 时间:2024/06/08 08:38

《TCP/IP网络编程》 尹圣雨

P101~P114


1 理解UDP

UDP提供的是不可靠的数据传输服务。

UDP结构上比TCP简洁,不会发送类似ACK的应答消息,不会像SEQ那样给数据包分配序号。因此UDP性能有时会比TCP更高。编程实现UDP也比TCP简单。另外,UDP的可靠性比不上TCP,但也不会像想象中那么频繁地发生数据损毁。


UDP作用?

为提供可靠的数据传输服务,TCP在不可靠的IP层进行流控制,而UDP就缺少这种流控制机制。


UDP和TCP的差异只在于流控制机制。TCP的生命在于流控制。

TCP的速度无法超过UDP,但是在收发某些类型的数据时有可能接近UDP。例如每次交换的数据量越大,TCP的传输速率就越接近UDP的传输速率。


UDP内部工作原理 P102

IP作用是让离开主机B的UDP数据包准确传递给主机A。但把UDP包最终交给主机A的某一UDP套接字的过程是由UDP完成的。

UDP最重要的作用就是根据端口号将传到主机的数据包交付给最终的UDP套接字


UDP的高效使用

UDP并非每次都快于TCP,TCP比UDP慢的原因通常有以下两点:

1)收发数据前后进行的连接设置及清除过程。

2)收发数据过程中为保证可靠性而添加的流控制。

如果收发的数据量小但需要频繁连接时,UDP比TCP更高效。


2 实现基于UDP的服务器端/客户端

(1)UDP中的服务器端和客户端没有连接

不必调用TCP连接过程中调用的listen函数和accept函数,UDP只有创建套接字的过程和数据交换过程。


(2)UDP服务器端和客户端均只需1个套接字

TCP中,套接字间应该是一对一高效。若要向10个客户端提供服务,则除了守门的服务器套接字外,还需要10个服务器端套接字。但是在UDP中,不管是服务器端还是客户端都只需要1个套接字。只需要1个套接字就能和多台主机通信。


(3)基于UDP的数据I/O函数

创建好TCP套接字后,传输数据时无需再添加地址信息。因为TCP套接字将保持与对方套接字的连接。即TCP套接字知道目标地址的信息。 而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的地址值结构体变量长度


接收UDP数据的函数

#include<sys/socket.h>ssize_t recvfrom(int sock, void *buff,ssize_t nbytes,int flags, struct sockaddr *from,socklen_t * addrlen)
成功时返回接收的字节数,失败时返回-1.

sock 用于接收数据的UDP套接字文件描述符

buff 保存接收数据的缓冲地址值

nbytes 可接收的最大字节数,无法超过参数buff所指的缓冲大小

flags 可选项参数,若没有则传递0

from 存有发送端地址信息的sockaddr结构体变量的地址值

addrlen 保存参数from的结构体变量长度的变量地址值


(4)基于UDP的回声服务器端/客户端 P105~P108


(5)UDP客户端套接字的地址分配

UDP客户端缺少把IP和端口分配给套接字的过程。TCP客户端调用connect函数自动完成此过程,而UDP中连能承担相同功能的函数调用语句都没有

UDP程序中,调用sento函数传输数据前应完成对套接字的地址分配工作,因此调用bind函数。bind函数不区分TCP或者UDP,也就是说,在UDP程序中同样可以调用。另外如果调用sendto函数时发现尚未分配地址信息,则在首次调用sendto函数时给相应套接字自动分配IP和端口。而且此时分配的地址一直保留到程序结束为止,因此也可用来与其他UDP套接字进行数据交换IP用主机IP,端口号选尚未使用的任意端口号

调用sendto函数时自动分配IP和端口号,UDP客户端中无需额外的地址分配过程



3 UDP的数据传输特性和调用connect函数

(1)存在数据边界的UDP套接字

TCP传输的数据不存在数据边界,表示“数据传输过程中调用I/O函数的次数不具有任何意义”。

UDP数据传输中存在数据边界,传输中调用I/O函数的次数非常重要。因此,输入函数的调用次数应和输出函数的调用次数完全一致,这样才能保证接收全部已发送数据。

  P109~P111简单示例。


UDP数据报:UDP套接字传输的数据包又称为数据报,实际上数据报也属于数据包的一种。只是与TCP包不同,其本身可以成为1个完整数据。这与UDP的数据传输特性有关,UDP中存在数据边界,1个数据包即可成为有关完整数据,因此称为数据报


TCP套接字中需注册传输数据的目标IP和端口号,而UDP中则无需注册。因此通过sendto函数传输数据的过程大致分为以下3个阶段

第一阶段:向UDP套接字注册目标IP和端口号

第二阶段:传输数据

第三阶段:删除UDP套接字中注册的目标地址信息

每次调用sendto函数时重复上述过程,每次都变更目标地址,因此可以重复利用同一UDP套接字向不同目标传输数据。这种未注册目标地址信息的套接字称为未连接套接字。UDP默认为未连接套接字。


创建已连接UDP套接字只需针对UDP套接字调用connect函数

这并不意外这要与对方UDP套接字连接,这只是向UDP套接字注册目标IP和端口信息。