e-poll服务器编程综合

一、e-poll服务器代码

#include
#include
#include
#include
#include
#include
#include
#include

static void Usage(const char *str)
{
    printf("Usage:%s [serv_ip][serv_port]\n",str);
}

typedef struct fd_buf  //struct epoll_event ev  ev.data.ptr 指向这个结构体。
{
    int fd;
    char buf[10240]; //每一个套接字都有自己的缓冲区。
}fd_buf_t,*fd_buf_p;


static void* alloc_fd_buf(int fd)
{
    fd_buf_p tmp = (fd_buf_p)malloc(sizeof(fd_buf_t));
    if(tmp == NULL)
    {
        perror("malloc");
        return NULL;
    }
    tmp->fd = fd;
    return tmp;
}


static int startup(const char *ip,int port)
{
    int listen_socket = socket(AF_INET,SOCK_STREAM,0);
    if(listen_socket < 0)
    {
        perror("socket");
        exit(1);
    }
    int op = 1;
    setsockopt(listen_socket,SOL_SOCKET,SO_REUSEADDR,&op,sizeof(op)); //端口复用

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(ip);
    serv_addr.sin_port = htons(port);

    int ret = bind(listen_socket,(struct sockaddr*)&serv_addr,sizeof(serv_addr)  );
    if(ret < 0)
    {
        perror("bind");
        exit(2);
    }

    ret = listen(listen_socket,128);
    if(ret < 0)
    {
        perror("listen");
        exit(3);
    }
    return listen_socket;
}

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

    if(argc != 3)
    {
        Usage(argv[0]);
        return 1;
    }

    int listen_sock = startup(argv[1],atoi(argv[2]));

    int epollfd = epoll_create(256);//建议操作系统创建一个有256个节点的红黑树。
    if(epollfd < 0)
    {
        perror("epoll_create");
        close(listen_sock);
        return 5;
    }

    struct epoll_event ev;
    ev.events = EPOLLIN; //监听listen_socket的可读事件。
    ev.data.ptr = alloc_fd_buf(listen_sock); //每一个fd都分配自己的空间。

    int ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,listen_sock,&ev);//将listen_sock加入到红黑树中,并且监听它的可读事件。


    int nums = 0;
    struct epoll_event evs[64];
    int timeout = -1;

    while(1)
    {
        switch(  (nums = epoll_wait(epollfd,evs,64,timeout) )  )  //红黑树中就绪的节点放入循环队列中,把队列中的事件放入epoll_event数组中。它不会修改红黑树的节点和定时器,所以不需要每次都重新初始化。
        {
            case -1:
                perror("epoll_wait");
                break;
            case 0:
                printf("timeout....!\n");
                break;
            default:
                {
                    int i = 0;
                    for(; i < nums; ++i) //遍历数组,这个数组的元素都是就绪的。
                    {
                        fd_buf_p fp =  (fd_buf_p)evs[i].data.ptr; //ptr指向一个结构,这个结构中包含了一个文件描述符和一块空间。

                        if(fp->fd == listen_sock &&(evs[i].events & EPOLLIN))
                        {
                            struct sockaddr_in clie_addr;
                            socklen_t len = sizeof(clie_addr);

                            int new_sock = accept(listen_sock, (struct sockaddr*)&clie_addr,&len);
                            if(new_sock < 0)
                            {
                                perror("accept");
                                continue;
                            }
                            printf("get a new client\n");

                            struct epoll_event temp;
                            temp.events = EPOLLIN;
                            temp.data.ptr = alloc_fd_buf(new_sock); //将连接套接字加入到红黑树中
                            epoll_ctl(epollfd,EPOLL_CTL_ADD,new_sock,&temp);
                        }//if
                        else if(fp->fd != listen_sock)
                        {
                            if(evs[i].events & EPOLLIN) //可读事件。
                            {
                                ssize_t s = read(fp->fd,fp->buf,sizeof(fp->buf)-1); //
                                if(s > 0)
                                {
                                    fp->buf[s] = 0; //从标准输入中读取s需要减一,其他情况下不需要。
                                    printf("client say:%s\n",fp->buf);
                                    //读完后让这个套接字成为写状态。
                                    struct epoll_event temp;
                                    temp.events = EPOLLOUT;
                                    temp.data.ptr = fp;

                                    epoll_ctl(epollfd,EPOLL_CTL_MOD,fp->fd,&temp);
                                }
                                else if (s <= 0)
                                {
                                    close(fp->fd);
                                    epoll_ctl(epollfd,EPOLL_CTL_DEL,fp->fd,NULL);
                                    free(fp);
                                }

                            } //if 可读事件。
                            else if(evs[i].events & EPOLLOUT) //可写事件。
                            {
                                const char *msg = "HTTP/1.0 200 OK\r\n\r\n

hello epoll!

"
; write(fp->fd,msg, strlen(msg)); close(fp->fd); epoll_ctl(epollfd,EPOLL_CTL_DEL,fp->fd,NULL); free(fp); } } } //for finish; break; } //default finish } } return 0; }

二、e-poll服务器优点

(1)支持一个进程打开大数目的socket描述符(FD) 
(2)IO效率不随FD数目增加而线性下降 
(3)使用mmap加速内核与用户空间的消息传递。

你可能感兴趣的:(编程脚印,服务器,编程)