《UNIX网络编程 卷1:套接字联网API》学习笔记——高级 I/O函数

UNIX网络编程——高级 I/O函数

  • 套接字超时
  • recv 和 send 函数
  • readv 和 writev 函数
  • recvmsg 和 sendmsg 函数
  • 辅助数据
  • 排队的数据量
  • 套接字和标准 I/O

套接字超时

涉及套接字的I/O操作上设置超时的方法有以下3种。

  • (1)调用 alarm,它在指定超时期满时产生 SIGALARM 信号。
  • (2)在 select 中阻塞等待I/O(select有内置的时间限制),以此代替直接阻塞在 read 或 write 调用上。
  • (3)使用较新的 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项。

recv 和 send 函数

#include 
ssize_t recv(int sockfd, void* buff, size_t nbytes, int flags);
ssize_t send(int sockfd, const void* buff, size_t nbytes, int flags);
                                                返回:若成功则为读入或写成的字节数,若出错则为-1

《UNIX网络编程 卷1:套接字联网API》学习笔记——高级 I/O函数_第1张图片

  • MSG_OOB
    对send,指明即将发送的是带外数据。
    对recv,指明即将读入的是带外数据。
  • MSG_PEEK
    适用于recv/recvfrom,它允许获取数据,但数据不移出缓冲区。
  • MSG_DONTWAIT
    在无需打开相应套接字的非阻塞标志的前提下,把单个I/O操作临时指定为非阻塞,接着执行I/O操作,然后关闭非阻塞标志。

readv 和 writev 函数

#include 
ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);
ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
                                       返回:若成功则为读入或写出的字节数,若出错则为-1

这两个函数的第二个参数都是指向某个iovec结构数组的一个指针,其中 iovec 结构在头文件中定义:

struct iovec
{
	void* iov_base;
	size_t iov_len;
};

iovec 结构数组中元素的数目存在某个限制,具体取决于实现。

readv 和 writev 这两个函数可用于任何描述符,而不仅限于套接字。

recvmsg 和 sendmsg 函数

这两个函数是最通用的I/O函数。
可以把所有 read、readv、recv 和 recvfrom 调用替换成 recvmsg调用。
类似地,各种输出函数调用也可以替换成 sendmsg 调用。

#include 
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr* msg, int flags);
                                返回:若成功则为读入或写出的字节数,若出错则为-1

这两个函数把大部分参数封装到一个 msghdr 结构中:

struct msghdr
{
	void* msg_name;         // 对端地址
	// 对sendmsg是一个值参数
	// 对recvmsg是一个值-结果参数
	socklen_t msg_namelen;     // 对端地址对象长
	struct iovec* msg_iov;
	int msg_iovlen;
	void* msg_control;           // 辅助数据地址
	// 对sendmsg是一个值参数
	// 对recvmsg是一个值-结果参数
	socklen_t msg_controllen;
	// recvmsg用其来接收内核处理后标志[来告知应用recvmsg中出现的一些应用可能感兴趣信息]
	int msg_flags;
};

辅助数据

辅助数据可通过调用 sendmsg 和 recvmsg 这两个函数,使用 msghdr 结构中的 msg_control 和 msg_controllen 这两个成员发送和接收。

辅助数据的另一个称谓是控制信息

《UNIX网络编程 卷1:套接字联网API》学习笔记——高级 I/O函数_第2张图片

辅助数据由一个或多个辅助数据对象构成,每个对象以一个定义在头文件 中的 cmsghdr 结构开头。

struct cmsghdr
{
	socklen_t cmsg_len;
	int cmsg_level;
	int cmsg_type;
	...
};

《UNIX网络编程 卷1:套接字联网API》学习笔记——高级 I/O函数_第3张图片

用于简化对辅助数据的处理。

#include 
#include 
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr * mhdrptr);
                      返回:指向第一个 cmsghdr 结构的指针,若无辅助数据则为 NULL
                      
struct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr);
                             返回:指向下一个 cmsghdr 结构的指针,若不再有辅助数据对象则为 NULL
                             
unsigned char *CMSG_DATA(struct cmsghdr *cmsgptr);
                               返回:指向与 cmsghdr 结构关联的数据的第一个字节的指针  
                               
unsigned int CMSG_LEN(unsigned int length);
                               返回:给定数据量下存放到 cmsg_len 中的值
                               
unsigned int CMSG_SPACE(unsigned int length);
                                返回:给定数据量下一个辅助数据对象总的大小 

排队的数据量

有3个技术可用于获悉已排队的数据量。

  • (1)如果获悉已排队数据量的目的在于避免读操作阻塞在内核中,那么可以使用非阻塞式I/O。
  • (2)如果既想要查看数据,又想数据仍然留在接收队列中以供本进程其他部分稍后读取,那么可以使用 MSG_PEEK 标志。
  • (3)一些实现支持 ioctl 的 FIONREAD 命令。

套接字和标准 I/O

Unix I/O——包括 read、write 这两个函数及它们的变体(recv、send等等)——的函数执行I/O。
这些函数围绕描述符工作,通常作为 Unix 内核中的系统调用实现。

执行I/O的另一个方法是使用标准I/O函数库

标准I/O函数库可用于套接字,不过需要考虑以下几点。

  • 通过调用 fdopen,可以从任何一个描述符创建出一个标准I/O流。
    类似地,通过调用 fileno ,可以获取一个给定标准I/O流对应的描述符。
  • TCP和UDP套接字是全双工的。
    标准I/O流也可以是全双工的:只要以 r+ 类型打开流即可,r+ 意味着读写。
  • 解决上述读写问题的最简单方法是为一个给定套接字打开两个标准I/O流:一个用于读,一个用于写。

学习参考资料:

《UNIX网络编程 卷1:套接字联网API》 第3版

你可能感兴趣的:(UNIX网络编程,unix,网络,服务器)