Unix网络编程 卷1 第8章: 基本UDP套接字编程(概述及recvfrom/sendto函数)

时间:2021-06-22 10:59:37

一、概述

使用UDP和TCP编写程序时,我们要了解他们的差异。原因在于这两个传输层之间的差别:TCP是面向连接可靠字节流传输协议,UDP是无连接不可靠数据报传输协议。不同的协议有不同的使用场合,使用UDP编写的一些常见的应用程序有:DNS(域名系统),NFS(网络文件系统)和SNMP(简单网络管理协议)。

下图是典型的UDP客户/服务器程序的函数调用。其中UDP不建立连接,只管使用sendto函数向服务器发送数据报(需要指定目的服务器的地址作为参数),服务器也不接受来自客户端的连接,而是只管调用recvfrom函数,等待客户端数据的到达

Unix网络编程 卷1 第8章: 基本UDP套接字编程(概述及recvfrom/sendto函数)

基于UDP套接字编程函数调用的顺序为:

1. 服务器端:socket--->bind--->recvfrom--->sendto--->close

2. 客户端:socket--->sendto--->recvfrom--->close

请注意:连接的UDP(这里连接的UDP和TCP不一样,这里没有三路握手过程)套接字接口函数在客户端调用的一般顺序为:socket--->connect--->write--->read--->close;服务器端调用顺序为:socket--->bind--->read--->write--->close。connect版本的UDP套接字函数稍后总结,狠戳这里,下面介绍的函数为UDP常规套接字函数。

二、recvfrom函数和sendto函数

函数原型如下,均在头文件socket.h中声明:

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, intflags, struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendto(int sockfd, const void *buf, size_t len, intflags, const struct sockaddr *dest_addr, socklen_taddrlen);

返回:成功---读或写的字节数(长度);出错--- -1

参数解释:

这两个函数的参数几乎相同,且均把读写(recvfrom为读,sento为写)数据的长度作为函数返回值。前三个参数sockfd,buf和len等同于write和read函数的三个参数:描述符、指向读入或写出缓冲区的指针和读写字节数。

1. recvfrom()函数用来从一个套接字sockfd接收信息,它可用于both  connectionless  and  connection-oriented  sockets(但经常使用于UDP,TCP不常用它)。如果没有信息从套接字读取,那么该函数一直等待到有信息传过来(服务器),否则出错且返回-1。如有消息传过来,则该函数把接收的消息内容置于缓冲区buf,调用者必须为缓冲区buf指定大小len。后面两个参数:该函数返回时,套接字地址结构 *src_addr存储的内容会告诉我们是谁发送了数据报(UDP情况下)或是谁发起了连接(TCP情况下,accept也有这两个参数)。如果调用者对通用地址结构及其长度(这里是指针)不感兴趣,那么可将他们置为NULL

2. sendto()函数用来给另外一个套接字传送信息,sockfd为发送套接字的文件描述符。要传送的消息内容存储在缓冲区buf中,参数const struct sockaddr *dest_addr中的指针dest_addr指向含有数据报接收者的协议地址(如IP地址和端口号)的套接字地址结构。这句话不好理解,但可以简单粗暴的总结为:通常情况下,dest_addr 指向的通用套接字地址结构和recvfrom()函数中的src_addr指向的通用套接字地址结构往往是同一个东东,一个清晰的例子见UDP回射服务器程序:dg_echo()函数源码,猛戳这里

3. addrlen均为两个函数倒数第二个参数(通用地址结构指针)的大小。

4. 在写简单的UDP客户/服务器程序时我们常把flags参数置为0,如何使用它,参见第14章的介绍或手册。

三、最后两个参数

Unix网络编程 卷1 第8章: 基本UDP套接字编程(概述及recvfrom/sendto函数)

其中,nrecv = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);  这行代码的的最后两个参数为指向客户端(因为我们要从客户端接收消息,因此这个参数存储了客户端的IP地址和端口等信息)套接字地址结构(这里是IPv4版本的)的指针及套接字地址结构的长度,而sendto(sockfd, mesg, nrecv, 0, pcliaddr, len); 这行代码为要发送到客户端(因为这行代码是服务器端程序的代码,所以最后两个参数是要填写对端(客户端)的相关信息)的函数,所以指定了要发送的消息缓冲区mesg及其长度nrecv,最后两个参数当然是客户端的套接字地址结构相关的咯。。。


2016年9月10号 晚