epoll主进程监听,子进程逻辑处理

epoll_ctl 默认的模式是水平模式。

epoll使用共享内存,使用内核和用户使用一块内存,使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据交换。内核可以直接看到epoll监听的句柄,效率高。

epoll 使用红黑树保存监听的套接字,当添加或者删除一个套接字时(epoll_ctl),都在红黑树上去处理,红黑树本身插入和删除性能比较好,时间复杂度O(logN)。

客户端connect,会产生EPOLLIN事件,

TCP-NODELAY 标志-代表发送的返回不汇总发送,而是接受消息立即发送。这种是块,但是增加带宽压力。

epoll 的大概逻辑是将有效的描述符放入epoll.

{1. epoll_wait 先等待listen描述符是否产生接受从cli端发来的新的connect 链接。新的connnect 对应的EPOLL 的事件 是EPOLLIN。

2 . accept 接受新的listen链接,将返回的有效描述符rd存放到epoll_ctl.

3. epoll_wait 对rd 描述符进行处理,判断是否有新的EPOLLIN 可以读,写等操作

}

EPOLLOUT事件:
EPOLLOUT事件只有在连接时触发一次,表示可写,其他时候想要触发,那你要先准备好下面条件:
1.某次write,写满了发送缓冲区,返回错误码为EAGAIN。
2.对端读取了一些数据,又重新可写了,此时会触发EPOLLOUT。
简单地说:EPOLLOUT事件只有在不可写到可写的转变时刻,才会触发一次,所以叫边缘触发,这叫法没错的!

其实,如果你真的想强制触发一次,也是有办法的,直接调用epoll_ctl重新设置一下event就可以了,event跟原来的设置一模一样都行(但必须包含EPOLLOUT),关键是重新设置,就会马上触发一次EPOLLOUT事件。

EPOLLIN事件:
EPOLLIN事件则只有当对端有数据写入时才会触发,所以触发一次后需要不断读取所有数据直到读完EAGAIN为止。否则剩下的数据只有在下次对端有写入时才能一起取出来了。
现在明白为什么说epoll必须要求异步socket了吧?如果同步socket,而且要求读完所有数据,那么最终就会在堵死在阻塞里。

可以为每一个listen 返回的fd ,产生epoll_wait 等操作。

 

int

tcp_service(constchar * in_port,constchar * in_ip )

{

   if( in_port ==NULL | in_ip ==NULL )

    {

        printf ( "port or ip is null\n");

       return E_FAIL;

    }

   int port = atoi( in_port);

   int listenfd,rwfd, epfd,okfds,i,ret;

   constchar *ip = in_ip;

   struct sockaddr_in address, local;

   struct epoll_event events[MAX_EVENTS_NUM];

   int address_len;

    pid_t pid;

char logname[STR_MAX_LEN];

int log_fd;

struct stat stat_buf;

    bzero( &address,sizeof(address) );

   if( port <1024 || port >65535)

    {

        printf( "prot can not be more than 65535 and \

                can not be less than 1024");

       return E_FAIL;

    }

    address.sin_family = AF_INET;

    inet_pton( AF_INET, ip, &address.sin_addr );

    address.sin_port = htons( port );

    listenfd = socket( AF_INET, SOCK_STREAM,0);

   if( listenfd <0 )

    {

        perror("socket wrong" );

       return E_FAIL; 

    }

setskopt(listenfd);

    ret = bind( listenfd, (struct sockaddr*)&address,sizeof(address)); 

   if( ret <0 )

    {

       if( errno == EADDRNOTAVAIL )

        {

            printf("ip is wrong");

           return E_FAIL;

        }

       elseif( errno == EADDRINUSE )

        {

            printf("prot is uesd" );

           return E_FAIL;

        }

        perror("bind wrong");

       return E_FAIL;

    }

//添加描述符,LISTEN_NUM 是listen 队列等待的最大数量,listen队列的描述符需要由accept函数获取,如果没有获取当等待队列大于 LISTEN_NUM,listen就会报错。

    ret = listen( listenfd, LISTEN_NUM );

   if( ret <0 )

    {

        perror("listen is wrong");

       return E_FAIL;

    }     

       

    epfd = epoll_create( EPOLL_CREAT_NUM );

   if( epfd <0 )

    {

        perror( "epoll_creat is wrong");

       return E_FAIL;

    

    }

    epoll_addfd( epfd, listenfd );

signal(SIGCHLD,SIG_IGN);

   while(1)

    {

printf( "parent is doing\n");

        okfds = epoll_wait(epfd, events, MAX_EVENTS_NUM, -1);

       if( okfds <0 )

        {

            perror("epoll_wait is wrong");

           return E_FAIL;

        }

        

       for ( i=0; i<okfds; i++)

        {

           if(events[i].data.fd == listenfd)

            {

address_len =sizeof(address);

                rwfd = accept(listenfd,(struct sockaddr*)&address,

                       &address_len );

               if(rwfd <0 )

                {

                    perror("accept wrong");

                   return E_FAIL;

                }

                epoll_addfd(epfd, rwfd);

printf("events.fd=[%d]\n",events[i].data.fd);

printf("listen=[%d]\n", listenfd);

printf("rwfd=[%d]\n", rwfd);

}elseif ( events[i].events & EPOLLIN)

{

                pid=fork(); 

               if(pid <0 )

                {

                    perror("fork is wrong");

                   return E_FAIL;

                }

               if( pid ==0 )

{

printf("clid events.fd=[%d]\n",events[i].data.fd);

char buf[STR_MIN_LEN];

close(listenfd);

memset(logname,0x00,sizeof(logname));

memset(buf,0x00,sizeof(buf));

sprintf( logname,"fd%d",events[i].data.fd); 

log_fd =open( logname, O_CREAT|O_RDWR|O_APPEND,0666);

if( log_fd <0 )

{

printf( "open is wrong\n");

return E_FAIL;

}

printf("log_fd=[%d]\n", log_fd);

while(1)

{

memset(buf,0x00,sizeof(buf));

ret=recv(events[i].data.fd,buf,sizeof(buf),0);

if(ret <0)

{

if(errno == EAGAIN || errno == EWOULDBLOCK)

break;

close(events[i].data.fd);

break;

}

if( ret ==0)

{

close(events[i].data.fd);

}

                  printf("being child:%s\n",buf);

}

exit(0);

                }

printf("par rwfd=[%d]\n", rwfd);

close(events[i].data.fd);

close(rwfd);

               continue

}

}

    }

    close(listenfd);

    close(epfd);

   return E_OK;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小喾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值