Chinaunix

标题: 讨论:怎样在epoll中实现全工TCP??? [打印本页]

作者: 79hy    时间: 2013-09-22 12:36
标题: 讨论:怎样在epoll中实现全工TCP???
问题描述: 怎样在epoll中实现全工TCP???

场景:

epoll一直在用,但是都是在半双工模式。

一般我只把读放进epoll中,我们的应用写很少(大部分都是这种情况吧)就放在队列中等epoll timeout出来转一圈,把该写的数据写出去。

tcp是全双工的,epoll怎么来实现全双工?

思考很久,没有写例子,希望大家帮忙推导一下可能出现的问题,以及解决方案。


思路如下:

1. 启动2线程,一个读(R_EPOLL),一个写(信号量通知,建立一个key是fd的hash表-W_HASH)

2. 每accept一个socket加入R_EPOLL 和 W_HASH

3. 当没错误的时候,一切正常不表。 如果当read出错,或write出错,会发生什么情况?

3-1:read/write出错,write/read也会出错吗?
3-2:当本地或对端shutdown_read,shutdown_write 会导致对方什么情况?
3-3:会发生断开一半,而另外一半正常的情况吗?


各位CUer, 喷我吧~~~
作者: linux_c_py_php    时间: 2013-09-22 16:11
非阻塞读写, 楼主不如读个简单的网络库了解了解就知道怎么实现了.
作者: 79hy    时间: 2013-09-22 16:57
回复 2# linux_c_py_php


    和非阻塞读写没关系。呵呵。我的意思是在epoll中怎么来实现读写并发操作,然后出错怎么处理。

不知道大家有想过这些问题了不,我没想明白,拿出来和大家讨论下。大家随意拍。
作者: linux_c_py_php    时间: 2013-09-22 17:19
C版本:https://code.csdn.net/qq120848369/cutil/tree/master/simple_io
C++版本:https://code.csdn.net/qq12084836 ... master/libevent_cpp

参考一下相关代码, 呵呵有啥用.
作者: egmkang    时间: 2013-09-23 10:43
同时读和写,"同时"有什么用?
作者: solu    时间: 2013-09-23 11:57
回复 3# 79hy


    读写并发,这是epoll的最基本的功能吧
作者: kdkgod    时间: 2013-09-23 13:31
想法非常好,我之前也这么想过,其实读非常容易理解,主要是写操作,肯定不能在没有写操作的情况就把fd注册到set里面,我用的是libevent,我的方法是当调用写操作的时候就写入写缓冲,然后注册fd的WRITE事件,当写缓冲没有数据可以发送的时候就去掉fd的WRITE事件。对于异常处理也容易,不管是read失败,还是write失败都没有关系,直接释放资源就可以。回复 1# 79hy


   
作者: 李营长    时间: 2013-09-23 17:40
这事我干过,多线程,全双工,epollin | epollout, 在epoll外的线程里close(socket),直接出现epoll线程里一直返回epollevent,epoll_ctl显式删除都没用。死循环了。lol
作者: csumck    时间: 2013-09-23 23:10
搞不懂楼主说的全双工是啥意思。。epoll就是个监听可读可写事件的东西,和如何进行读写没有关系的。。。
难道像楼上说的,同时监听EPOLLIN和EPOLLOUT就叫双工?
作者: hanxin83    时间: 2013-09-24 09:16
同没有理解什么叫"同时读写"...
作者: hua9537    时间: 2013-09-24 09:39
全双工,还是半双工应该在驱动那层处理掉了,上层不需考虑这些,读写分别起一个线程就行。只要你的代码没问题,操作系统会以最大效率处理的。
作者: 79hy    时间: 2013-09-24 13:15
本帖最后由 79hy 于 2013-09-24 13:16 编辑
hanxin83 发表于 2013-09-24 09:16
同没有理解什么叫"同时读写"...


全双工就是 对一个socket同时读写。  比如1个fd,用2个线程,1个线程读,1个线程写,并行。

epoll是单线程的,监听了读写事件后,在同一时间操作fd,要不只能读,要不就只能写。这就是半双工。

我说的你们能理解吗?
作者: 79hy    时间: 2013-09-24 13:18
回复 6# solu


    epoll注册了读写事件后只能在同一事件单一的读或者写。不能同时读写。所以这是半双工。
作者: 79hy    时间: 2013-09-24 13:21
回复 5# egmkang


    同时就是想 如果有个场景是读写都比较频繁的时候,效率高点。让tcp真正的全双工。
作者: 79hy    时间: 2013-09-24 13:23
回复 7# kdkgod


    你的方法还是半双工的。而且频繁的去操作epoll,增加或减少事件,会很降低效率的。
作者: hellioncu    时间: 2013-09-24 13:55
79hy 发表于 2013-09-24 13:15
全双工就是 对一个socket同时读写。  比如1个fd,用2个线程,1个线程读,1个线程写,并行。

epoll是 ...


两个线程各自epoll,一个关心读,一个关心写,这样就能做到你要求的全双工了
作者: 李营长    时间: 2013-09-24 14:17
回复 17# hellioncu


    虽然epoll的函数号称是“线程安全”的,不过我还是遇到了多线程操作问题。在RHEL6.0上面遇到的。正确的操作应该是在一个线程里epoll_wait,epoll_ctl,在其它的线程里recv/send
作者: hellioncu    时间: 2013-09-24 14:20
李营长 发表于 2013-09-24 14:17
回复 17# hellioncu


那估计是连接断开、建立的时序没处理好,我说的方式有这样用过,没问题
作者: 李营长    时间: 2013-09-24 14:25
回复 19# hellioncu


    在unbuntu12和suse上测试是ok的,测echo时一秒能处理上万个请求。但是上了rhel以后就傻逼了,不清楚具体原因。 最后建立了多个线程,每一个有自己的epoll池,每个线程只操作自己的epoll,同时read/write,这样就工作得很稳定了。
作者: hellioncu    时间: 2013-09-24 14:33
李营长 发表于 2013-09-24 14:25
回复 19# hellioncu


咱epoll也是两个的,不是两个线程共用一个。
作者: kdkgod    时间: 2013-09-24 15:35
如果一直关心写,但是没有数据写的话,那么肯定会造成CPU浪费。回复 15# 79hy


   
作者: csumck    时间: 2013-09-25 09:16
要异步读写的话只能多线程了啊,linux没有完善的网络异步IO的接口的。  但是多线程带来的消耗也不小的。
作者: 79hy    时间: 2013-09-25 16:26
回复 22# kdkgod


    也不是一直关心写。有数据写的时候就写。没数据就阻塞休息。 主要是要同一个socket实现同时读写。
作者: 79hy    时间: 2013-09-25 16:28
李营长 发表于 2013-09-24 14:17
回复 17# hellioncu


如果在一个线程池里读写,怎么做到同步? 如果对一个fd进行多线程读、写, 怎么保证读出错,写怎么处理???
作者: kdkgod    时间: 2013-09-25 16:29
哦,以前同样做过这样的事。但是发现效率并不高,真实环境很少读与写同时,并且量特别大的情况。回复 24# 79hy


   
作者: 79hy    时间: 2013-09-25 16:34
本帖最后由 79hy 于 2013-09-25 16:34 编辑

回复 26# kdkgod


    谢谢。就是我就是妄想症发了。

其实我现在的处理方式是用ET模式,把IN,OUT都放到epoll里监听。

每个fd上都挂一个sendlist,和recvbuf, 1个SendEnable(SocketMap)

如果有OUT事件,就把SendEnable设置 1. 发送阻塞时设置成0.

每次epoll都0.5s超时出来都遍历一下 SocketMap. 把SendEnable 为1的 sendlist不为空的数据发出去。


我想有没有可能避免掉遍历呢???????
作者: kdkgod    时间: 2013-09-25 16:52
sendlist和recvbuff你是怎么实现的?
我当是也是这么干的,sendlist是每一次应用层在调send接口的时候push到sendlist中,而recvbuff的呢就是一块固定内存,收到数据的时候就调一下协议解析,是一个完整包的时候就回调给应用层。


回复 27# 79hy


   
作者: 李营长    时间: 2013-09-25 16:53
79hy 发表于 2013-09-25 16:28
如果在一个线程池里读写,怎么做到同步? 如果对一个fd进行多线程读、写, 怎么保证读出错,写怎么处理 ...


recv, send本身是线程安全的。你没弄清楚自己想要用什么服务器模式,弄明白了这个以后你就不会焦虑于epoll了。
作者: 79hy    时间: 2013-09-25 16:57
kdkgod 发表于 2013-09-25 16:52
sendlist和recvbuff你是怎么实现的?
我当是也是这么干的,sendlist是每一次应用层在调send接口的时候push ...



握爪。  哈哈。


我的recvbuff相当于2块内存,1个固定大小的头,然后一个指针,根据头里的数据大小分配一个内存块。收完后push到业务层去。

sendlist就更简单了,就是个结构体+List,里面存了个已发送字节数和一个要发送的数据块。
作者: 79hy    时间: 2013-09-25 16:59
李营长 发表于 2013-09-25 16:53
recv, send本身是线程安全的。你没弄清楚自己想要用什么服务器模式,弄明白了这个以后你就不会焦虑于ep ...



recv, send本身是线程安全的。 能详细解释下不?

如果recv的时候,send出错了(多线程并行), 那怎么处理这个fd呢?直接close,应该epoll会报错吧。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2