我在CentOS 6.5上使用内核版本内核-2.6.32-431.el6。
我试图找到recvmmsg()的实现,希望我没有看错源~/rpmbuild/BUILD/kernel-2.6.32-431.el6/linux-2.6.32-431.el6.x86_64/net/socket.c.如果我是,请告诉我正确的来源。
int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
unsigned int flags, struct timespec *timeout)
{
int fput_needed, err, datagrams;
struct socket *sock;
struct mmsghdr __user *entry;
struct compat_mmsghdr __user *compat_entry;
struct msghdr msg_sys;
struct timespec end_time;
if (timeout &&
poll_select_set_timeout(&end_time, timeout->tv_sec,
timeout->tv_nsec))
return -EINVAL;
datagrams = 0;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
return err;
err = sock_error(sock->sk);
if (err)
goto out_put;
entry = mmsg;
compat_entry = (struct compat_mmsghdr __user *)mmsg;
while (datagrams < vlen) {
/*
* No need to ask LSM for more than the first datagram.
*/
if (MSG_CMSG_COMPAT & flags) {
err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
&msg_sys, flags, datagrams);
if (err < 0)
break;
err = __put_user(err, &compat_entry->msg_len);
++compat_entry;
} else {
err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
&msg_sys, flags, datagrams);
if (err < 0)
break;
err = put_user(err, &entry->msg_len);
++entry;
}
if (err)
break;
++datagrams;
if (timeout) {
ktime_get_ts(timeout);
*timeout = timespec_sub(end_time, *timeout);
if (timeout->tv_sec < 0) {
timeout->tv_sec = timeout->tv_nsec = 0;
break;
}
/* Timeout, return less than vlen datagrams */
if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
break;
}
/* Out of band data, return right away */
if (msg_sys.msg_flags & MSG_OOB)
break;
}
out_put:
fput_light(sock->file, fput_needed);
if (err == 0)
return datagrams;
if (datagrams != 0) {
/*
* We may return less entries than requested (vlen) if the
* sock is non block and there aren't enough datagrams...
*/
if (err != -EAGAIN) {
/*
* ... or if recvmsg returns an error after we
* received some datagrams, where we record the
* error to return on the next call or if the
* app asks about it using getsockopt(SO_ERROR).
*/
sock->sk->sk_err = -err;
}
return datagrams;
}
return err;
}
假设套接字上有两个数据包,我试着:
timespec t = {0, 0};
recvmmsg(fd, mmsg, vlen, 0, &t);
然后,因为这些行:
if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
break;
recvmmsg()只返回一个包而不是两个包,对吗?
它似乎背离了recvmmsg()的主要目的之一--试图在数据包排队时减少#系统调用。
也许我错过了什么?
任何建议都是欢迎的。
谢谢!
============================
更新:
我试图编写一个小的代码片段,它等待数据包排队,然后用timeout=0 ( NULL)调用recvmmsg()。它仍然只捡到一个包。因此,我认为我看到的是正确的源代码。
发布于 2017-03-29 11:55:02
是的,你是对的。我认为如果要读取队列中的所有数据包,最好使用空超时+ O_NONBLOCK。
发布于 2014-09-29 04:12:26
不是的。零超时意味着无穷大。
发布于 2020-10-31 10:19:01
忽略recvmmsg超时参数,必要时使用SOL_SOCKET、SO_RCVTIMEO。工作正常。
https://stackoverflow.com/questions/26092379
复制相似问题