使用sendmsg,recvmsg有什么好处

时间:2015-01-23 07:57:14

标签: sockets

我正在研究Linux网络编程,并看到一些关于读取,从/向套接字写入数据的功能。 recv,send,recvmsg,sendmesg。据我所知,recvmsg可用于传递文件描述符,增加从/向套接字读/写的超时。你能不能让我知道使用recvmsg,sendmsg而不是recv,send? 非常感谢你。

2 个答案:

答案 0 :(得分:2)

recvmsg和sendmsg可以做的一些事情:

  1. 您可以执行分散/收集缓冲区。例如,让我们想要收到1MB的数据,但是你只有10个缓冲区,每个缓冲区都是100KB,那么你可以在一个recvmsg调用中填写每个缓冲区。

  2. 访问控制标志,辅助数据和IP数据包标头字段。例如,对于UDP,您可以通过枚举从recvmsg返回的控制数据(启用某些ioctl)来获取数据包被寻址的目标IP /端口地址。

答案 1 :(得分:0)

古老的问题,但是recvmsg的另一个有用的功能是用于在数据包中使用标头/数据格式的协议。您可以设置一个用于接收标头的缓冲区,以及另一个用于接收数据的缓冲区。

到目前为止,仅需将后者移入接收的数据即可,您将获得连续的数据,而没有任何(附加的)内存副本。效率更高。

想象一下您需要分批传输非常大的文件的情况。使用经典的recv调用,您需要创建一个这样的缓冲区(伪代码):

while(received < expectedFileSize)
{
  char buffer[65536 - sizeof(Header)];
  int s = recv(fd, buffer, sizeof(buffer), 0); // One syscall here
  received += write(outfd, &buffer[sizeof(Header)], s);  // One syscall per buffer, which cause a memcpy in the kernel
}

使用recvmsg,您可以跳过每个数据包和许多系统调用的内存副本:

char * file = mmap(...); // Get a writable buffer for this file
while(received < expectedFileSize)
{
    char header[sizeof(Header)];
    struct iovec v[2] = { { header, sizeof(Header) }, { file + received, expectedFileSize - received } };
    msghdr msg = { NULL, 0, v, 2, 0, 0, 0 };
    int s = recvmsg(fd, &msg, 0); // Only one syscall here
    received += s - sizeof(Header);
}

不幸的是,这仅适用于固定大小的标头。

相反,假设您需要编写一个HTTP服务器。

此协议在发送内容之前先发送一堆头。使用sendmsg几乎是执行此任务的1:1方法,其中一个线程在编译头文件,而另一个线程在编译内容。

在这种情况下,无需添加锁定,因为每个线程在其自己的缓冲区上执行,,内容编译的处理无需等待标头被完全编译(因为没有sendmsg,您需要标头大小才能在标头后附加内容。