|
||||||||
|
|
|||||||
![]() |
|
|
Thread Tools | Display Modes |
|
#1
|
|
Hello everyone,
Consider an internet datagram socket. sock = socket(PF_INET, SOCK_DGRAM, 0); Suppose I know there are more than one datagram waiting in the socket. (For example, because I'm receiving 4000 packets per second, and I've just woken up from a 10 ms sleep.) It seems wasteful to make one system call per datagram I'm about to recv(). On the other hand, the overhead from the system calls might be negligible. I think I could write: uint8_t buf[PACKET_SIZE*N]; struct iovec iov; for (int i=0; i < N; ++i) { iov[i].iov_base = buf + PACKET_SIZE*i; iov[i].iov_len = PACKET_SIZE; } then call recvmsg(). If I don't set MSG_DONTWAIT, will recvmsg() block until N packets are available? If I do set MSG_DONTWAIT, and if there are 0 datagrams available, will recvmsg return -1 with errno set to EAGAIN? If I do set MSG_DONTWAIT, and if there are 0<K<N datagrams available, will recvmsg return PACKET_SIZE*K with errno unchanged? Final question: has anyone measured the overhead of calling recv() 10 times in a loop vs calling recvmsg() to greb 10 packets? (My OS is Linux 2.6.22 if it matters.) Regards. Spoon |
|
#2
|
|||
|
|||
|
Spoon <root@localhost> writes:
> Consider an internet datagram socket. > sock = socket(PF_INET, SOCK_DGRAM, 0); > [...] > It seems wasteful to make one system call per datagram I'm about to > recv(). On the other hand, the overhead from the system calls might be > negligible. > > I think I could write: > > uint8_t buf[PACKET_SIZE*N]; > struct iovec iov; > for (int i=0; i < N; ++i) > { > iov[i].iov_base = buf + PACKET_SIZE*i; > iov[i].iov_len = PACKET_SIZE; > } > > then call recvmsg(). [...] > If I do set MSG_DONTWAIT, and if there are 0<K<N datagrams available, > will recvmsg return PACKET_SIZE*K with errno unchanged? No. Datagram sockets preserve message boundaries, and this means that each call to a receive-routine will return exactly one message (in absence of errors). |
|
#3
|
|||
|
|||
|
Rainer Weikusat wrote:
> Spoon wrote: > >> Consider an internet datagram socket. >> sock = socket(PF_INET, SOCK_DGRAM, 0); >> >> It seems wasteful to make one system call per datagram I'm about to >> recv(). On the other hand, the overhead from the system calls might be >> negligible. >> >> I think I could write: >> >> uint8_t buf[PACKET_SIZE*N]; >> struct iovec iov; Doh! I meant struct iovec iov[N]; >> for (int i=0; i < N; ++i) >> { >> iov[i].iov_base = buf + PACKET_SIZE*i; >> iov[i].iov_len = PACKET_SIZE; >> } >> >> then call recvmsg(). >> >> If I do set MSG_DONTWAIT, and if there are 0<K<N datagrams available, >> will recvmsg return PACKET_SIZE*K with errno unchanged? > > No. Datagram sockets preserve message boundaries, and this means that > each call to a receive-routine will return exactly one message (in > absence of errors). If I understand correctly, recvmsg() could be used to "splice" a single large datagram into several parts (one part per struct iovec). But it can't be used to receive more than one datagram? If this is correct, my question becomes: Is there a way to receive more than one datagram in a single system call? Regards. |
|
#4
|
|||
|
|||
|
On Sep 30, 10:48 am, Spoon <root@localhost> wrote:
> Rainer Weikusat wrote: > > Spoon wrote: > > >> Consider an internet datagram socket. > >> sock = socket(PF_INET, SOCK_DGRAM, 0); > > >> It seems wasteful to make one system call per datagram I'm about to > >> recv(). On the other hand, the overhead from the system calls might be > >> negligible. > > >> I think I could write: > > >> uint8_t buf[PACKET_SIZE*N]; > >> struct iovec iov; > > Doh! I meant struct iovec iov[N]; > > >> for (int i=0; i < N; ++i) > >> { > >> iov[i].iov_base = buf + PACKET_SIZE*i; > >> iov[i].iov_len = PACKET_SIZE; > >> } > > >> then call recvmsg(). > > >> If I do set MSG_DONTWAIT, and if there are 0<K<N datagrams available, > >> will recvmsg return PACKET_SIZE*K with errno unchanged? > > > No. Datagram sockets preserve message boundaries, and this means that > > each call to a receive-routine will return exactly one message (in > > absence of errors). > > If I understand correctly, recvmsg() could be used to "splice" a single > large datagram into several parts (one part per struct iovec). But it > can't be used to receive more than one datagram? > > If this is correct, my question becomes: Is there a way to receive more > than one datagram in a single system call? No (that is, not without introducing new syscall in the kernel). But if you change UDP to TCP, you get the desired property automatically. Did you actually measure the overhead of the recv() syscall to begin with ? Yakov |
|
#5
|
|||
|
|||
|
Yakov <(E-Mail Removed)> writes:
> On Sep 30, 10:48 am, Spoon <root@localhost> wrote: >> Rainer Weikusat wrote: [...] >> If I understand correctly, recvmsg() could be used to "splice" a single >> large datagram into several parts (one part per struct iovec). But it >> can't be used to receive more than one datagram? >> >> If this is correct, my question becomes: Is there a way to receive more >> than one datagram in a single system call? > > No (that is, not without introducing new syscall in the kernel). > But if you change UDP to TCP, you get the desired property > automatically. TCP is bytestream protocol, consequently, there is not way to 'receive a datagram' with TCP. A successful receive will return some number of bytes between zero (remote closed the connection) and the size of the buffer which was passed to the syscall. Additionally, it is a reliable protocol, which is not useful for realtime-applications (which I figure 'Spoon' is writing about), because the data becomes useless once the time when it would have been needed has passed (imagine a local 10s power outage at some place where a router forwarding telephone voice data sits: If data from this period is afterwards retransmitted, the receiver would be ten seconds in the past relative to the sender afterwards). |
![]() |
| Tags |
| datagrams, grabbing, socket |
| Thread Tools | |
| Display Modes | |
|
|