linux 多个select,Linux select()和多个套接字的FIFO排序?

您可以使用IP_PKTINFO获取数据包发送到的多播组的地址 - 即使套接字订阅了一堆多播组。有了这个,您将按顺序获取数据包并按组地址过滤。请参阅以下示例:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 1234

#define PPANIC(msg) perror(msg); exit(1);

#define STATS_PATCH 0

int main(int argc, char **argv)

{

fd_set master;

fd_set read_fds;

struct sockaddr_in serveraddr;

int sock;

int opt = 1;

size_t i;

int rc;

char *mcast_groups[] = {

"226.0.0.1",

"226.0.0.2",

NULL

};

#if STATS_PATCH

struct stat stat_buf;

#endif

struct ip_mreq imreq;

FD_ZERO(&master);

FD_ZERO(&read_fds);

rc = sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if(rc == -1)

{

PPANIC("socket() failed");

}

rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

if(rc == -1)

{

PPANIC("setsockopt(reuse) failed");

}

memset(&serveraddr, 0, sizeof(serveraddr));

serveraddr.sin_family = AF_INET;

serveraddr.sin_port = htons(PORT);

serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

rc = bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

if(rc == -1)

{

PPANIC("bind() failed");

}

rc = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));

if(rc == -1)

{

PPANIC("setsockopt(IP_PKTINFO) failed");

}

for (i = 0; mcast_groups[i] != NULL; i++)

{

imreq.imr_multiaddr.s_addr = inet_addr(mcast_groups[i]);

imreq.imr_interface.s_addr = INADDR_ANY;

rc = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&imreq, sizeof(struct ip_mreq));

if (rc != 0)

{

PPANIC("joing mcast group failed");

}

}

FD_SET(sock, &master);

while(1)

{

read_fds = master;

rc = select(sock + 1, &read_fds, NULL, NULL, NULL);

if (rc == 0)

{

continue;

}

if(rc == -1)

{

PPANIC("select() failed");

}

if(FD_ISSET(sock, &read_fds))

{

char buf[1024];

int inb;

char ctrl_msg_buf[1024];

struct iovec iov[1];

iov[0].iov_base = buf;

iov[0].iov_len = 1024;

struct msghdr msg_hdr = {

.msg_iov = iov,

.msg_iovlen = 1,

.msg_name = NULL,

.msg_namelen = 0,

.msg_control = ctrl_msg_buf,

.msg_controllen = sizeof(ctrl_msg_buf),

};

struct cmsghdr *ctrl_msg_hdr;

inb = recvmsg(sock, &msg_hdr, 0);

if (inb < 0)

{

PPANIC("recvmsg() failed");

}

for (ctrl_msg_hdr = CMSG_FIRSTHDR(&msg_hdr); ctrl_msg_hdr != NULL; ctrl_msg_hdr = CMSG_NXTHDR(&msg_hdr, ctrl_msg_hdr))

{

if (ctrl_msg_hdr->cmsg_level == IPPROTO_IP && ctrl_msg_hdr->cmsg_type == IP_PKTINFO)

{

struct in_pktinfo *pckt_info = (struct in_pktinfo *)CMSG_DATA(ctrl_msg_hdr);

printf("got data for mcast group: %s\n", inet_ntoa(pckt_info->ipi_addr));

break;

}

}

printf("|");

for (i = 0; i < inb; i++)

printf("%c", isprint(buf[i])?buf[i]:'?');

printf("|\n");

#if STATS_PATCH

rc = fstat(sock, &stat_buf);

if (rc == -1)

{

perror("fstat() failed");

} else {

printf("st_atime: %d\n", stat_buf.st_atime);

printf("st_mtime: %d\n", stat_buf.st_mtime);

printf("st_ctime: %d\n", stat_buf.st_ctime);

}

#endif

}

}

return 0;

}下面的代码不会解决OP问题,但可能会指导人们处理类似的要求

(编辑)一个人不应该在深夜做这样的事情......即使有了这个解决方案,你也只能通过选择获得fd处理的订单 - 而且这不会给你关于帧到达时间的指示。

如here所述,目前无法检索套接字的顺序或它们更改的时间戳,因为没有为套接字inode设置所需的回调。但是,如果您能够修补内核,则可以通过在select系统调用中设置时间来解决此问题。

以下补丁可能会给你一个想法:

diff --git a/fs/select.c b/fs/select.c

index 467bb1c..3f2927e 100644

--- a/fs/select.c

+++ b/fs/select.c

@@ -435,6 +435,9 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)

for (i = 0; i < n; ++rinp, ++routp, ++rexp) {

unsigned long in, out, ex, all_bits, bit = 1, mask, j;

unsigned long res_in = 0, res_out = 0, res_ex = 0;

+ struct timeval tv;

+

+ do_gettimeofday(&tv);

in = *inp++; out = *outp++; ex = *exp++;

all_bits = in | out | ex;

@@ -452,6 +455,16 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)

f = fdget(i);

if (f.file) {

const struct file_operations *f_op;

+ struct kstat stat;

+

+ int ret;

+ u8 is_sock = 0;

+

+ ret = vfs_getattr(&f.file->f_path, &stat);

+ if(ret == 0 && S_ISSOCK(stat.mode)) {

+ is_sock = 1;

+ }

+

f_op = f.file->f_op;

mask = DEFAULT_POLLMASK;

if (f_op->poll) {

@@ -464,16 +477,22 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)

res_in |= bit;

retval++;

wait->_qproc = NULL;

+ if(is_sock && f.file->f_inode)

+ f.file->f_inode->i_ctime.tv_sec = tv.tv_sec;

}

if ((mask & POLLOUT_SET) && (out & bit)) {

res_out |= bit;

retval++;

wait->_qproc = NULL;

+ if(is_sock && f.file->f_inode)

+ f.file->f_inode->i_ctime.tv_sec = tv.tv_sec;

}

if ((mask & POLLEX_SET) && (ex & bit)) {

res_ex |= bit;

retval++;

wait->_qproc = NULL;

+ if(is_sock && f.file->f_inode)

+ f.file->f_inode->i_ctime.tv_sec = tv.tv_sec;

}

/* got something, stop busy polling */

if (retval) {笔记:

这是......仅适合你:) - 不要指望它在主线

在测试每个相关的fd之前调用

do_gettimeofday()。

为了获得更高的粒度,这应该在每次迭代中完成(并且仅在需要时)。因为stat-interface只提供一秒的粒度

你可以(!UGLY!)使用剩余的时间属性将秒的分数映射到那些字段。

这是使用内核3.16.0完成的,并没有经过充分测试。不要在太空船或医疗设备中使用它。如果您想尝试一下,请获取文件系统映像(例如https://people.debian.org/~aurel32/qemu/amd64/debian_wheezy_amd64_standard.qcow2)并使用qemu进行测试:

sudo qemu-system-x86_64 -kernel arch / x86 / boot / bzImage -hda debian_wheezy_amd64_standard.qcow2 -append“root = / dev / sda1”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值