Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets Epoll事件(EPOLLT)仅在udp套接字上触发一次_Sockets_Udp_Epoll - Fatal编程技术网

Sockets Epoll事件(EPOLLT)仅在udp套接字上触发一次

Sockets Epoll事件(EPOLLT)仅在udp套接字上触发一次,sockets,udp,epoll,Sockets,Udp,Epoll,从在线资源中,他们说,如果epoll使用默认模式(级别触发器)侦听文件描述符,当fd(文件描述符)准备好读取且与fd相关的缓冲区数据未完全消耗时,epoll将继续触发,直到所有数据被消耗,然而,当我使用在udp套接字上侦听的epoll(LT模式)进行测试时,当出现多个字符时,epoll只触发一次。 过程如下: 步骤1:创建epoll、udp套接字fd,然后使epoll在套接字上侦听写事件 步骤2:向udp套接字发送多个字符(“abc”) 步骤3:每次触发epoll时,从udp套接字读取1个字符

从在线资源中,他们说,如果epoll使用默认模式(级别触发器)侦听文件描述符,当fd(文件描述符)准备好读取且与fd相关的缓冲区数据未完全消耗时,epoll将继续触发,直到所有数据被消耗,然而,当我使用在udp套接字上侦听的epoll(LT模式)进行测试时,当出现多个字符时,epoll只触发一次。 过程如下:

步骤1:创建epoll、udp套接字fd,然后使epoll在套接字上侦听写事件

步骤2:向udp套接字发送多个字符(“abc”)

步骤3:每次触发epoll时,从udp套接字读取1个字符

我希望epoll触发三次,因为udp套接字接收3个字符,但结果是epoll只触发一次。 这是我的密码:

#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define BUFFER_SIZE 512
#define log(fmt, arg...) printf(""fmt, ##arg)

void main(){
    int fd1,efd, fds, i, fd;
    int ret, addr_len;
    struct epoll_event g_event;             
    struct epoll_event *epoll_events_ptr; 
    char buffer[BUFFER_SIZE] = {0};
    struct sockaddr_in addr1;

    fd1 = socket(AF_INET, SOCK_DGRAM, 0);   
    if (fd1 == -1) {
        log("create socket fail \r\n");
        return ;
    }     

    addr1.sin_family = AF_INET;             
    addr1.sin_addr.s_addr = INADDR_ANY; 
    addr1.sin_port = htons(3500);    
    addr_len = sizeof(struct sockaddr_in);

    if (0 != bind(fd1, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in))) { 
        log("bind local listening addr fail,errno : %d \r\n", errno);
        goto err;
    }


    efd = epoll_create1(0);                 
    if (efd == -1) {
        log("create epoll fail \r\n");
        goto err;
    }
    log("create epoll instance success \r\n");

    epoll_events_ptr = (struct epoll_event *)calloc(2, sizeof(struct epoll_event));
    if (epoll_events_ptr == NULL) {
        log("calloc fail \r\n");
        goto err;
    }

    g_event.data.fd = fd1; 
    g_event.events = EPOLLIN;   
    epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &g_event);          

    while(1) {
        fds = epoll_wait(efd, epoll_events_ptr, 2, -1); 
        for (i = 0; i<fds; i++)
        {    
            if (epoll_events_ptr[i].events & EPOLLIN)
            {   
                ret = recv(fd1, buffer, 1, MSG_DONTWAIT);
                if(ret != -1)
                log("recv msg : %s \n", buffer);
            }
            memset(buffer, 0, BUFFER_SIZE);
        }        
    }   

err:
    close(fd1);
    if(epoll_events_ptr) 
        free(epoll_events_ptr);

    return ;
}
#包括
#包括
#包括
#包括

#包括

您将UDP视为流协议,即TCP。事实并非如此。这是一个数据报协议。如果将UDP数据报读入太小而无法接收的缓冲区,则会丢弃该数据报的其余部分。下次不会留在缓冲区中

因此,在UDP中,一次读取一个字符是毫无意义的,更不用说在任何协议中效率极低

注意:您不需要
memset()
,并且:

log("recv msg : %s \n", buffer);
这是无效的。应该是:

log("recv msg : %.*s \n", ret, buffer);

您不能假设接收到的数据以null结尾。

我还测试了在STDIN_文件上侦听epoll(LT模式)否,所有过程都是相同的,除了文件描述符,一个用于udp套接字,一个用于标准输入,但结果是,在侦听STDIN时,epoll将触发数次,而在udp套接字上仅触发一次,udp套接字上有什么特殊的功能吗?感谢@EJP的回答,根据您的想法,我做了另一个测试(udp套接字准备好读取后,每次读取1个字符),结果显示读取1个字符后,读取操作被阻止,正如您所说的“数据报的其余部分被丢弃”,这解释了为什么epoll只触发一次。顺便说一下,感谢您指出日志(“recv msg:%s\n”,buffer);