Chinaunix首页 | 论坛 | 博客
  • 博客访问: 42831
  • 博文数量: 27
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 145
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-19 12:09
文章分类
文章存档

2012年(27)

我的朋友

分类:

2012-10-31 11:03:10

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,如果该socketflag标志为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中的数据已经拷贝到queueinBuf中,但还没有处理,所以这段程序主要是处理接收缓存中还没有处理的数据(见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决定是检查idsidsocket(当sid大于0),还是遍历整个socketList(当sid小于0),如果以上3个条件中没有一个满足,则返回0

 

socketSelect (-1, 2000)函数分析

 

socketSelect (-1, 2000)是主要还是用在有新连接到来的时候,有新连接到来才会使这个函数返回真。在等待时间内,也处理已经连接socket的读写事件。

 

1.监听socketsocketOpenConnection()设置为sp->handleMask |= SOCKET_READBLE

2accept()之后,调用websAccept(),在里面利用socketCreateHandler()设置这个accept后的socketsp->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->currentEventssp->handlerMask这几个标志位来判断是否有数据读写。socketDoEvent()是对已连接的socket,通过改变sp->currentEventssp->handlerMask来分阶段的去处理数据,

socketDoEvent()中调用的sp->handler()为读写处理函数。

对于SOCKET_READBLE(读事件)àwebsReadEvent()

对于SOCKET_WRITEABLE(写事件)àwebsDefaultWriteEvent()

阅读(1129) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~