!!!!!!!!!!!!
分类: LINUX
2011-06-14 10:31:18
socket sp->accept 对应的函数是websAccpet()
socket sp->handler对应的函数是websSocketEvent(),该函数中
对于SOCKET_READBLE(读事件),对应的函数为websReadEvent(),
对于SOCKET_WRITEABLE(写事件)对应的函数为websDefaultWriteEvent()
最让人难理解的是web服务器主循环
while (!finished)
{
if (socketReady(-1) || socketSelect(-1, 2000)) /*socketReady(-1)处理已有的连接socket,如果有事件就马上处理,不需要延时socketSelect(sid, 0)(调用socketSelect(sid, 0)的目的主要是判断这个已经连接的sid,是否有新的可读事件发生),优先处理已经连接的socket发生过的事件*/
{/*socketSelect(-1, 2000)处理监听新连接*/
socketProcess(-1);
}
websCgiCleanup();
emfSchedProcess();
}
socketReady(-1)函数分析
socketReady函数检查已建立连接的socket中是否有以下事件,如果检查到一个,就返回1,如果没有检查到,就返回零。
(1) sp->flags & SOCKET_CONNRESET,如果该socket的flag标志为SOCKET_CONNRESET,则调用函数socketCloseConnection关闭该socket连接,然后返回0;
(2) sp->currentEvents & sp->handlerMask,如果该socket当前的事件和他要处理的事件相同,就返回1,告诉调用socketReady的函数有socket准备好被处理了;(说明:sp->handlerMask用于表示select监听该socket的事件,sp->currentEvents表示select监听该socket的事件发生后,会对其赋值)
(3) sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0,如果该socket要处理的事件是SOCKET_READABLE并且该socket的缓存中有可读的数据,则调用socketSelect函数(为什么在这里要调用这个函数,看了下socketSelect,应该是为了设置sp->currentEvents |= SOCKET_READABLE),然后返回1,告诉调用socketReady的函数有socket准备好被处理了;
socketInputBuffered(sid) > 0说明socket中的数据已经拷贝到queue的inBuf中,但还没有处理,所以这段程序主要是处理接收缓存中还没有处理的数据(见socketRead函数)。
if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0)
{
socketSelect(sid, 0);
return 1;
}
调用socketSelect(sid, 0)的目的主要是判断这个已经连接的sid,是否有新的可读事件发生,如果有则设置sp->currentEvents |= SOCKET_READABLE,即使没有,也返回1,这样会调用socketProcess(-1),在socketProcess(-1)里面继续调用socketReady(sid),同样返回为1,这样就调用了socketDoEvent (sp),在socketDoEvent(sp)中走到
if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0)
{
sp->currentEvents |= SOCKET_READABLE;
}
这样,sp->currentEvents |= SOCKET_READABLE。
随后调用
if (sp->handler && (sp->handlerMask & sp->currentEvents))
{
(sp->handler)(sid, sp->handlerMask & sp->currentEvents,
sp->handler_data);
…..
}
这样会调用函数websReadEvent()àwebsGetInput()àsocketRead(),在socketRead()中,由于len = min(ringqLen(rq), bufsize); if (len <= 0)不成立,就直接调用memcpy(&buf[bytesRead], rq->servp, len);
ringqGetBlkAdj(rq, len);
bufsize -= len;
bytesRead += len;
(4) socketReady函数根据传入的参数sid决定是检查id为sid的socket(当sid大于0),还是遍历整个socketList(当sid小于0),如果以上3个条件中没有一个满足,则返回0。
socketSelect (-1, 2000)函数分析
socketSelect (-1, 2000)是主要还是用在有新连接到来的时候,有新连接到来才会使这个函数返回真。在等待时间内,也处理已经连接socket的读写事件。
1.监听socket在socketOpenConnection()设置为sp->handleMask |= SOCKET_READBLE
2.accept()之后,调用websAccept(),在里面利用socketCreateHandler()设置这个accept后的socket为sp->handleMask = SOCKET_READBLE
3..在初始化initWebs(),定义钩子函数websDefaultHandler(),在该函数中,websSetRequestSocketHandler()中,调用了socketCreateHandler(),定义sp->handleMask=SOCKET_WRITEABLE,也就是说在处理url请求时,才会sp->handleMask=SOCKET_WRITEABLE
综上,socketSelect()函数处理监听socket,监听是否有新的连接,同时监听已经连接的socket,只有在accept之后,socket变成了已连接,socketSelect()才会监听这些端口
socketProcess(-1)函数分析
socketProcess处理到达的socket事件,如果传入的参数是小于0,则会处理所有的socket的事件,如果大于0,则会处理指定的socket的事件。下面是主要过程:
if (socketReady(sid))
{
socketDoEvent(sp);
}
socketReady(int sid)函数中,是sp->currentEvents,sp->handlerMask这几个标志位来判断是否有数据读写。socketDoEvent()是对已连接的socket,通过改变sp->currentEvents和sp->handlerMask来分阶段的去处理数据,
socketDoEvent()中调用的sp->handler()为读写处理函数。
对于SOCKET_READBLE(读事件),àwebsReadEvent(),
对于SOCKET_WRITEABLE(写事件)àwebsDefaultWriteEvent()