使用epoll创建tcp并发服务器流程

1.创建套接字  socket函数

2.设置套接字重用 setsockopt函数

3.绑定套接字 bind函数

4.建立监听 listen函数

5.创建一个epoll实例

        int epoll_creaet(1024)--->1024为最大描述符

        定义一个变量去接受他的返回值 int epfd = epoll_create(1024);

        将监听套接字放入epoll实例中 使用 struct epoll_event结构体

        设置为EPOLLIN事件。

        struct epoll_event events[1024] 用来存储检测到的事件和文件描述符的集合

        使用epoll_wait()循环检测 事件和文件描述符是否准备就绪

        对准备就绪的事件和文件描述符进行一一轮询

                判断是否为监听套接字,如果是监听套接字则建立新的通信连接

                        建立新链接 accept函数

                                连接成功则将通信套接字添加到epoll实例中

                如果为通信套接字,处理客户端的数据请求。

实例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>

#include <sys/epoll.h>

int main()
{
    int listenfd;
    int connfd;
    int ret;
    int i;
    int j;
    char buf[128];
    struct sockaddr_in srvaddr;
    struct sockaddr_in cltaddr;
    socklen_t addrlen;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == listenfd) {
        perror("socket");
        return -1;
    }
    printf("create socket success !\n");

    memset(&srvaddr, 0, sizeof(srvaddr));
    srvaddr.sin_family = AF_INET;
    srvaddr.sin_port = htons(8888);
#if 0
    inet_aton("192.168.5.135", &(srvaddr.sin_addr));
#else
    srvaddr.sin_addr.s_addr = inet_addr("0.0.0.0");
#endif
    ret = bind(listenfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
    if (-1 == ret) {
        perror("bind");
        return -1;
    }
    printf("srv bind success !\n");

    ret = listen(listenfd, 1024);
    if (-1 == ret) {
        perror("listen");
        return -1;
    }
    printf("listen success\n");

    int epfd;

    /* 创建一个epoll实例 */
    epfd = epoll_create(1024);    //1024表示的是某一个时间点期望检测到的最大个数;
    if (-1 == epfd) {
        perror("epoll_create");
        return -1;
    }

    /* 将所要关心的文件描述符listenfd添加到eoll实例中 */
    struct epoll_event event;    //需要添加的事件和文件描述符;
    event.events = EPOLLIN;        //事件
    event.data.fd = listenfd;    //文件描述符
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &event);
    if (-1 == ret ) {
        perror("epoll_ctl");
        return -1;
    }

    struct epoll_event events[1024];    //用来存储检测到的事件和文件描述符的集合(小于等于epoll实例所能处理最大数)
    while(1)
    {
        ret = epoll_wait(epfd, events, 1024, 5000);    //循环检测;
        if (ret == -1) {
            perror("epoll");
            return -1;
        }
#if 1
        else if (0 == ret) {
            printf("epoll timeout ....\n");
            continue;
        }
#endif

        for (i = 0; i < ret; i++)
        {    //对准备就绪的事件和文件描述符进行一一轮询;
            int fd = events[i].data.fd;    
            if (events[i].events == EPOLLIN)
            {    //判断是否为读事件
                if (fd == listenfd)
                {    //判断是否为监听套接字,如果是监听套接字则建立新的通信连接;
                    addrlen = sizeof(struct sockaddr_in);
                    connfd = accept(listenfd, (struct sockaddr*)&cltaddr, &addrlen);
                    if (-1 == connfd)
                    {
                        perror("accept");
                        return -1;
                    }
                    printf("IP : %s -- PORT : %d\n", inet_ntoa(cltaddr.sin_addr) , ntohs(cltaddr.sin_port));
                    printf("accept connfd = %d success \n", connfd);
                    /* 连接成功则将通信套接字添加到epoll实例中 */
                    event.events = EPOLLIN;
                    event.data.fd = connfd;
                    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event);
                    if (-1 == ret ) {
                        perror("epoll_ctl");
                        return -1;
                    }
                }
                else
                {    //如果是通信套接字,则处理客户端的数据请求。
                    memset(buf, 0, sizeof(buf));
                    ret = read(fd, buf, sizeof(buf));
                    if (-1 == ret) {
                        perror("read");
                        return -1;
                    } else if (0 == ret) {
                        printf("client quit\n");
                        /* 将退出的套接字文件描述符从epoll实例中清除 */
                        event.events = EPOLLIN;
                        event.data.fd = fd;
                        ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);
                        if (-1 == ret ) {
                            perror("epoll_ctl");
                            return -1;
                        }
                        close(fd);
                        continue;
                    }
                    printf("buf : %s\n", buf);
                }
            }
        }  
    }   
    close(listenfd);
    return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值