c1000k

c1000k_test-master

1. client.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>

#define MAX_PORTS 100

int main(int argc, char **argv){
    if(argc <=  2){
        printf("Usage: %s ip port\n", argv[0]);
        exit(0);
    }

    struct sockaddr_in addr;
    const char *ip = argv[1];
    int base_port = atoi(argv[2]);
    int opt = 1;
    int bufsize;
    socklen_t optlen;
    int connections = 0;

    memset(&addr, sizeof(addr), 0);
    addr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &addr.sin_addr);

    char tmp_data[10];
    int index = 0;
    while(1){
        if(++index >= MAX_PORTS){
            index = 0;
        }
        int port = base_port + index;
        //printf("connect to %s:%d\n", ip, port);

        addr.sin_port = htons((short)port);

        int sock;
        if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            goto sock_err;
        }
        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1){
            goto sock_err;
        }

        connections ++;

        if(connections % 1000 == 999){
            //printf("press Enter to continue: ");
            //getchar();
            printf("connections: %d, fd: %d\n", connections, sock);
        }
        usleep(1 * 1000);

        bufsize = 5000;
        setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
        setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
    }

    return 0;
sock_err:
    printf("connections: %d\n", connections);
    printf("error: %s\n", strerror(errno));
    return 0;
}
2. client_mutlport_epoll.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>


#define MAX_BUFFER        128
#define MAX_EPOLLSIZE    (384*1024)
#define MAX_PORT        4

#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)

int isContinue = 0;

static int ntySetNonblock(int fd) {
    int flags;

    flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0) return flags;
    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0) return -1;
    return 0;
}

static int ntySetReUseAddr(int fd) {
    int reuse = 1;
    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}

int main(int argc, char **argv) {
    if (argc <= 2) {
        printf("Usage: %s ip port\n", argv[0]);
        exit(0);
    }

    const char *ip = argv[1];
    int port = atoi(argv[2]);
    int connections = 0;
    char buffer[128] = {0};
    int i = 0, index = 0;

    struct epoll_event events[MAX_EPOLLSIZE];
    
    int epoll_fd = epoll_create(MAX_EPOLLSIZE);
    
    strcpy(buffer, " Data From MulClient\n");
        
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);

    struct timeval tv_begin;
    gettimeofday(&tv_begin, NULL);

    while (1) {
        //if (++index >= MAX_PORT) index = 0;
        
        struct epoll_event ev;
        int sockfd = 0;

        if (connections < 380000 && !isContinue) {
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd == -1) {
                perror("socket");
                goto err;
            }

            //ntySetReUseAddr(sockfd);
            addr.sin_port = htons(port+index);

            if (connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
                perror("connect");
                goto err;
            }
            ntySetNonblock(sockfd);
            ntySetReUseAddr(sockfd);

            sprintf(buffer, "Hello Server: client --> %d\n", connections);
            send(sockfd, buffer, strlen(buffer), 0);

            ev.data.fd = sockfd;
            ev.events = EPOLLIN | EPOLLOUT;
            epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev);
        
            connections ++;
        }
        //connections ++;
        if (connections % 1000 == 999 || connections >= 380000) {
            struct timeval tv_cur;
            memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
            
            gettimeofday(&tv_begin, NULL);

            int time_used = TIME_SUB_MS(tv_begin, tv_cur);
            printf("connections: %d, sockfd:%d, time_used:%d\n", connections, sockfd, time_used);

            int nfds = epoll_wait(epoll_fd, events, connections, 100);
            for (i = 0;i < nfds;i ++) {
                int clientfd = events[i].data.fd;

                if (events[i].events & EPOLLOUT) {
                    sprintf(buffer, "data from %d\n", clientfd);
                    send(sockfd, buffer, strlen(buffer), 0);
                } else if (events[i].events & EPOLLIN) {
                    char rBuffer[MAX_BUFFER] = {0};                
                    ssize_t length = recv(sockfd, rBuffer, MAX_BUFFER, 0);
                    if (length > 0) {
                        printf(" RecvBuffer:%s\n", rBuffer);

                        if (!strcmp(rBuffer, "quit")) {
                            isContinue = 0;
                        }
                        
                    } else if (length == 0) {
                        printf(" Disconnect clientfd:%d\n", clientfd);
                        connections --;
                        close(clientfd);
                    } else {
                        if (errno == EINTR) continue;

                        printf(" Error clientfd:%d, errno:%d\n", clientfd, errno);
                        close(clientfd);
                    }
                } else {
                    printf(" clientfd:%d, errno:%d\n", clientfd, errno);
                    close(clientfd);
                }
            }
        }

        usleep(1 * 1000);
    }

    return 0;

err:
    printf("error : %s\n", strerror(errno));
    return 0;
    
}



3.server.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/select.h>

#define MAX_PORTS 100

int main(int argc, char **argv){
    if(argc <  2){
        printf("Usage: %s port\n", argv[0]);
        exit(0);
    }

    struct sockaddr_in addr;
    const char *ip = "0.0.0.0";
    int opt = 1;
    int bufsize;
    socklen_t optlen;
    int connections = 0;
    int base_port = 7000;
    if(argc >= 2){
        base_port = atoi(argv[1]);
    }

    int server_socks[MAX_PORTS];

    int i;
    int port;
    for(i=0; i<MAX_PORTS; i++){
        port = base_port + i;
        memset(&addr, sizeof(addr), 0);
        addr.sin_family = AF_INET;
        addr.sin_port = htons((short)port);
        inet_pton(AF_INET, ip, &addr.sin_addr);

        int serv_sock;
        if((serv_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            goto sock_err;
        }
        if(setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1){
            goto sock_err;
        }
        if(bind(serv_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1){
            goto sock_err;
        }
        if(listen(serv_sock, 1024) == -1){
            goto sock_err;
        }

        server_socks[i] = serv_sock;
        printf("server listen on port: %d\n", port);
    }

    while(1){
        fd_set readset;
        FD_ZERO(&readset);
        int maxfd = 0;
        int i = 0;
        
        for(i=0; i<MAX_PORTS; i++){
            FD_SET(server_socks[i], &readset);
            if(server_socks[i] > maxfd){
                maxfd = server_socks[i];
            }
        }
        int ret = select(maxfd + 1, &readset, NULL, NULL, NULL);
        if(ret < 0){
            if(errno == EINTR){
                continue;
            }else{
                printf("select error! %s\n", strerror(errno));
                exit(0);
            }
        }
        if(ret == 0){
            continue;
        }

        for(i=0; i<MAX_PORTS; i++){
            if(!FD_ISSET(server_socks[i], &readset)){
                continue;
            }
            socklen_t addrlen = sizeof(addr);
            int sock = accept(server_socks[i], (struct sockaddr *)&addr, &addrlen);
            if(sock == -1){
                goto sock_err;
            }
            connections ++;
            if(connections % 1000 == 999){
                //printf("press Enter to continue: ");
                //getchar();
                printf("connections: %d, fd: %d\n", connections, sock);
            }

            bufsize = 5000;
            setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
            setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
        }
    }

    return 0;
sock_err:
    printf("connections: %d\n", connections);
    printf("error: %s\n", strerror(errno));
    return 0;
}


4.server_mulport_epoll.c


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/poll.h>

#include <errno.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>

#include <pthread.h>

#define SERVER_PORT        8080
#define SERVER_IP        "127.0.0.1"
#define MAX_BUFFER        128
#define MAX_EPOLLSIZE    100000
#define MAX_THREAD        80
#define MAX_PORT        100

#define CPU_CORES_SIZE    8

#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)

static int ntySetNonblock(int fd) {
    int flags;

    flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0) return flags;
    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0) return -1;
    return 0;
}

static int ntySetReUseAddr(int fd) {
    int reuse = 1;
    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}

static int ntySetAlive(int fd) {
    int alive = 1;
    int idle = 60;
    int interval = 5;
    int count = 2;

    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&alive, sizeof(alive));
    setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*)&idle, sizeof(idle));
    setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void*)&interval, sizeof(interval));
    setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void*)&count, sizeof(count));
}


/** **** ******** **************** thread pool **************** ******** **** **/

#define LL_ADD(item, list) { \
    item->prev = NULL; \
    item->next = list; \
    list = item; \
}

#define LL_REMOVE(item, list) { \
    if (item->prev != NULL) item->prev->next = item->next; \
    if (item->next != NULL) item->next->prev = item->prev; \
    if (list == item) list = item->next; \
    item->prev = item->next = NULL; \
}

typedef struct worker {    
    pthread_t thread;    
    int terminate;    
    struct workqueue *workqueue;    
    struct worker *prev;    
    struct worker *next;
} worker_t;

typedef struct job {    
    void (*job_function)(struct job *job);    
    void *user_data;    
    struct job *prev;    
    struct job *next;
} job_t;

typedef struct workqueue {    
    struct worker *workers;    
    struct job *waiting_jobs;    
    pthread_mutex_t jobs_mutex;    
    pthread_cond_t jobs_cond;
} workqueue_t;


static void *worker_function(void *ptr) {    
    worker_t *worker = (worker_t *)ptr;    
    job_t *job;    

    while (1) {            
        pthread_mutex_lock(&worker->workqueue->jobs_mutex);        
        while (worker->workqueue->waiting_jobs == NULL) {            
            if (worker->terminate) break;            
            pthread_cond_wait(&worker->workqueue->jobs_cond, &worker->workqueue->jobs_mutex);        
        }            
        if (worker->terminate) break;        
        job = worker->workqueue->waiting_jobs;        
        if (job != NULL) {            
            LL_REMOVE(job, worker->workqueue->waiting_jobs);        
        }        
        pthread_mutex_unlock(&worker->workqueue->jobs_mutex);        
            
        if (job == NULL) continue;    
        
        /* Execute the job. */        
        job->job_function(job);    
    }    
    
    free(worker);    
    pthread_exit(NULL);
}

int workqueue_init(workqueue_t *workqueue, int numWorkers) {    
    int i;    
    worker_t *worker;    
    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;    
    pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;    

    if (numWorkers < 1) numWorkers = 1;    
    
    memset(workqueue, 0, sizeof(*workqueue));    
    memcpy(&workqueue->jobs_mutex, &blank_mutex, sizeof(workqueue->jobs_mutex));    
    memcpy(&workqueue->jobs_cond, &blank_cond, sizeof(workqueue->jobs_cond));    

    for (i = 0; i < numWorkers; i++) {        
        if ((worker = malloc(sizeof(worker_t))) == NULL) {            
            perror("Failed to allocate all workers");            
            return 1;        
        }        

        memset(worker, 0, sizeof(*worker));        
        worker->workqueue = workqueue;        
        
        if (pthread_create(&worker->thread, NULL, worker_function, (void *)worker)) {            
            perror("Failed to start all worker threads");            
            free(worker);            
            return 1;        
        }        

        LL_ADD(worker, worker->workqueue->workers);    
    }    

    return 0;
}


void workqueue_shutdown(workqueue_t *workqueue) {    

    worker_t *worker = NULL;        
    for (worker = workqueue->workers; worker != NULL; worker = worker->next) {        
        worker->terminate = 1;    
    }    


    pthread_mutex_lock(&workqueue->jobs_mutex);    
    workqueue->workers = NULL;    
    workqueue->waiting_jobs = NULL;    
    pthread_cond_broadcast(&workqueue->jobs_cond);    
    pthread_mutex_unlock(&workqueue->jobs_mutex);

}


void workqueue_add_job(workqueue_t *workqueue, job_t *job) {    

    pthread_mutex_lock(&workqueue->jobs_mutex);    

    LL_ADD(job, workqueue->waiting_jobs);    

    pthread_cond_signal(&workqueue->jobs_cond);    
    pthread_mutex_unlock(&workqueue->jobs_mutex);

}

static workqueue_t workqueue;
void threadpool_init(void) {
    workqueue_init(&workqueue, MAX_THREAD);
}


/** **** ******** **************** thread pool **************** ******** **** **/

typedef struct client {
    int fd;
    char rBuffer[MAX_BUFFER];
    int length;
} client_t;

void *client_cb(void *arg) {
    int clientfd = *(int *)arg;
    char buffer[MAX_BUFFER] = {0};

    int childpid = getpid();

    while (1) {
        bzero(buffer, MAX_BUFFER);
        ssize_t length = recv(clientfd, buffer, MAX_BUFFER, 0); //bio
        if (length > 0) {
            //printf(" PID:%d --> buffer: %s\n", childpid, buffer);

            int sLen = send(clientfd, buffer, length, 0);
            //printf(" PID:%d --> sLen: %d\n", childpid, sLen);
        } else if (length == 0) {
            printf(" PID:%d client disconnect\n", childpid);
            break;
        } else {
            printf(" PID:%d errno:%d\n", childpid, errno);
            break;
        }
    }
}


static int nRecv(int sockfd, void *data, size_t length, int *count) {
    int left_bytes;
    int read_bytes;
    int res;
    int ret_code;

    unsigned char *p;

    struct pollfd pollfds;
    pollfds.fd = sockfd;
    pollfds.events = ( POLLIN | POLLERR | POLLHUP );

    read_bytes = 0;
    ret_code = 0;
    p = (unsigned char *)data;
    left_bytes = length;

    while (left_bytes > 0) {

        read_bytes = recv(sockfd, p, left_bytes, 0);
        if (read_bytes > 0) {
            left_bytes -= read_bytes;
            p += read_bytes;
            continue;
         } else if (read_bytes < 0) {
            if (!(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
                ret_code = (errno != 0 ? errno : EINTR);
            }
        } else {
            ret_code = ENOTCONN;
            break;
        }
        
        res = poll(&pollfds, 1, 5);
        if (pollfds.revents & POLLHUP) {
            ret_code = ENOTCONN;
            break;
        }
        if (res < 0) {
            if (errno == EINTR) {
                continue;
            }
            ret_code = (errno != 0 ? errno : EINTR);
        } else if (res == 0) {
            ret_code = ETIMEDOUT;
            break;
        }

    }

    if (count != NULL) {
        *count = length - left_bytes;
    }
    //printf("nRecv:%s, ret_code:%d, count:%d\n", (char*)data, ret_code, *count);


    return ret_code;
}

void epoll_et_loop(int sockfd)
{
    char buffer[MAX_BUFFER];
    int ret;

    while (1)
    {
        memset(buffer, 0, MAX_BUFFER);
        ret = recv(sockfd, buffer, MAX_BUFFER, 0);
        if (ret == -1)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                printf(" read all data\n");
                break;
            }
            close(sockfd);
            break;
        }
        else if (ret == 0)
        {
            printf(" disconnect\n");
            close(sockfd);
            break;
        }
        else
            printf("Recv:%s, %d Bytes\n", buffer, ret);
    }
    
}

static int nSend(int sockfd, const void *buffer, int length, int flags) {

    int wrotelen = 0;
    int writeret = 0;

    unsigned char *p = (unsigned char *)buffer;

    struct pollfd pollfds = {0};
    pollfds.fd = sockfd;
    pollfds.events = ( POLLOUT | POLLERR | POLLHUP );

    do {
        int result = poll( &pollfds, 1, 5);
        if (pollfds.revents & POLLHUP) {
            
            printf(" ntySend errno:%d, revent:%x\n", errno, pollfds.revents);
            return -1;
        }

        if (result < 0) {
            if (errno == EINTR) continue;

            printf(" ntySend errno:%d, result:%d\n", errno, result);
            return -1;
        } else if (result == 0) {
        
            printf(" ntySend errno:%d, socket timeout \n", errno);
            return -1;
        }

        writeret = send( sockfd, p + wrotelen, length - wrotelen, flags );
        if( writeret <= 0 )
        {
            break;
        }
        wrotelen += writeret ;

    } while (wrotelen < length);
    
    return wrotelen;
}


static int curfds = 1;
static int nRun = 0;
    

void client_job(job_t *job) {


    client_t *rClient = (client_t*)job->user_data;
    int clientfd = rClient->fd;

    char buffer[MAX_BUFFER];
    bzero(buffer, MAX_BUFFER);

    int length = 0;
    int ret = nRecv(clientfd, buffer, MAX_BUFFER, &length);
    if (length > 0) {    
        if (nRun || buffer[0] == 'a') {        
            printf(" TcpRecv --> curfds : %d, buffer: %s\n", curfds, buffer);
            
            nSend(clientfd, buffer, strlen(buffer), 0);
        }

    } else if (ret == ENOTCONN) {
        curfds --;
        close(clientfd);
    } else {
        
    }

    free(rClient);
    free(job);
}

void client_data_process(int clientfd) {

    char buffer[MAX_BUFFER];
    bzero(buffer, MAX_BUFFER);
    int length = 0;
    int ret = nRecv(clientfd, buffer, MAX_BUFFER, &length);
    if (length > 0) {    
        if (nRun || buffer[0] == 'a') {        
            printf(" TcpRecv --> curfds : %d, buffer: %s\n", curfds, buffer);
            
            nSend(clientfd, buffer, strlen(buffer), 0);
        }

    } else if (ret == ENOTCONN) {
        curfds --;
        close(clientfd);
    } else {
        
    }

}

int listenfd(int fd, int *fds) {
    int i = 0;

    for (i = 0;i < MAX_PORT;i ++) {
        if (fd == *(fds+i)) return *(fds+i);
    }
    return 0;
}

int main(void) {
    int i = 0;
    int sockfds[MAX_PORT] = {0};

    printf("C1000K Server Start\n");
    
    threadpool_init(); //

    int epoll_fd = epoll_create(MAX_EPOLLSIZE); 

    for (i = 0;i < MAX_PORT;i ++) {

        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            perror("socket");
            return 1;
        }

        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(struct sockaddr_in));
        
        addr.sin_family = AF_INET;
        addr.sin_port = htons(SERVER_PORT+i);
        addr.sin_addr.s_addr = INADDR_ANY;

        if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
            perror("bind");
            return 2;
        }

        if (listen(sockfd, 5) < 0) {
            perror("listen");
            return 3;
        }

        sockfds[i] = sockfd;
        printf("C1000K Server Listen on Port:%d\n", SERVER_PORT+i);

        struct epoll_event ev;
         
        ev.events = EPOLLIN | EPOLLET; //EPOLLLT
        ev.data.fd = sockfd;
        epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev);  
    }

    struct timeval tv_begin;
    gettimeofday(&tv_begin, NULL);
    
    struct epoll_event events[MAX_EPOLLSIZE];

    while (1) {

        int nfds = epoll_wait(epoll_fd, events, curfds, 5);  //是不是祕書給累死。
        if (nfds == -1) {
            perror("epoll_wait");
            break;
        }
        for (i = 0;i < nfds;i ++) {

            int sockfd = listenfd(events[i].data.fd, sockfds);
            if (sockfd) {
                struct sockaddr_in client_addr;
                memset(&client_addr, 0, sizeof(struct sockaddr_in));
                socklen_t client_len = sizeof(client_addr);
                
                int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
                if (clientfd < 0) {
                    perror("accept");
                    return 4;
                }
                
                if (curfds ++ > 1000 * 1000) {
                    nRun = 1;
                }
#if 0
                printf(" Client %d: %d.%d.%d.%d:%d \n", curfds, *(unsigned char*)(&client_addr.sin_addr.s_addr), *((unsigned char*)(&client_addr.sin_addr.s_addr)+1),                                                    
                            *((unsigned char*)(&client_addr.sin_addr.s_addr)+2), *((unsigned char*)(&client_addr.sin_addr.s_addr)+3),                                                    
                            client_addr.sin_port);
#elif 0
                if(curfds % 1000 == 999) {    
                    printf("connections: %d, fd: %d\n", curfds, clientfd);            
                }
#else
                if (curfds % 1000 == 999) {
                    struct timeval tv_cur;
                    memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
                    
                    gettimeofday(&tv_begin, NULL);

                    int time_used = TIME_SUB_MS(tv_begin, tv_cur);
                    printf("connections: %d, sockfd:%d, time_used:%d\n", curfds, clientfd, time_used);
                }
#endif
                ntySetNonblock(clientfd);
                ntySetReUseAddr(clientfd);

                struct epoll_event ev;
                ev.events = EPOLLIN | EPOLLET | EPOLLOUT;
                ev.data.fd = clientfd;
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, clientfd, &ev);

            } else {

                int clientfd = events[i].data.fd;
#if 1
                if (nRun) {
                    printf(" New Data is Comming\n");
                    client_data_process(clientfd);
                } else {

                //epoll_ctrl(epfd, EPOLL_CTL_DELe,vent[i].data.fd,ev);
                //poll 
                    client_t *rClient = (client_t*)malloc(sizeof(client_t));
                    memset(rClient, 0, sizeof(client_t));                
                    rClient->fd = clientfd;
                    
                    job_t *job = malloc(sizeof(job_t));
                    //工作隊列處理函數
                    job->job_function = client_job;
                    //工作隊列處理的IO
                    job->user_data = rClient;
                    workqueue_add_job(&workqueue, job);
                    //工作隊列 引入了一個線程池
                    //poll()
                    //epoll_ctrl(epfd, EPOLL_CTL_ADD, event[i].data.fd,&ev);
                }
#else
                client_data_process(clientfd);
                
#endif
            }
        }
        
    }
}




5.server_mulport_mulepoll.c


/*
 * author : wangbojing
 * email  : [email protected] 
 * 測試操作系統的併發量
 */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/poll.h>

#include <errno.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>

#include <pthread.h>

#define SERVER_PORT        8080
#define SERVER_IP        "127.0.0.1"
#define MAX_BUFFER        128
#define MAX_EPOLLSIZE    100000
#define MAX_THREAD        80
#define MAX_PORT        100

#define CPU_CORES_SIZE    8

#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)

static int ntySetNonblock(int fd) {
    int flags;

    flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0) return flags;
    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0) return -1;
    return 0;
}

static int ntySetReUseAddr(int fd) {
    int reuse = 1;
    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}

static int ntySetAlive(int fd) {
    int alive = 1;
    int idle = 60;
    int interval = 5;
    int count = 2;

    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&alive, sizeof(alive));
    setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*)&idle, sizeof(idle));
    setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void*)&interval, sizeof(interval));
    setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void*)&count, sizeof(count));
}


/** **** ******** **************** thread pool **************** ******** **** **/

#define LL_ADD(item, list) { \
    item->prev = NULL; \
    item->next = list; \
    list = item; \
}

#define LL_REMOVE(item, list) { \
    if (item->prev != NULL) item->prev->next = item->next; \
    if (item->next != NULL) item->next->prev = item->prev; \
    if (list == item) list = item->next; \
    item->prev = item->next = NULL; \
}

typedef struct worker {    
    pthread_t thread;    
    int terminate;    
    struct workqueue *workqueue;    
    struct worker *prev;    
    struct worker *next;
} worker_t;

typedef struct job {    
    void (*job_function)(struct job *job);    
    void *user_data;    
    struct job *prev;    
    struct job *next;
} job_t;

typedef struct workqueue {    
    struct worker *workers;    
    struct job *waiting_jobs;    
    pthread_mutex_t jobs_mutex;    
    pthread_cond_t jobs_cond;
} workqueue_t;


static void *worker_function(void *ptr) {    
    worker_t *worker = (worker_t *)ptr;    
    job_t *job;    

    while (1) {            
        pthread_mutex_lock(&worker->workqueue->jobs_mutex);        
        while (worker->workqueue->waiting_jobs == NULL) {            
            if (worker->terminate) break;            
            pthread_cond_wait(&worker->workqueue->jobs_cond, &worker->workqueue->jobs_mutex);        
        }            
        if (worker->terminate) break;        
        job = worker->workqueue->waiting_jobs;        
        if (job != NULL) {            
            LL_REMOVE(job, worker->workqueue->waiting_jobs);        
        }        
        pthread_mutex_unlock(&worker->workqueue->jobs_mutex);        
            
        if (job == NULL) continue;    
        
        /* Execute the job. */        
        job->job_function(job);    
    }    
    
    free(worker);    
    pthread_exit(NULL);
}

int workqueue_init(workqueue_t *workqueue, int numWorkers) {    
    int i;    
    worker_t *worker;    
    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;    
    pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;    

    if (numWorkers < 1) numWorkers = 1;    
    
    memset(workqueue, 0, sizeof(*workqueue));    
    memcpy(&workqueue->jobs_mutex, &blank_mutex, sizeof(workqueue->jobs_mutex));    
    memcpy(&workqueue->jobs_cond, &blank_cond, sizeof(workqueue->jobs_cond));    

    for (i = 0; i < numWorkers; i++) {        
        if ((worker = malloc(sizeof(worker_t))) == NULL) {            
            perror("Failed to allocate all workers");            
            return 1;        
        }        

        memset(worker, 0, sizeof(*worker));        
        worker->workqueue = workqueue;        
        
        if (pthread_create(&worker->thread, NULL, worker_function, (void *)worker)) {            
            perror("Failed to start all worker threads");            
            free(worker);            
            return 1;        
        }        

        LL_ADD(worker, worker->workqueue->workers);    
    }    

    return 0;
}


void workqueue_shutdown(workqueue_t *workqueue) {    

    worker_t *worker = NULL;        
    for (worker = workqueue->workers; worker != NULL; worker = worker->next) {        
        worker->terminate = 1;    
    }    


    pthread_mutex_lock(&workqueue->jobs_mutex);    
    workqueue->workers = NULL;    
    workqueue->waiting_jobs = NULL;    
    pthread_cond_broadcast(&workqueue->jobs_cond);    
    pthread_mutex_unlock(&workqueue->jobs_mutex);

}


void workqueue_add_job(workqueue_t *workqueue, job_t *job) {    

    pthread_mutex_lock(&workqueue->jobs_mutex);    

    LL_ADD(job, workqueue->waiting_jobs);    

    pthread_cond_signal(&workqueue->jobs_cond);    
    pthread_mutex_unlock(&workqueue->jobs_mutex);

}

static workqueue_t workqueue;
void threadpool_init(void) {
    workqueue_init(&workqueue, MAX_THREAD);
}


/** **** ******** **************** thread pool **************** ******** **** **/

typedef struct client {
    int fd;
    char rBuffer[MAX_BUFFER];
    int length;
} client_t;

void *client_cb(void *arg) {
    int clientfd = *(int *)arg;
    char buffer[MAX_BUFFER] = {0};

    int childpid = getpid();

    while (1) {
        bzero(buffer, MAX_BUFFER);
        ssize_t length = recv(clientfd, buffer, MAX_BUFFER, 0); //bio
        if (length > 0) {
            //printf(" PID:%d --> buffer: %s\n", childpid, buffer);

            int sLen = send(clientfd, buffer, length, 0);
            //printf(" PID:%d --> sLen: %d\n", childpid, sLen);
        } else if (length == 0) {
            printf(" PID:%d client disconnect\n", childpid);
            break;
        } else {
            printf(" PID:%d errno:%d\n", childpid, errno);
            break;
        }
    }
}


static int nRecv(int sockfd, void *data, size_t length, int *count) {
    int left_bytes;
    int read_bytes;
    int res;
    int ret_code;

    unsigned char *p;

    struct pollfd pollfds;
    pollfds.fd = sockfd;
    pollfds.events = ( POLLIN | POLLERR | POLLHUP );

    read_bytes = 0;
    ret_code = 0;
    p = (unsigned char *)data;
    left_bytes = length;

    while (left_bytes > 0) {

        read_bytes = recv(sockfd, p, left_bytes, 0);
        if (read_bytes > 0) {
            left_bytes -= read_bytes;
            p += read_bytes;
            continue;
         } else if (read_bytes < 0) {
            if (!(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
                ret_code = (errno != 0 ? errno : EINTR);
            }
        } else {
            ret_code = ENOTCONN;
            break;
        }
        
        res = poll(&pollfds, 1, 5);
        if (pollfds.revents & POLLHUP) {
            ret_code = ENOTCONN;
            break;
        }
        if (res < 0) {
            if (errno == EINTR) {
                continue;
            }
            ret_code = (errno != 0 ? errno : EINTR);
        } else if (res == 0) {
            ret_code = ETIMEDOUT;
            break;
        }

    }

    if (count != NULL) {
        *count = length - left_bytes;
    }
    //printf("nRecv:%s, ret_code:%d, count:%d\n", (char*)data, ret_code, *count);


    return ret_code;
}

void epoll_et_loop(int sockfd)
{
    char buffer[MAX_BUFFER];
    int ret;

    while (1)
    {
        memset(buffer, 0, MAX_BUFFER);
        ret = recv(sockfd, buffer, MAX_BUFFER, 0);
        if (ret == -1)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                printf(" read all data\n");
                break;
            }
            close(sockfd);
            break;
        }
        else if (ret == 0)
        {
            printf(" disconnect\n");
            close(sockfd);
            break;
        }
        else
            printf("Recv:%s, %d Bytes\n", buffer, ret);
    }
    
}

static int nSend(int sockfd, const void *buffer, int length, int flags) {

    int wrotelen = 0;
    int writeret = 0;

    unsigned char *p = (unsigned char *)buffer;

    struct pollfd pollfds = {0};
    pollfds.fd = sockfd;
    pollfds.events = ( POLLOUT | POLLERR | POLLHUP );

    do {
        int result = poll( &pollfds, 1, 5);
        if (pollfds.revents & POLLHUP) {
            
            printf(" ntySend errno:%d, revent:%x\n", errno, pollfds.revents);
            return -1;
        }

        if (result < 0) {
            if (errno == EINTR) continue;

            printf(" ntySend errno:%d, result:%d\n", errno, result);
            return -1;
        } else if (result == 0) {
        
            printf(" ntySend errno:%d, socket timeout \n", errno);
            return -1;
        }

        writeret = send( sockfd, p + wrotelen, length - wrotelen, flags );
        if( writeret <= 0 )
        {
            break;
        }
        wrotelen += writeret ;

    } while (wrotelen < length);
    
    return wrotelen;
}


static int curfds = 1;
static int nRun = 0;
int sockfds[MAX_PORT] = {0};
    

void client_job(job_t *job) {


    client_t *rClient = (client_t*)job->user_data;
    int clientfd = rClient->fd;

    char buffer[MAX_BUFFER];
    bzero(buffer, MAX_BUFFER);

    int length = 0;
    int ret = nRecv(clientfd, buffer, MAX_BUFFER, &length);
    if (length > 0) {    
        if (nRun || buffer[0] == 'a') {        
            printf(" TcpRecv --> curfds : %d, buffer: %s\n", curfds, buffer);
            
            nSend(clientfd, buffer, strlen(buffer), 0);
        }

    } else if (ret == ENOTCONN) {
        curfds --;
        close(clientfd);
    } else {
        
    }

    free(rClient);
    free(job);
}

void client_data_process(int clientfd) {

    char buffer[MAX_BUFFER];
    bzero(buffer, MAX_BUFFER);
    int length = 0;
    //int ret = nRecv(clientfd, buffer, MAX_BUFFER, &length);
    int ret = recv(clientfd, buffer, MAX_BUFFER, 0);
    if (length > 0) {    
        if (nRun || buffer[0] == 'a') {        
            printf(" TcpRecv --> curfds : %d, buffer: %s\n", curfds, buffer);
            
            //nSend(clientfd, buffer, strlen(buffer), 0);
            send(clientfd, buffer, strlen(buffer), 0);
        }

    } else if (ret == ENOTCONN) {
        curfds --;
        close(clientfd);
    } else {
        
    }

}

int listenfd(int fd, int *fds) {
    int i = 0;

    for (i = 0;i < MAX_PORT;i ++) {
        if (fd == *(fds+i)) return *(fds+i);
    }
    return 0;
}

struct timeval tv_begin;
struct timeval tv_cur;

void *listen_thread(void *arg) {

    int i = 0;
    int epoll_fd = *(int *)arg;
    struct epoll_event events[MAX_EPOLLSIZE];

    
    gettimeofday(&tv_begin, NULL);

    while (1) {

        int nfds = epoll_wait(epoll_fd, events, curfds, 5);  
        if (nfds == -1) {
            perror("epoll_wait");
            break;
        }
        for (i = 0;i < nfds;i ++) {

            int sockfd = listenfd(events[i].data.fd, sockfds);
            if (sockfd) {
                struct sockaddr_in client_addr;
                memset(&client_addr, 0, sizeof(struct sockaddr_in));
                socklen_t client_len = sizeof(client_addr);
                
                int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
                if (clientfd < 0) {
                    perror("accept");
                    return NULL;
                }
                
                if (curfds ++ > 1000 * 1000) {
                    nRun = 1;
                }
#if 0
                printf(" Client %d: %d.%d.%d.%d:%d \n", curfds, *(unsigned char*)(&client_addr.sin_addr.s_addr), *((unsigned char*)(&client_addr.sin_addr.s_addr)+1),                                                    
                            *((unsigned char*)(&client_addr.sin_addr.s_addr)+2), *((unsigned char*)(&client_addr.sin_addr.s_addr)+3),                                                    
                            client_addr.sin_port);
#elif 0
                if(curfds % 1000 == 999) {    
                    printf("connections: %d, fd: %d\n", curfds, clientfd);            
                }
#else
                if (curfds % 1000 == 999) {
                    
                    memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
            
                    gettimeofday(&tv_begin, NULL);
                    int time_used = TIME_SUB_MS(tv_begin, tv_cur);
                    
                    printf("connections: %d, sockfd:%d, time_used:%d\n", curfds, clientfd, time_used);
                }
#endif
                ntySetNonblock(clientfd);
                ntySetReUseAddr(clientfd);

                struct epoll_event ev;
                ev.events = EPOLLIN | EPOLLET | EPOLLOUT;
                ev.data.fd = clientfd;
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, clientfd, &ev);

            } else {

                int clientfd = events[i].data.fd;
#if 0
                if (nRun) {
                    printf(" New Data is Comming\n");
                    client_data_process(clientfd);
                } else {
            
                    client_t *rClient = (client_t*)malloc(sizeof(client_t));
                    memset(rClient, 0, sizeof(client_t));                
                    rClient->fd = clientfd;
                    
                    job_t *job = malloc(sizeof(job_t));
                    job->job_function = client_job;
                    job->user_data = rClient;
                    workqueue_add_job(&workqueue, job);
                    
                    
                }
#else
                client_data_process(clientfd);
#endif
            }
        }
        
    }
    
}

int main(void) {
    int i = 0;

    printf("C1000K Server Start\n");
    
    threadpool_init(); //


#if 0
    int epoll_fd = epoll_create(MAX_EPOLLSIZE); 
#else

    int epoll_fds[CPU_CORES_SIZE] = {0};
    pthread_t thread_id[CPU_CORES_SIZE] = {0};

    for (i = 0;i < CPU_CORES_SIZE;i ++) {
        epoll_fds[i] = epoll_create(MAX_EPOLLSIZE);

        pthread_create(&thread_id[i], NULL, listen_thread, &epoll_fds[i]);
    }


#endif
    for (i = 0;i < MAX_PORT;i ++) {

        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            perror("socket");
            return 1;
        }

        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(struct sockaddr_in));
        
        addr.sin_family = AF_INET;
        addr.sin_port = htons(SERVER_PORT+i);
        addr.sin_addr.s_addr = INADDR_ANY;

        if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
            perror("bind");
            return 2;
        }

        if (listen(sockfd, 5) < 0) {
            perror("listen");
            return 3;
        }

        sockfds[i] = sockfd;
        printf("C1000K Server Listen on Port:%d\n", SERVER_PORT+i);

        struct epoll_event ev;
         
        ev.events = EPOLLIN | EPOLLET; //EPOLLLT
        ev.data.fd = sockfd;
        epoll_ctl(epoll_fds[i%CPU_CORES_SIZE], EPOLL_CTL_ADD, sockfd, &ev);  
    }

    for (i = 0;i < CPU_CORES_SIZE;i ++) {
        pthread_join(thread_id[i], NULL);
    }


    getchar();
    printf("end\n");
}








 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章