【问题标题】:UDP send and receive in different threadsUDP在不同线程中发送和接收
【发布时间】:2017-07-05 15:03:35
【问题描述】:

Linux 内核在同一个套接字上处理 UDP 发送和接收的独立性如何?我的用例是一个工作线程在(最多)1000 个套接字上发送 UDP 测试流量,并在另一个工作线程中接收 UDP 回复。接收器将是一个 epoll 循环,它还接收套接字错误队列上的硬件发送和接收时间戳。

澄清一下,在执行 sendmsg() 系统调用时,这会在同一套接字上接收的接收线程上暂时阻塞(或生成 EAGAIN/EWOULDBLOCK)吗? (即如果发送和接收恰好在时间上重叠)所有套接字都设置为非阻塞模式。

另一个问题是内核中锁定的粒度 - 如果我使用 sendmmsg/recvmmsg 发送和接收,该套接字的锁定是每个 sendmmsg 锁定一次,还是每个 sendmmsg 中的 UDP 数据报锁定一次?

更新:我查看了 Linux 内核中 sendmmsg 的原始补丁,似乎主要的好处是避免了用户内核空间的多次转换。如果完成了任何锁定,它可能是在对 __sys_sendmsg 的单独调用中完成的: https://lwn.net/Articles/441169/

【问题讨论】:

  • 不得不说,看标题的时候没想到这么好的问题。
  • 考虑到 UDP 是多么微不足道,如果 UDP 发送会干扰 UDP 接收,我会感到非常惊讶。对于 TCP 来说,隐藏的 ACK 是一对发送和接收,而 UDP 只不过是 IP 加上一个端口号。
  • @MSalters:我同意,发送和接收是相当独立的。如果我有时间,我会深入研究我更新的内核存储库,看看是否能找到更多信息。
  • @MSalters 快速浏览一下 net/ipv4/udp.c 可以看出,对于非阻塞情况(用于 udp 发送)有一个快速、无锁的路径。我对内核不够精通,无法确定这是否意味着对于普通的 UDP 数据包根本没有锁定。

标签: c++ linux multithreading sockets linux-kernel


【解决方案1】:

每个系统调用都是线程独立的。因此,只要您不涉及每个进程的内核数据,两者都将独立运行而不会相互干扰。

另一个不同的事情是内核如何处理与同一 inode 相关的系统调用(在这种情况下,分配给您用来通信的套接字的虚拟节点)为了序列化并对文件系统进行原子调用,内核通常会执行在整个系统调用(这是一个读、写或 ioctl 系统调用)期间的一个 inode 锁,它代表整个系统调用(即使您执行一个唯一的写调用来写入数百万字节,inode 在执行期间被阻塞)整个系统调用)

在 tcp-ip 堆栈中,这是在套接字级别进行的,在您的情况下由特定的AF_INET 套接字类软件控制。就 udp 而言,发送或接收数据包不会影响需要锁定的共享资源,但您必须查看您的 udp 实现(或套接字级别)以查看是否完成了某些锁定以及粒度是多少.通常情况下,锁应该只在 udp 缓冲区的加载/卸载期间使用(通常 udp 中没有缓冲区,因为套接字和网卡驱动程序足以提供足够的缓冲区资源。

【讨论】:

  • inode 是 Unix 文件系统中的结构。套接字不是inode。您要查找的术语是“文件描述符”。
  • @Luis Colorado 你是什么意思'通常在 UDP 中没有缓冲区',你在内核中有每个套接字缓冲区(需要调整例如高速套接字(setsockopt SO_SNDBUF) ),并且您拥有位于 NIC 环形缓冲区之前的整个排队系统。
  • @ErikAlapää,是的...但是在 UDP 模块中没有缓冲...在套接字模块中对传入数据包进行缓冲,在驱动程序缓冲区中对传出数据包进行缓冲。 udp 模块没有缓冲资源,因为数据包直接从用户空间流向驱动程序。 UDP 只选择驱动程序将存储数据包,直到驱动程序准备好传输数据包。 UDP 将数据包直接传递给 IP(并将 IP 传递给驱动程序)模块,没有缓冲。
  • @EJP,一些 unix 实现称之为 vnode,另一些称之为 incore i-node,另一些则不同。但是它们都做同样的事情,在系统调用执行期间阻塞 *-node 以提供系统调用的原子性。 AF_UNIX 套接字是使用文件系统 i-nodes 实现的套接字,与普通文件相同,并且在某些实现中作为一种特殊类型的套接字实现的命名为 fifos(在这种情况下,它们甚至分配磁盘块以实现读取器和读取器之间的缓冲)作家)
  • @EJP,另一方面,文件表条目(文件描述符只是每个进程文件表中的索引)是一个不同的结构,仅分配用于提供文件指针(点下一次写入)以解决进程共享或不文件指针的问题。文件表条目只存储文件指针和一些fcntl(2) 标志。正确的是,今天的实现使用从文件条目指向的不同结构,用于套接字而不是文件系统 inode,但出于锁定目的,两者是相同的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 1970-01-01
  • 2018-12-22
相关资源
最近更新 更多