C语言 如何删除sendto()上的“资源暂时不可用”

nqwrtyyt  于 2023-03-12  发布在  其他
关注(0)|答案(1)|浏览(223)

程序使用单个UDP套接字和sendto()与4个微控制器设备通信。主程序循环的每次迭代都调用sendto()函数,以更新程序状态的控制器。
如果我只发送到1个设备是可以的。但是,如果我尝试发送到4个设备,我会非常频繁地得到EAGAIN错误,以至于无法通信。
我怎样才能消除这些错误呢?我不能阻塞套接字,因为这会降低整个程序的速度,因为它需要几乎在瞬间处理许多其他函数。
我可以不那么频繁地发送sendto()消息,但我仍然希望每秒向每个设备发送2-3条300字节的消息。
如果我使用select(),则会有一个额外的问题,即确保每个设备获得相同的套接字份额。

main_loop {
    open_chamber_socket();
    while (!sig_received) {
        unsigned char * buf;
        for (keydata_poll = 0; msgsize < 0 && errno == ENOMSG && !must_term; keydata_poll++) {
            if ((keydata_poll % 12) == 0) {
                deferred_activities();
            }
            msgsize = msgrcv (msgqid
                , (struct msgbuf_s *)msg, MSGTEXTSIZE (msg)
                , MSGID_KEYDATA, IPC_NOWAIT);
            if (msgsize >= 0)
                break;
            usleep(500);    
        }
        if (msgsize < 0) {
            if (errno != EINTR) {   // report any error except a termination signal
                log_perror(MYNAME ": Error receiving queued message.");
                usleep(5 * 1000);
            }
            continue;
        }
        switch (msg->mtext.action) {
            ...
        }
        ...
    }
}
deferred_activities() {
    ... 
    two thousand lines of code which bit by bit build the send buffers
    ...
    int j, code;
    for (j=0; j<4; j++) {
        struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(4096)};
        addr.sin_addr.s_addr = device[j]->net_address;
        addr.sin_port = device[j]->net_port;
        code = sendto(e_socket, device[j]->buf, device[j]->datasize, 0, (struct sockaddr *) &addr, sizeof addr);
    }
}
int open_chamber_socket(void)
{
    int code, flags;
    struct sockaddr_in addr;
    int optval = 1;
    
    e_socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (e_socket < 0) {
        log_perror (_("%s: Can't create chamber socket."), MYNAME);
        return e_socket;
    }
    // set non-blocking flag on the socket ..
    flags = fcntl (e_socket, F_GETFL, 0);
    if (flags != -1)
        fcntl (e_socket, F_SETFL, flags | O_NONBLOCK);
        
    setsockopt(e_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    bzero((char *) &addr, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl (CHAMBER_ADDRESS);
    addr.sin_port = htons (CHAMBER_PORT);
    code = bind (e_socket, (struct sockaddr *)&addr, sizeof addr);
    if (code < 0) {
        log_perror (_("%s: Can't bind chamber socket to 10.0.0.1:%d."), MYNAME, CHAMBER_PORT);
        return code;
    }
    return 0;
}

系统:Debian Linux靶心

kmpatx3s

kmpatx3s1#

增加Linux操作系统UDP缓冲区可以解决这个冲突。在/etc/sysctl.conf中,我将读写缓冲区都设置为默认值1 MB和最大值25 MB:

net.core.rmem_max = 26214400
net.core.rmem_default=1048576

net.core.wmem_max = 26214400
net.core.wmem_default = 1048576

相关问题