简单的epoll echo server,使用et模式

直接上代码:

#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/epoll.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <errno.h>

#define MAX_EVENTS 200
#define PORT 8000

typedef struct  {
    int fd;
    bool canread;
    bool canwrite;
    bool closeFlag;
} TcpConn;

// 设置socket连接为非阻塞模式
void setnonblocking(int sockfd)
{
    int opts;

    opts = fcntl(sockfd, F_GETFL);
    if (opts < 0) {
        perror("fcntl(F_GETFL)\n");
        exit(1);
    }
    opts = (opts | O_NONBLOCK);
    if (fcntl(sockfd, F_SETFL, opts) < 0) {
        perror("fcntl(F_SETFL)\n");
        exit(1);
    }
}

void closeConnection(int epfd,TcpConn *conn)
{
    printf("connection closed.\n");
    epoll_ctl(epfd, EPOLL_CTL_DEL, conn->fd, NULL);
    close(conn->fd);
    free(conn);
}

int writeData(TcpConn *conn,char *buf,int len)
{
    int nwrite, ptr = 0;

    while (len > 0) {
        nwrite = write(conn->fd, buf + ptr, len);
        if (nwrite < len) {
            if (nwrite == -1 && errno != EAGAIN) {
                conn->closeFlag = true;
                break;
            }
            if (nwrite == -1 && errno == EAGAIN) {
                conn->canwrite = false;
                break;
            }
        }
        len -= nwrite;
        ptr += nwrite;
    }

    return ptr;
}

int readData(TcpConn *conn,char *buf,int bufSize)
{
    int nread, ptr = 0;

    while ((nread = read(conn->fd, buf, bufSize - 1 - ptr)) > 0) {
        ptr += nread;
    }

    if (nread == -1 && errno == EAGAIN) {
        conn->canread = false;
    }
    if (nread==0) {
        conn->closeFlag = true;
    }
    if (nread == -1 && errno != EAGAIN) {
        conn->closeFlag = true;
    }

    return ptr;
}

int main()
{
    struct epoll_event ev, events[MAX_EVENTS];
    int addrlen, listenfd, conn_sock, nfds, epfd, fd, i;
    struct sockaddr_in local, remote;
    char buf[BUFSIZ];

    // 创建listen socket
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("sockfd\n");
        exit(1);
    }
    setnonblocking(listenfd);
    bzero(&local, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = htonl(INADDR_ANY); ;
    local.sin_port = htons(PORT);
    if (bind(listenfd, (struct sockaddr*)&local, sizeof(local)) < 0) {
        perror("bind\n");
        exit(1);
    }
    listen(listenfd, MAX_EVENTS);

    epfd = epoll_create(MAX_EVENTS);
    if (epfd == -1) {
        perror("epoll_create");
        exit(EXIT_FAILURE);
    }

    TcpConn* listener = (TcpConn*)malloc(sizeof(TcpConn));
    listener->fd = listenfd;
    ev.events = EPOLLIN;
    ev.data.ptr = listener;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) {
        perror("epoll_ctl: listen_sock");
        exit(EXIT_FAILURE);
    }

    for (; ;) {
        nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            perror("epoll_pwait");
            exit(EXIT_FAILURE);
        }

        for (i = 0; i < nfds; ++i) {
            TcpConn* conn = (TcpConn*)events[i].data.ptr;
            fd = conn->fd;
            if (fd == listenfd) {
                while ((conn_sock = accept(listenfd, (struct sockaddr*)&remote,
                                           (socklen_t*)&addrlen)) > 0) {
                    setnonblocking(conn_sock);

                    // 接收缓冲区
                    int nRecvBuf=2*1024; // 设置为2K
                    setsockopt (conn_sock,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
                    // 发送缓冲区
                    int nSendBuf=2*1024; // 设置为2K
                    setsockopt (conn_sock,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

                    TcpConn* newConn = (TcpConn*)malloc(sizeof(TcpConn));
                    // printf("new conn: %p,  socket: %d\n",newConn,conn_sock);
                    if (newConn==NULL) {
                        perror("out of memory.");
                        exit(EXIT_FAILURE);
                    }
                    newConn->fd = conn_sock;
                    newConn->canread = false;
                    newConn->canwrite = false;
                    newConn->closeFlag = false;

                    ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
                    ev.data.ptr = newConn;
                    if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev)== -1) {
                        perror("epoll_ctl: add");
                        exit(EXIT_FAILURE);
                    }
                }
                if (conn_sock == -1) {
                    if (errno != EAGAIN && errno != ECONNABORTED && errno !=
                            EPROTO && errno != EINTR)
                        perror("accept");
                }
                continue;
            }

            if (events[i].events & EPOLLIN) {
                conn->canread = true;
                int len = readData(conn,buf,BUFSIZ);
                if (conn->closeFlag) {
                    closeConnection(epfd,conn);
                    continue;
                }
                if (len&&(conn->canwrite)) {
                    buf[len] = 0x00;
                    printf("send: %s",buf);
                    writeData(conn,buf,len);
                    if (conn->closeFlag) {
                        closeConnection(epfd,conn);
                        continue;
                    }
                }
            }
            if (events[i].events & EPOLLOUT) {
                conn->canwrite = true;
            }
        }
    }

    return 0;
}

 

posted @ 2015-09-28 17:09  cy99  阅读(303)  评论(0编辑  收藏  举报