StarTrack

导航

Linux网络通信模型实践

  Linux的网络通信模型主要有迭代模型,fork子进程模型,多线程模型和io多路转接模型,迭代模型不能支持并发请求,fork子进程模型在并发数较高时性能开销比较大,所以不介绍这两种模型。

  1、创建线程池模型,同时accpet。然后accept加锁

void *threadFunc_1(void *arg)
{
    int thrId = *((int *)arg);
    int connect_fd;
    char rcvBuf[MAXLEN];
    int nCount;

    for(;;){
        pthread_mutex_lock(&mlock);
        //printf("SERVER: [%d] accept.\n", thrId);
        if( (connect_fd = accept(socket_fd, NULL, NULL)) == -1){
            printf("accept socket error: %s\n", strerror(errno));
            pthread_mutex_unlock(&mlock);
            exit(-1);
        }
        pthread_mutex_unlock(&mlock);

        pthread_mutex_lock(&nlock);
        nCount = ++connCount;
        if(connCount > CONNMAX){
            --connCount;
            pthread_mutex_unlock(&nlock);
            //xsend(connect_fd, replyBuf, strlen(replyBuf));
            //shutdown(connect_fd, SHUT_WR);
            //read(connect_fd, NULL, MAXLEN);
            close(connect_fd);
            printf("Server: connection full!\n");
            continue;
        }
        pthread_mutex_unlock(&nlock);
        printf("SERVER: [%d] new client connected, current connected count: %d\n", thrId, nCount);

        for(;;){
            int ret = transfer(connect_fd, thrId, rcvBuf);
            if(ret < 0){
                close(connect_fd);
                break;
            }
        }
        pthread_mutex_lock(&nlock);
        nCount = --connCount;
        pthread_mutex_unlock(&nlock);
        printf("SERVER: [%d] client logout, current connected count: %d\n", thrId, nCount);
    }

    return 0;
}

  2、主线程accpet,动态创建线程(短连接时开销太大)

for(;;){
        int connect_fd;
        if( (connect_fd = accept(socket_fd, NULL, NULL)) == -1){
            printf("accept socket error: %s\n", strerror(errno));
            exit(-1);
        }

        int nCount;
        pthread_mutex_lock(&nlock);
        nCount = ++connCount;
        if(connCount > CONNMAX){
            --connCount;
            pthread_mutex_unlock(&nlock);
            //xsend(connect_fd, replyBuf, strlen(replyBuf));
            //shutdown(connect_fd, SHUT_WR);
            //read(connect_fd, NULL, MAXLEN);
            close(connect_fd);
            printf("Server: connection full!\n");
            continue;
        }
        pthread_mutex_unlock(&nlock);
        printf("SERVER: new client[%d] connected, current connected count: %d\n", connect_fd, nCount);

        pthread_t thread;
        pthread_create(&thread, NULL, threadFunc_2, &connect_fd);
    }

//.....

void *threadFunc_2(void *arg)
{
    int connect_fd = *((int *)arg);
    int nCount;
    char rcvBuf[MAXLEN];
    pthread_detach(pthread_self());

    for(;;){
        int ret = transfer(connect_fd, -1, rcvBuf);
        if(ret < 0){
            close(connect_fd);
            break;
        }
    }
    pthread_mutex_lock(&nlock);
    nCount = --connCount;
    pthread_mutex_unlock(&nlock);
    printf("SERVER: client[%d] logout, current connected count: %d\n", connect_fd, nCount);

    return 0;
}

  3、io多路转接模型(使用epoll)

void *threadFunc_3(void *arg)
{
    pthread_detach(pthread_self());
    prctl(PR_SET_NAME, "threadFunc_3", 0, 0, 0);

    int ret = 0;
    int connect_fd = 0;
    int epfd = epoll_create(CONNMAX);
    unsigned int session_count = 0;
    struct epoll_event ev, events[CONNMAX];

    setNonBlocking(socket_fd);
    ev.data.fd = socket_fd;
    ev.events = EPOLLIN/* | EPOLLET*/;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &ev);
    if(ret < 0){
        verbose("epoll_ctl: %s\n", strerror(errno));
    }

    for(;;){
        int nfds = epoll_wait(epfd, events, CONNMAX, -1);
        if(nfds == -1){
            perror("threadFunc_3: epoll_wait");
            goto ERREXIT;
        }
        for(int i = 0; i < nfds; i++){
            if(events[i].data.fd == socket_fd){
                connect_fd = accept(socket_fd, NULL, NULL);
                if(connect_fd == -1){
                    perror("threadFunc_3: accept socket error");
                    goto ERREXIT;
                }

                struct timeval tv;
                gettimeofday(&tv, NULL);
                unsigned long uid = (tv.tv_sec%3600)*1000000 + tv.tv_usec;
                EventDataSt *data = (EventDataSt *)malloc(sizeof(EventDataSt));
                bzero(data, sizeof(EventDataSt));
                data->socket_fd = connect_fd;
                data->uid = uid;

                setNonBlocking(connect_fd);
                setSocketBuffer(connect_fd);

                ev.data.ptr = data;
                ev.events = EPOLLIN/* | EPOLLET*/;
                ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connect_fd, &ev);
                if(ret < 0){
                    verbose("epoll_ctl: %s\n", strerror(errno));
                }
                session_count++;
                //printf("SERVER: new connection[%lu]! session_count[%d]\n", uid, session_count);
            }else if(events[i].events & EPOLLIN){
                EventDataSt *eventData = (EventDataSt *)(events[i].data.ptr);
                connect_fd = eventData->socket_fd;
                bzero(&(eventData->data), MAXLEN);
                eventData->len = 0;

                ret = xrecv(connect_fd, eventData->data, MAXLEN);
                if(ret <= 0){
                    session_count--;
                    closeSession(epfd, connect_fd, eventData);
                    eventData = nullptr;
                }else{
                    eventData->len = ret;
                    ev.data.ptr = eventData;
                    ev.events = EPOLLOUT/* | EPOLLET*/;
                    ret = epoll_ctl(epfd, EPOLL_CTL_MOD, connect_fd, &ev);
                    if(ret < 0){
                        verbose("epoll_ctl: %s\n", strerror(errno));
                    }
                    char idBuf[8];
                    memcpy(idBuf, eventData->data, 8);
                }
            }else if(events[i].events & EPOLLOUT){
                bool bClose = false;
                EventDataSt *eventData = (EventDataSt *)(events[i].data.ptr);
                connect_fd = eventData->socket_fd;

                {
                    ret = xsend(connect_fd, eventData->data, eventData->len);
                    if(ret <= 0){
                        bClose = true;

                        session_count--;
                        closeSession(epfd, connect_fd, eventData);
                        eventData = nullptr;
                    }
                }
                if(!bClose){
                    ev.data.ptr = eventData;
                    ev.events = EPOLLIN/* | EPOLLET*/;
                    ret = epoll_ctl(epfd, EPOLL_CTL_MOD, connect_fd, &ev);
                    if(ret < 0){
                        verbose("epoll_ctl: %s\n", strerror(errno));
                    }
                }
            }
        }
    }

ERREXIT:
    close(epfd);
    close(socket_fd);
    exit(EXIT_FAILURE);
}

 

posted on 2017-06-07 13:45  StarTrack  阅读(456)  评论(0)    收藏  举报