最近调试openwrt,发现低版本的ulibc不支持recv/send mmsg API,故简单写个实现一个测试程序,直接贴代码吧!,这里的程序可能兼容新版版本的ulibc出现问题,所以使用wrap_简单封装一下。
#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/unistd.h>
#include <unistd.h>
/* Support recvmmsg/sendmmsg as uClib not support*/
#ifndef MSG_WAITFORONE
#define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */
#endif
struct mmsghdr {
struct msghdr msg_hdr;
unsigned msg_len;
};
static inline int recvmmsg(int fd, struct mmsghdr *mmsg,
unsigned vlen, unsigned flags, struct timespec *timeout)
{
return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
}
static inline int sendmmsg(int fd, struct mmsghdr *mmsg,
unsigned vlen, unsigned flags)
{
return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
}
int
main(void)
{
#define VLEN 10
#define BUFSIZE 200
#define TIMEOUT 3
int sockfd, retval, i;
struct sockaddr_in sa;
struct mmsghdr msgs[VLEN];
struct iovec iovecs[VLEN];
char bufs[VLEN][BUFSIZE+1];
struct timespec timeout;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket()");
exit(EXIT_FAILURE);
}
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(12345);
if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
perror("bind()");
exit(EXIT_FAILURE);
}
LOOP:
memset(msgs, 0, sizeof(msgs));
for (i = 0; i < VLEN; i++) {
iovecs[i].iov_base = bufs[i];
iovecs[i].iov_len = BUFSIZE;
msgs[i].msg_hdr.msg_iov = &iovecs[i];
msgs[i].msg_hdr.msg_iovlen = 1;
}
timeout.tv_sec = TIMEOUT;
timeout.tv_nsec = 0;
retval = recvmmsg(sockfd, msgs, VLEN, MSG_WAITFORONE, NULL);
if (retval == -1) {
perror("recvmmsg()");
exit(EXIT_FAILURE);
}
printf("%d messages received\n", retval);
for (i = 0; i < retval; i++) {
bufs[i][msgs[i].msg_len] = 0;
printf("%d %s", i+1, bufs[i]);
}
/* delay */
for(i = 0; i < 10000000; i++)
memset(msgs, 0, sizeof(msgs));
goto LOOP;
exit(EXIT_SUCCESS);
}