介绍UDP协议,并提供一个适用于客户端和服务器端的实例子程序。
关键词:Linux;UDP协议;TCP/IP协议;程序设计
UDP Protocol Program Based on Linux
LIU Chang, PENG Chuwu
(School of Electrical Engineering, Hunan University, Changsha 410082,China)
Key words: Linux; UDP protocol; TCP/IP protocol; programming
UDP(User Datagram Protocol)是一个面向数据报的简单传输层协议,它为应用程序发送和接收数据报。它是一种无连接协议,即它不像TCP那样需要建立服务器与客户端的连接才可以工作。
UDP是个很简单的协议,它建立在IP协议之上,利用IP数据报提供一种无连接的高效率的服务。它不保证数据的可靠,不进行重传,时延较短,很适用实时性要求高而不需要数据绝对可靠的应用。在网络通信质量较好的情况下,UDP体现出高效率,这适合于传送少量报文的应用,其可靠性由应用程序来保证,如:接收信号后向源方返回一个回响,超时重发、数据检验等功能需应用程序来实现。UDP不提供流控制,它按发送方的速率发送数据,而不管接收方的缓存区大小,这样容易造成溢出错误。由于UDP不存在客户端与服务器的连接,它可用同一个套接字向不同的目标发送数据报;同样,UDP可以是双向的,所以也可通过同一个套接字从几个不同的发送源接收数据报。?
UDP是个很简单的协议,它建立在IP协议之上,利用IP数据报提供一种无连接的高效率的服务。它不保证数据的可靠,不进行重传,时延较短,很适用实时性要求高而不需要数据绝对可靠的应用。在网络通信质量较好的情况下,UDP体现出高效率,这适合于传送少量报文的应用,其可靠性由应用程序来保证,如:接收信号后向源方返回一个回响,超时重发、数据检验等功能需应用程序来实现。UDP不提供流控制,它按发送方的速率发送数据,而不管接收方的缓存区大小,这样容易造成溢出错误。由于UDP不存在客户端与服务器的连接,它可用同一个套接字向不同的目标发送数据报;同样,UDP可以是双向的,所以也可通过同一个套接字从几个不同的发送源接收数据报。?
linux系统是通过套接字来进行网络编程的。下面介绍几个UDP数据报编程用到的基本套接字函数:
网络程序通过socket和其他几个函数调用,会返回一个用于通信的套接字描述符。Linux应用程序在执行任何形式的I/O的时候,程序是在读或者写一个文件描述符。因此,我们可以将创建的套接字描述符看成普通文件的描述符来操作,并可以通过向套接字描述符读写操作实现网络之间的数据交流,这就是linux设备无关性的好处。
(1)int socket(int domain,int type,int protocol)
函数socket()用于创建一个套接字描述符。参数domain说明网络程序所在的主机采用的通信协议(AFUNIX和AFINET等)。AFUNIX只能用于单一的UNIX系统进程间通信,而AFINET是针对Internet的,因而可以允许在远程主机之间通信。一般把它赋为AFINET。参数type指明创建的套接字类型,对应的参数值为SOCKDGRAM:数据报套接字,表明用的是UDP协议,提供无序的、不可靠的、无连接的通信。参数protocol,由于指定了type,所以这里一般只要用0来代替即可。?
socket()得到套接字描述符,为网络通信做基本的准备工作,调用成功时将返回文件描述符,失败时将返回-1,通过查看error文件可以知道有关出错的详细信息。
(2)int bind(int sockfd,struct sockaddr*myaddr,int addrlen)
得到套接字描述符后,将套接口和机器上的一定的端口号绑定在一起。sockfd是调用socket函数返回的文件描述符;addrlen是sockaddr结构的长度:myaddr是一个指向sockaddr结构的指针,它保存着本地套接字的地址(即端口和IP地址)信息。不过由于系统兼容性的问题,一般不使用这个结构,而使用另外一个结构(struct sockaddrin)来代替。bind()函数在成功被调用时返回0,如果出错返回-1。
结构类型struct sockaddrin保存着套接口的地址信息,定义如下:
struct sockaddrin{short int sinfamily;/*地址族*/
unsigned short int sinport;/*端口号*/
struct inaddr sinaddr;/*IP地址*/
unsigned char sinzero[8];}/*填充0以保持与struct sockaddr同样大小*/
这个数据结构使得使用其中的各个元素更为方便,sinzero(它用来将sockaddrin结构填充到与sockaddr结构同样的长度)应该用bzero()或memset()函数将其置为0。另外,一个指向sockaddrin数据结构的指针可以强行转换为一个指向数据结构sockaddr的指针,反之亦然。
(3)int close(int sockfd)
函数close用来关闭一个套接字描述符,参数sockfd为指定要关闭的套接字描述符,函数close()在成功执行时返回0,否则返回-1。
以上三个函数中,前两个要包含头文件#include〈sys/types.h〉和#include〈sys/socket.h〉,后一个包含#include〈unistd.h〉。再介绍两个用于UDP协议的接收和发送函数,包含头文件#include〈sys/socket.h〉:
int sendto(int sockfd,const void*msg,int len,unsigned int flags,struct
3利用UDP数据报编程
UDP协议有自己的通信模型。首先由UDP服务器调用函数socket创建一个数据报类型的套接字,然后服务器调用bind函数绑定在一个默认的UDP端口上,接着调用函数recvfrom在指定的端口上等待UDP客户机数据报的到来。而UDP客户机首先也调用函数socket创建一个数据报类型的套接字,然后调用函数sendto向UDP服务器发送数据报。需要注意的是,UDP客户机应用程序通常不需要调用函数bind将套接字绑定到某个固定的端口,linux操作系统会为进程分配一个空闲的端口号。UDP服务器进程接收到客户机发来的数据报后,将从recvfrom函数中返回,对数据报进行相关处理后,再调用sendto函数将结果返回到客户端。
通常,客户端的设计和实现比服务器端的要容易一些,典型的UDP服务器与操作系统进行交互作用,而且大多数需要同时处理多个客户。一个UDP客户机启动后直接与单个服务器通信,然后就结束了。而对于服务器来说,它启动后处于休眠状态,等待客户请求的到来。当客户数据报到达时,服务器苏醒过来,数据报中可能包含来自客户的某种形式的请求消息。一个基本的UDP通信过程如图1所示。
网络程序通过socket和其他几个函数调用,会返回一个用于通信的套接字描述符。Linux应用程序在执行任何形式的I/O的时候,程序是在读或者写一个文件描述符。因此,我们可以将创建的套接字描述符看成普通文件的描述符来操作,并可以通过向套接字描述符读写操作实现网络之间的数据交流,这就是linux设备无关性的好处。
(1)int socket(int domain,int type,int protocol)
函数socket()用于创建一个套接字描述符。参数domain说明网络程序所在的主机采用的通信协议(AFUNIX和AFINET等)。AFUNIX只能用于单一的UNIX系统进程间通信,而AFINET是针对Internet的,因而可以允许在远程主机之间通信。一般把它赋为AFINET。参数type指明创建的套接字类型,对应的参数值为SOCKDGRAM:数据报套接字,表明用的是UDP协议,提供无序的、不可靠的、无连接的通信。参数protocol,由于指定了type,所以这里一般只要用0来代替即可。?
socket()得到套接字描述符,为网络通信做基本的准备工作,调用成功时将返回文件描述符,失败时将返回-1,通过查看error文件可以知道有关出错的详细信息。
(2)int bind(int sockfd,struct sockaddr*myaddr,int addrlen)
得到套接字描述符后,将套接口和机器上的一定的端口号绑定在一起。sockfd是调用socket函数返回的文件描述符;addrlen是sockaddr结构的长度:myaddr是一个指向sockaddr结构的指针,它保存着本地套接字的地址(即端口和IP地址)信息。不过由于系统兼容性的问题,一般不使用这个结构,而使用另外一个结构(struct sockaddrin)来代替。bind()函数在成功被调用时返回0,如果出错返回-1。
结构类型struct sockaddrin保存着套接口的地址信息,定义如下:
struct sockaddrin{short int sinfamily;/*地址族*/
unsigned short int sinport;/*端口号*/
struct inaddr sinaddr;/*IP地址*/
unsigned char sinzero[8];}/*填充0以保持与struct sockaddr同样大小*/
这个数据结构使得使用其中的各个元素更为方便,sinzero(它用来将sockaddrin结构填充到与sockaddr结构同样的长度)应该用bzero()或memset()函数将其置为0。另外,一个指向sockaddrin数据结构的指针可以强行转换为一个指向数据结构sockaddr的指针,反之亦然。
(3)int close(int sockfd)
函数close用来关闭一个套接字描述符,参数sockfd为指定要关闭的套接字描述符,函数close()在成功执行时返回0,否则返回-1。
以上三个函数中,前两个要包含头文件#include〈sys/types.h〉和#include〈sys/socket.h〉,后一个包含#include〈unistd.h〉。再介绍两个用于UDP协议的接收和发送函数,包含头文件#include〈sys/socket.h〉:
int sendto(int sockfd,const void*msg,int len,unsigned int flags,struct
3利用UDP数据报编程
UDP协议有自己的通信模型。首先由UDP服务器调用函数socket创建一个数据报类型的套接字,然后服务器调用bind函数绑定在一个默认的UDP端口上,接着调用函数recvfrom在指定的端口上等待UDP客户机数据报的到来。而UDP客户机首先也调用函数socket创建一个数据报类型的套接字,然后调用函数sendto向UDP服务器发送数据报。需要注意的是,UDP客户机应用程序通常不需要调用函数bind将套接字绑定到某个固定的端口,linux操作系统会为进程分配一个空闲的端口号。UDP服务器进程接收到客户机发来的数据报后,将从recvfrom函数中返回,对数据报进行相关处理后,再调用sendto函数将结果返回到客户端。
通常,客户端的设计和实现比服务器端的要容易一些,典型的UDP服务器与操作系统进行交互作用,而且大多数需要同时处理多个客户。一个UDP客户机启动后直接与单个服务器通信,然后就结束了。而对于服务器来说,它启动后处于休眠状态,等待客户请求的到来。当客户数据报到达时,服务器苏醒过来,数据报中可能包含来自客户的某种形式的请求消息。一个基本的UDP通信过程如图1所示。
4结束语
本文介绍了UDP套接字的通信机制。UDP是一个面向数据报的简单传输层协议。建议网络环境好,要求资源少的采用UDP,如很多实时系统一般采用UDP协议进行数据的网络传输。如果需要对接收的UDP数据报进行排序和流量控制,并保证数据报的可靠性, 则必须在应用程序中增加一些控制机制。
评论
查看更多