epoll---简单服务器

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <strings.h>
#include <errno.h>
#include <error.h>
#include <poll.h>

#define LISTENQ 20
#define OPEN_MAX 128
#define TIMEOUT_EPOLL -1
#define MAX_MESSAGE_SIZE 1024

unsigned int current_connect=0;
int epollAccept(int epfd,int servfd,struct sockaddr_in *clientAddr,socklen_t *addrlen);
int epollClient(int epfd,struct epoll_event *events);
int main(int argc,char *argv[]){

    int i=0;
    if(argc!=2){
        printf("%s <port>\n",argv[0]);
        exit(0);
    }
    /* 1.创建套接字 */
    int servfd=socket(AF_INET,SOCK_STREAM,0);
    if(servfd == -1){
        perror("socket");
        exit(0);
    }

    /* 2.设置套接字地址 */
    struct sockaddr_in servAddr,clientAddr;
    socklen_t addrlen = sizeof(servAddr);
    bzero(&servAddr,addrlen);
    bzero(&clientAddr,addrlen);
    servAddr.sin_family=AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi(argv[1]));

    /* 3.bind地址 */
    int err = bind(servfd,(struct sockaddr *)&servAddr,addrlen);
    if(err == -1){
        perror("bind");
    }

    /* 4/listen,服务器变为LISTEN状态 */
    err = listen(servfd,LISTENQ);
    if(err == -1){
        perror("listen");
    }

    /* 5.创建epfd描述符 */
    int epfd = epoll_create(1);

    /* 6.添加事件 */
    struct epoll_event ev;
    bzero(&ev,sizeof(ev));
    ev.data.fd = servfd;
    ev.events = EPOLLIN | EPOLLET;//可读事件(新的连接),边沿触发

    err = epoll_ctl(epfd,EPOLL_CTL_ADD,servfd,&ev);
    if(err == -1){
        perror("epoll_ctrl");
        exit(0);
    }

    /* 7.创建事件 */
    struct epoll_event events[OPEN_MAX];

    /* 8.等待事件 */
    while(1){
        int nfd = epoll_wait(epfd,events,current_connect+1,-1);
        //printf("nfd = %d\n",nfd);
        for(i=0;i<nfd;i++){
            /* 如果是servfd可读,即有新的连接,服务器处于SYN_RCVD状态 */
            //printf("now is event[%d]\n",i);
            if(events[i].data.fd == servfd){
                /* 接受连接,服务器状态变为:ESTABLISHED */
                epollAccept(epfd,servfd,&clientAddr,&addrlen);

            }else if(events[i].events&EPOLLIN){//如果是可读事件
                epollClient(epfd,&events[i]);
            }else{
                printf("fd = %d\n",events[i].data.fd);
                printf("没有理由运行到这里啊!\n");
            }
        }
    }

    return 0;
}
/**
 * @function:接收一个新的连接,加入epfd监听的队列
 *
 */
int epollAccept(int epfd,int servfd,struct sockaddr_in *clientAddr,socklen_t *addrlen){
    struct epoll_event ev;
    int clientfd = accept(servfd,(struct sockaddr *)clientAddr,addrlen);
    if(clientfd == -1){
        perror("accept");
    }else{
        char *str = inet_ntoa(clientAddr->sin_addr);
        printf("got a new connection:%s ,fd = %d!\n",str,clientfd);
        current_connect+=1;

        ev.data.fd = clientfd;
        ev.events = EPOLLIN | EPOLLET;
        epoll_ctl(epfd,EPOLL_CTL_ADD,clientfd,&ev);
    }
    return clientfd;
}

/**
 *@function:处理用户的数据
 *
 */
int epollClient(int epfd,struct epoll_event *events){
    struct epoll_event ev;
    char buf[MAX_MESSAGE_SIZE];
    int count=0;
    int sockfd = -1;

    if( (sockfd = events->data.fd) < 0)
        return -1;

    bzero(buf,MAX_MESSAGE_SIZE);
    if ( (count = read(sockfd, buf, MAX_MESSAGE_SIZE)) < 0) {
    /* 1.对端发送FIN后,还向这个套接字写会受到RST */
        if (errno == ECONNRESET) {
            epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);
            close(sockfd);
            current_connect--;
            events->data.fd = -1;
        }
        perror("read sockfd");
        return -2;
    }
    /* 2.对方发送了FIN,服务器读会返回0,应答后处于CLOSE_WAIT状态 */
    else if (count == 0){
        epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);
        close(sockfd);
        current_connect--;
        events->data.fd = -1;
        return -3;
    }
    /* 3.正常读数据 */
    buf[count]=0;           //添加结束符
    printf("recv :%s",buf); //打印接收的数据

    return 0;
}











猜你喜欢

转载自blog.csdn.net/qq_36337149/article/details/81488953
今日推荐