-1

From online resource, they said that if epoll listening on file descriptors using default mode(level trigger), when the fd(file descriptor) is ready to read and the buffer data associated with fd not fully consumed, epoll will continue to trigger until all data is consumed, however, when I test with epoll(LT mode) listening on udp socket, when multiple characters comes epoll only trigger once. the process like below:

step 1: create epoll, udp socket fd, then make epoll listening on socket for write event.

step 2: send multiple characters("abc") to the udp socket

step 3: each time epoll triggered, then read 1 character from the udp socket.

I am expecting that epoll trigger three times as udp socket receive 3 characters, but the result is epoll only trigger once. here is my code:

#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 ;
}

enter image description here

SonKo
  • 1
  • 1
  • I also test epoll(LT mode) listening on STDIN_FILENO, All procedure are same except the file discriptor, one for udp socket, one for standard input, however the result is that when listening on stdin, epoll will trigger several times while only one time on udp socket, Is there any special on udp socket? Thanks – SonKo Jun 20 '18 at 00:50

1 Answers1

0

You are treating UDP as though it was a streaming protocol, i.e. TCP. It isn't. It is a datagram protocol. If you read a UDP datagram into a buffer that is too small to receive it, the remainder of the datagram is discarded. Not left in the buffer for next time.

Reading one character at a time is therefore pointless in UDP, not to mention extremely inefficient in any protocol.

NB You don't need the memset(), and this:

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

is invalid. It should be:

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

You can't assume the received data is null-terminated.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thank you @EJP for your answer, Following your idea I did another test(read every 1 character each time once the udp socket is ready to read), the result shows after reading 1 character, read action is blocked, as you said "the remainder of the datagram is discarded", This explains why epoll trigger only once. by the way, Thank you for pointing out the log("recv msg : %s \n", buffer); – SonKo Jun 20 '18 at 04:58