UNIX TCP回射服务器/客户端(4)

程序简介:这是一个运用epoll系列函数进行IO复用的服务器模型。它是目前UNIX与LINUX平台上效率最高,最受欢迎的IO复用传输模型。

上代码:

#include "my_unp.h" 
 
int main(void)   
{   
    int listenfd, connfd, sockfd, epfd; 
    int i, maxi, nfds; 
    ssize_t n;   
    char buf[MAXLINE];   
    socklen_t clilen;   
    struct sockaddr_in cliaddr;   
    struct sockaddr_in servaddr; 
 
    //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件   
    struct epoll_event ev, events[256];   
 
    //创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大   
    epfd = Epoll_create(256); 
 
    //创建用于TCP协议的套接字     
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);   
    memset(&servaddr, 0, sizeof(servaddr));   
    servaddr.sin_family = AF_INET;   
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);   
    servaddr.sin_port = htons(SERV_PORT);   
 
    //把socket和socket地址结构联系起来   
    Bind(listenfd, (SA*)&servaddr, sizeof(servaddr)); 
    //开始监听LISTENQ端口   
    Listen(listenfd, LISTENQ); 
 
    //设置与要处理的事件相关的文件描述符和事件 
    ev.data.fd = listenfd;   
    ev.events = EPOLLIN|EPOLLET;   
 
    //注册epoll事件   
    Epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd,&ev);   
    maxi = 0; 
 
    while(1) 
    {   
        //等待epoll事件的发生   
        //返回需要处理的事件数目nfds,如返回0表示已超时。   
        nfds = Epoll_wait(epfd, events, 20, 500);   
 
        //处理所发生的所有事件   
        for(i=0; i < nfds; ++i)   
        {   
            //如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。   
            if(events[i].data.fd == listenfd)   
            {   
                connfd = Accept(listenfd,(SA*)&cliaddr, &clilen);   
                printf("connection from %s, port %d.\n",       
                    Inet_ntop(AF_INET, (void*)&cliaddr.sin_addr, buf, sizeof(buf)),       
                    ntohs(cliaddr.sin_port));   
 
                //设置用于读操作的文件描述符和事件 
                ev.data.fd = connfd;   
                ev.events = EPOLLIN|EPOLLET;   
 
                //注册事件 
                Epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); 
            }   
 
            //如果是已经连接的用户,并且收到数据,那么进行读入。   
            else if(events[i].events & EPOLLIN)   
            {   
                sockfd = events[i].data.fd; 
                if ( sockfd < 0 )   
                    continue;   
                n = read(sockfd, buf, MAXLINE); 
                if ( n < 0)   
                {     
                    // Connection Reset:你连接的那一端已经断开了, 
                    //而你却还试着在对方已断开的socketfd上读写数据!   
                    if (errno == ECONNRESET)   
                    {   
                        Close(sockfd);   
                        events[i].data.fd = -1;   
                    }   
                    else   
                        error_quit("read error"); 
                }   
                //如果读入的数据为空   
                else if ( n == 0 ) 
                {   
                    Close(sockfd);   
                    events[i].data.fd = -1;   
                }   
                else 
                { 
                    //设置用于写操作的文件描述符和事件 
                    ev.data.fd = sockfd; 
                    ev.events = EPOLLOUT|EPOLLET; 
                    //注册事件 
                    Epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); 
                } 
            } 
 
            //如果有数据发送 
            else if(events[i].events & EPOLLOUT) 
            { 
                sockfd = events[i].data.fd; 
                Writen(sockfd, buf, n);   
 
                //设置用于读操作的文件描述符和事件 
                ev.data.fd = sockfd; 
                ev.events = EPOLLIN|EPOLLET; 
 
                //注册事件 
                Epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); 
            } 
        } 
    } 
    return 0;   

与其配套的客户端在这里:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/705b6d211bf1cc988c7ad0b9b8966423.html