How to make an epoll-based HTTP client

return
::::::::::::::
Makefile
::::::::::::::
# @author KISHI Yasuhiro
# $Id: Makefile,v 1.2 2008/11/23 12:30:13 ykishi Exp ykishi $

CC       = gcc
OBJS     = epoll-client.o getSocket.o setNonblocking.o
LIBS     =
INCLUDES =
TARGET   = epoll-client

$(TARGET): $(OBJS)
        $(CC) -o $@ $(OBJS) $(LIBS) && strip $(TARGET)

.c.o:
        $(CC) -c $< $(INCLUDES)

clean:
        rm -f $(TARGET) $(OBJS) *~ *.c.orig

indent:
        astyle -a -P --mode=java *.c

getSocket.o: getSocket.h
setNoblocking.o: setNonblocking.h
::::::::::::::
getSocket.h
::::::::::::::
/*
 * $Id: getSocket.h,v 1.1 2008/11/23 12:18:50 ykishi Exp ykishi $
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

int getSocket (char *hostname, int portNumber);
::::::::::::::
setNonblocking.h
::::::::::::::
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <netinet/in.h>

/**
* $Source: /home/ykishi/C-test/epoll-client/RCS/setNonblocking.h,v $
*/

void setNonblocking (int sock);
::::::::::::::
epoll-client.c
::::::::::::::
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <netinet/in.h>

/**
* $Source: /home/ykishi/C-test/epoll-client/RCS/epoll-client.c,v $
*/

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

    char *host;
    int port;
    char *requestURI;
    int i = 0;
    int maxClients = 0;

    if ( argc != 5 ) {
        fprintf ( stderr, "Usage: %s [host] [port] [requestURI] [maxClients]\n", argv[0] );
        return -1;
    }
    host = argv[1];
    port = atoi ( argv[2] );
    requestURI = argv[3];
    maxClients = atoi(argv[4]);

    //--------------------------------------------------
    // create epoll's descriptors
    //--------------------------------------------------
    int epfd;
    if ( ( epfd = epoll_create ( maxClients ) ) < 0 ) {
        perror ( "epoll_create" );
        exit ( 1 );
    }

    //--------------------------------------------------
    // create as many socket handles as needed
    //--------------------------------------------------
    int sock[maxClients];
    for ( i = 0; i < maxClients; i++ ) {
        sock[i] = getSocket ( host, port );
        setNonblocking ( sock[i] );

        fprintf ( stderr, "... socket handle created ... \n" );
    }

    //--------------------------------------------------
    // add all the sockets into epoll
    //--------------------------------------------------
    struct epoll_event ev;
    struct epoll_event events[maxClients];

    for ( i = 0; i < maxClients; i++ ) {
        memset ( &ev, 0, sizeof ev );
        ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
        ev.data.fd = sock[i];
        if ( epoll_ctl ( epfd, EPOLL_CTL_ADD, sock[i], &ev ) < 0 ) {
            fprintf ( stderr, "epoll_ctl()\n" );
            exit ( 2 );
        }
    }

    //--------------------------------------------------------------
    // wait for the available status of each epoll descriptor
    //--------------------------------------------------------------
    int nfd;
    while ( 1 ) {
        nfd = epoll_wait ( epfd, events, maxClients, -1 );

        for ( i = 0; i < nfd; ++i ) {
            fprintf ( stderr, "*** now polling *** i=%d\n", i );

            int client = events[i].data.fd;
            char message[1024];

            if ( events[i].events & EPOLLOUT ) {
                sprintf ( message, "GET %s HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
                          requestURI, host, port );
                int write_len = write ( client, message, strlen ( message ) );
                printf ( "write_len=%d\n", write_len );
            }

            if ( events[i].events & EPOLLIN ) {
                memset ( message, 0, sizeof message );
                int read_len = read ( client, message, sizeof message );
                printf ( "read_len=%d\n", read_len );

                // detached
                epoll_ctl ( epfd, EPOLL_CTL_DEL, client, &ev );
                // close socket
                close ( client );

                // add new descriptor
                int newSock = getSocket ( host, port );
                setNonblocking ( newSock );

                memset ( &ev, 0, sizeof ev );
                ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
                ev.data.fd = newSock;
                if ( epoll_ctl ( epfd, EPOLL_CTL_ADD, newSock, &ev ) < 0 ) {
                    fprintf ( stderr, "epoll_ctl()\n" );
                    exit ( 3 );
                }
            }

        }
    }
    return 0;
}
::::::::::::::
getSocket.c
::::::::::::::
/*
 * $Id: getSocket.c,v 1.4 2008/11/23 13:24:02 ykishi Exp ykishi $
 */

#include "getSocket.h"

int
getSocket ( char *hostname, int portNumber ) {

    struct sockaddr_in addr;
    struct hostent *he;
    int sock;

    if ( hostname == NULL ) {
        perror ( "host is undefined!" );
        exit ( 1 );
    }

    if ( ( sock = socket ( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) {
        perror ( "socket" );
        exit ( 2 );
    }

    bzero ( ( char * ) &addr, sizeof ( addr ) );

    if ( ( he = gethostbyname ( hostname ) ) == NULL ) {
        perror ( "No such host" );
        exit ( 3 );
    }
    bcopy ( he->h_addr, &addr.sin_addr, he->h_length );
    addr.sin_family = AF_INET;
    addr.sin_port = htons ( portNumber );

    if ( connect ( sock, ( struct sockaddr * ) &addr, sizeof ( addr ) ) < 0 ) {
        perror ( "connect" );
        exit ( 4 );
    }

    return sock;
}
::::::::::::::
setNonblocking.c
::::::::::::::
#include "setNonblocking.h"

/**
* $Source: /home/ykishi/C-test/epoll-client/RCS/setNonblocking.c,v $
*/

void
setNonblocking ( int sock ) {
    int flag = fcntl ( sock, F_GETFL, 0 );
    fcntl ( sock, F_SETFL, flag | O_NONBLOCK );
}
[ykishi@foo-bar-machine epoll-client]$

[ykishi@foo-bar-machine epoll-client]$ ./epoll-client 10.181.168.72 80 / 100
... snip ...

*** now polling *** i=22
write_len=42
read_len=366
*** now polling *** i=23
write_len=42
*** now polling *** i=24
write_len=42
*** now polling *** i=25
write_len=42
read_len=366
*** now polling *** i=26
write_len=42
read_len=366
*** now polling *** i=27
write_len=42
*** now polling *** i=28
write_len=42
*** now polling *** i=29
write_len=42
read_len=366
*** now polling *** i=30

[root@foo-bar-machine logs]# tail -f access_log
... snip ...
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"
10.181.168.72 - - [24/Nov/2008:13:54:44 +0900] "GET / HTTP/1.1" 200 103 "-" "-"


return
[PR]ŠΕŒμŽt‚̍DπŒ‹l‚Θ‚η:“]E‚ΜΜίΫ‚ͺ»Ξ߰āI”NŠΤ5–œl‚ͺ—˜—p