kqueue nonblocking socket timeout with siege

Victor França victorfranlopes at outlook.com
Sat Jan 3 15:37:36 UTC 2015


I'm trying to create a server that works with multiple connections using kqueue.
After much research, I developed my code to test the technology. 
So I started testing with the siege, however, after an average of 300 requests, the server begins to become unstable, sometimes the siege points timeout, sometimes it can get the answer.

I 'm using the g ++ to compile.

Here is my code.

#include <iostream>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sstream>

using namespace std;

struct client_s {
    int fd;
    int type;
    socklen_t addrlen;
    struct sockaddr addr;
    int bufflen;
};

int main (int argc, char *argv[]) {

    int portN, sockFD, sockOPT, eveCT, optRET, bindRET, listenRET, kernelQUE, nev, connectionFlags, numBT;
    struct sockaddr_in sockADDR;
    struct kevent events[2];
    struct kevent changes[2];

    if (argc < 2) {
        cerr << "Argument required: [port]" << endl; 
        return -1;
    }

    portN = atoi(argv[1]);

    sockFD = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

    if (sockFD < 0) {
        cerr << "Error while opening socket: " << strerror(errno) << endl;
        return -1;
    } else
        clog << "Socket openend. Nonblock socket defined." << endl;

    sockOPT = 1;

    optRET = setsockopt(sockFD, SOL_SOCKET, SO_REUSEADDR, &sockOPT, sizeof(sockOPT)); // Avoid TIME_WAIT
    if (optRET < 0) {
        cerr << "Error while setting flag SO_REUSEADDR: " << strerror(errno) << endl;
        return -1;
    } else
        clog << "SO_REUSEADDR flag ok." << endl;

    optRET = setsockopt(sockFD, IPPROTO_TCP, TCP_NODELAY, &sockOPT, sizeof(sockOPT)); // Avoid socket buffer
    if (optRET < 0) {
        cerr << "Error while setting flag TCP_NODELAY: " << strerror(errno) << endl;
        return -1;
    } else
        clog << "TCP_NODELAY flag ok." << endl;

    memset(&sockADDR, 0, sizeof(struct sockaddr_in));

    sockADDR.sin_family = AF_INET;
    sockADDR.sin_port = htons(portN);
    sockADDR.sin_addr.s_addr = INADDR_ANY;

    bindRET = bind(sockFD, (struct sockaddr*)&sockADDR, sizeof(sockADDR));

    if (bindRET < 0) {
        cerr << "Error while binding socket: " << strerror(errno) << endl;
        return -1;
    } else
        clog << "Socket binded." << endl;

    listenRET = listen(sockFD, 1000);

    if (listenRET < 0) {
        cerr << "Error while start listening the port: " << strerror(errno) << endl;
        return -1;
    } else
        clog << "Socket is listening the port " << argv[1] << endl;

    kernelQUE = kqueue();

    if (kernelQUE < 0) {
        cerr << "Error on creating kqueue." << endl;
        return -1;
    } else
        clog << "Starting kernel queue." << endl;

    memset(events, 0, sizeof(events));
    memset(changes, 0, sizeof(changes));

    EV_SET(&changes[0], sockFD, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

    eveCT = 1;
    for (;;) {

        nev = kevent(kernelQUE, changes, eveCT, events, eveCT, NULL);

        if (nev < 0) {
            cerr << "Error resolving event." << endl;
            return -1;
        }

        for (int i = 0;i <= nev; i++) {
            struct client_s * client = static_cast<client_s *>(malloc(sizeof(struct client_s)));

            if (events[i].ident == sockFD && events[i].filter == EVFILT_READ) {
                client->fd = accept4(sockFD, &client->addr, &client->addrlen, SOCK_NONBLOCK);

                if (client->fd < 0) {
                    cerr << "Error while accepting new connection." << strerror(errno) << endl;
                    free(client);
                } else {
                    client->type = 2;
                    client->bufflen = 0;        
                    EV_SET(&changes[1], client->fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, client);
                    eveCT=2;
                }
            }

            if (events[i].filter == EVFILT_READ && events[i].udata && events[i].data > 0) {
                client = static_cast<client_s *>(events[i].udata);
                if (client->type == 2) {

                    client->type++;
                    char *buffer = new char[events[i].data];
                    client->bufflen = events[i].data;
                    numBT = recv(client->fd, buffer, events[i].data, 0);
                    delete[] buffer;
                    if (numBT == events[i].data) {
                        EV_SET(&changes[1], client->fd, EVFILT_READ, EV_DISABLE, 0, 0, 0);
                        kevent(kernelQUE, &changes[1], 1, NULL, 0, 0);                  
                        EV_SET(&changes[1], client->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, client);
                    } else
                        cerr << "Error while reading." << strerror(errno) << endl;
                }
            } else if (events[i].filter == EVFILT_WRITE && events[i].udata) {
                client = static_cast<client_s *>(events[i].udata);
                if (client->type == 3) {            
                    string query("HTTP/1.1 200 OK\r\n\r\nKernel events, baby!";);
                    numBT = send(client->fd, query.c_str(), query.size(), 0);
                    if (numBT == query.size()) {
                        EV_SET(&changes[1], client->fd, EVFILT_WRITE, EV_DISABLE, 0, 0, 0);
                        kevent(kernelQUE, &changes[1], 1, NULL, 0, 0);
                        memset(&changes[1], 0, sizeof(struct kevent));
                        shutdown(client->fd, SHUT_RDWR);
                        close(client->fd);
                        free(client);
                        eveCT=1;
                    } else
                        cerr << "Error while writing." << strerror(errno) << endl;
                }
            }
        }
    }

    shutdown(sockFD, SHUT_RDWR);
    close(sockFD);

    return 0;
} 		 	   		  


More information about the freebsd-hackers mailing list