How to know connection disconnected while receive paused

Tan Xiaofan xfan1024 at live.com
Fri Jun 21 20:51:03 CEST 2019


hello,
    I am learning how to write a server program using libev, but I encounter some confusion.
    
    I write a very simple server, the server receive data and send back intact. In order to handle the case of receive speed fast than send speed,
    I pause data receive when send back not complete, send remain data while EV_WRITE event coming, restart receive when remain data send finished.
    
    When receive paused, peer close socket after I call send(), I can not receive any event to indicate the connection is disconnected.
    How to fix it?

                                                                                                Thanks a lot

                                                                                                
my code:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <ev.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

static struct sockaddr_in client_addr;
static int client_fd;
static ev_io watcher;
static char buffer[4096];
static int buffer_end;
static int buffer_off;

static void worker_reset_watcher(EV_P_ int events)
{
    printf("reset_watcher: %s\n", (events == EV_READ) ? "EV_READ" : "EV_WRITE");
    ev_io_stop(EV_A_ &watcher);
    ev_io_set(&watcher, client_fd, events);
    ev_io_start(EV_A_ &watcher);
}

static void close_client(EV_P)
{
    ev_io_stop(EV_A_ &watcher);
    close(client_fd);
}

void client_cb(EV_P_ ev_io *w, int revents)
{
    int res = 0;
    if (revents & EV_READ) {
        res = (int)read(client_fd, buffer, sizeof(buffer));
        printf("read %d\n", res);
        if (res < 0) {
            perror("read");
            close_client(EV_A);
        } else if (res == 0) {
            printf("client disconnected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
            close_client(EV_A);
        } else {
            buffer_end = res;
            res = write(client_fd, buffer, buffer_end);
            printf("write %d, expect %d (1)\n", res, buffer_end);
            if (res < 0) {
                if (errno == EAGAIN) {
                    printf("write EAGIN");
                    worker_reset_watcher(EV_A_ EV_WRITE);
                } else {
                    perror("write");
                    close_client(EV_A);
                }
            } else if (res < buffer_end) {
                buffer_off = res;
                printf("send size less than receive size\n");
                worker_reset_watcher(EV_A_ EV_WRITE);
            }
        }
    }

    if (revents & EV_WRITE) {
        int remain = buffer_end - buffer_off;
        res = (int)write(client_fd, buffer + buffer_off, remain);
        printf("write %d, expect %d (2)\n", res, remain);
        if (res < 0) {
            perror("write");
            close_client(EV_A);
        } else if (res < remain) {
            buffer_off += res;
        } else {
            worker_reset_watcher(EV_A_ EV_READ);
        }
    }
}

int main()
{
    struct sockaddr_in bindaddr = {
        .sin_family = AF_INET,
        .sin_port = htons(6666),
        .sin_addr = { htonl(0) },
    };
    int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    bind(listen_fd, (struct sockaddr*)&bindaddr, sizeof(bindaddr));
    listen(listen_fd, 1);
    socklen_t socklen = sizeof(client_addr);
    client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &socklen);
    printf("client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    close(listen_fd);
    fcntl(client_fd, F_SETFL, fcntl(client_fd, F_GETFL, 0) | O_NONBLOCK);
    ev_io_init(&watcher, client_cb, client_fd, EV_READ);
    ev_io_start(EV_DEFAULT_ &watcher);
    ev_run(EV_DEFAULT_ 0);
    return 0;
}

output:

client connected: 172.30.100.10:5014
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
...
write 2336, expect 4096 (1)
send size less than receive size
reset_watcher: EV_WRITE
write 1760, expect 1760 (2)
reset_watcher: EV_READ
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 4096, expect 4096 (1)
read 4096
write 3840, expect 4096 (1)
send size less than receive size
reset_watcher: EV_WRITE
(program stuck, not exit)



More information about the libev mailing list