
转载自:https://blog.csdn.net/javazejian/article/details/51932554。转载自:https://blog.csdn.net/a19881029/article/details/26348627。2011/07/2516:41 287,832 blog.csdn.net-qi_jianzhou-article-details-649362.mdi。
对于一个已上锁的互斥锁,若调用pthread_mutex_trylock()函数再次加锁,将返回错误ebusy(已加锁错误),因而不会发生阻塞.对于未上锁的情况,该函数将对互斥锁加锁.调用成功返回0,失败返回-1.。此时程序不会阻塞起来等待数据准备就绪返回,read函数会返回一个错误eagain,提示你的应用程序现在没有数据可读请稍后再试。if((sockfd=socket(af_inet,sock_stream,0))==-1){ //创建套接字socket函数可以调用socket函数,该函数返回一//个类似于文件描述符的句柄。
从字面上看, 意思是:EAGAIN: 再试一次,EWOULDBLOCK: 如果这是一个阻塞socket, 操作将被block,perror输出: Resource temporarily unavailable
总结:
这个错误表示资源暂时不够,能read时,读缓冲区没有数据,或者write时,写缓冲区满了。遇到这种情况,如果是阻塞socketepoll lt 不可写变可写,read/write就要阻塞掉。而如果是非阻塞socket,read/write立即返回-1, 同时errno设置为EAGAIN。
所以,对于阻塞socket,read/write返回-1代表网络出错了。但对于非阻塞socket,read/write返回-1不一定网络真的出错了。可能是Resource temporarily unavailable。这时你应该再试,直到Resource available。

综上,对于non-blocking的socket,正确的读写操作为:
读:忽略掉errno = EAGAIN的错误,下次继续读
写:忽略掉errno = EAGAIN的错误,下次继续写
对于select和epoll的LT模式,这种读写方式是没有问题的。但对于epoll的ET模式,这种方式还有漏洞。
epoll的两种模式LT和ET
//为true表示等待全部对象都变为有信号状态才返回,为false表示任何一个对象变为有信号状态则返回。waitforsingleobject函数用来检测 hhandle事件的信号状态,当函数的执行时间超过dwmilliseconds就返回,但如果参数dwmilliseconds为infinite时 函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到waitforsingleobject有返回直才执行后面的代码。若某原子在处于能量最低状态时,电子排布为4d15s2,则下列说法正确的是a.该元素原子处于能量最低状态时,原子中共有3个未成对电子b.该元素原子核外共有5个电子层c.该元素原子的m能层共有8个电子d.该元素原子最外层共有3个电子。

所以,在epoll的ET模式下,正确的读写方式为:
读:只要可读,就一直读,直到返回0,或者 errno = EAGAIN
写:只要可写,就一直写,直到数据发送完,或者 errno = EAGAIN
为何要使用非阻塞套接字:
对于epoll有两种触发模式:水平触发LT和边缘触发ET,其中边缘触发“必须”(经评论区提示,这个这个“必须“用的不严谨,说明一下:不是因为程序硬性要求这样,而是从工程实现的角度来看,如果不这么做会产生问题)需要设置所的socket为non_blocking。
边缘触发,顾名思义,不到边缘情况,是死都不会触发的。

EPOLLOUT事件:
EPOLLOUT事件在连接时建立时首先触发触发一次,表示可写,其他时候的触发条件为:
1.某次write,写满了发送缓冲区,返回错误码为EAGAIN。
2.对端读取了一些数据,又重新可写了,此时会触发EPOLLOUT。
简单地说:EPOLLOUT事件只有socket从unwritable变为writable时,才会触发一次。
对于EPOLLOUT事件,必须要将该文件描述符缓冲区一直写满,让 errno 返回 EAGAIN 为止,或者发送完所有数据为止。

EPOLLIN事件:
EPOLLIN事件则只有当对端有数据写入时才会触发,所以触发一次后需要不断读取所有数据直到读完EAGAIN为止,否则剩下的数据只有在下次对端有写入时才能一起取出来了。设想这样一个场景:接收端接收完整的数据后会向对端发送应答报文,对端才会继续向接收端发送数据,从而触发下一次的EPOLLIN,而这时没有读完socket缓冲区中的所有数据,导致接收端无法向对端发送应答报文,而对端没有收到应答报文,也就不会再发送数据触发下一次的EPOLLIN,而没有下一次的EPOLLIN事件epoll lt 不可写变可写,接收端也就永远不知道此socket缓冲区中还有未读出的数据。(一个完美的死循环) 简单的说:EPOLLIN事件只有对端新数据写入时,才会触发一次。
对于EPOLLIN事件,必须要将该文件描述符一直读到空,让 errno 返回 EAGAIN 为止。
总结:现在明白为什么说epoll要求异步socket了吧?如果你的文件描述符如果不是非阻塞的.
在实现先拉后推式转发之前,我们先熟悉下live555的运转模式,live555主要运转的是一个source与sink的循环,sink想要数据,就调用source的getnextframe,source获取到数据后,再调用aftergettingframe回调,返回给sink数据,sink处理完后,再调用source的getnextframe,如此循环。从一个文件流中读数据,读取count个元素,每个元素size字节.如果调用成功返回count.返回实际读取size*count字节.如不成功,返回实际读取的元素个数。还是采用fseek的方式从文件最后开始读,但这时不是一位一位的读,而是一块一块的读,每读一块数据时,就将读取后的数据放在一个buf里,然后通过换行符(n)的个数来判断是否已经读完最后$num行数据.。
于逻辑线程对数据的处理方式,这个独立发送线程也维护一个消息队列,逻辑线程要发数据时也只是把数据加入到这个队列中,发送线程循环取包来执行send调用,这时的阻塞也就不会对逻辑线程有任何影响了。在非阻塞模式下,一般是用setsockopt函数设置发送阻塞的时间,然后调用send()发送数据,当超出这个时间,send函数会返回已发送的数据大小, 但是请注意此时缓存中可能还有些数据没有发送到网络上.。信号量的发送数据函数,并不会真的把数据存储到队列数据存储区中去,而且也没有数据存储区,它仅仅记录数据项的个数,而且这个发送函数没有阻塞时间,也就是一旦满了,任务就不能再向队列尝试添加数据,如果有任务尝试添加,会直接返回一个满列错误,而不会进入阻塞以便等到队列有空间时再将数据添加到队列中区。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-115571-1.html
站坑里宋
#杨洋2015金投赏##杨洋icon#杨洋