The My Opera forums have been replaced with forums.opera.com. Please head over there to discuss Opera's products and features

See the new Forums

NeL Network Layer 1

Forums » Ryzom » Nel

You need to be logged in to post in the forums. If you do not have an account, please sign up first.

Go to last post

3. November 2011, 10:15:55

li9chuan

Posts: 12

NeL Network Layer 1

Server
Server Structure

服务器提供了一个接收队列(见下面对象图上的“Receive FIFO Buffer”),每个连接一个发送队列(“Send FIFO Buffer”)。在内部,每个连接关联的接收缓冲区处理非阻塞接收不完整的数据块(CServerBufSock中)。实际接收和发送是由CTcpSock(from layer 0)。


NLNET Layer 1 UML图


NLNET Layer 1 UML运行图


每个连接都被接收线程控制(CServerReceiveTask)。而不必每个线程一个连接(它会减慢系统,进而系统的限制将限制连接的最大数量),有一个线程池处理多个连接。例如,30个线程,处理30连接允许900个并发连接。如果只有一个线程负责所有的连接,select()操作在大量的sockets上的开销太大。

启动服务器
服务器(CBufServer)启动一个监听套接字(CListenSock),由一个特定的线程(CListenTask)处理。然后,它可以接受传入的连接。

接受一个连接
接受一个连接时,服务器通过将连接事件推入接收队列广播连接,并且调度相关的套接字到接收线程池(或new一个)

读取数据
第1层(注:它可以是一个较高的NeL Net级别)的用户调用CBufServer::dataAvailable()来检查传入的数据。如果在接收队列的顶部找到一个连接或断开事件,相关系统的回调会被调用。然后是逻辑连接的套接字(CBufSock::connectedState()为true), in case of a connection event.

如果dataAvailable()返回true,用户呼叫CBufServer::receive(data,&sockid)。第二个参数告知连接的数据到来。它可以直接回复,通过调用CBufServer::send(replydata,sockid)。

为保证系统的正常工作用户必须调用CBufServer::update()。

发送数据
如发送缓冲。实际发送数据时的那一刻,取决于指定的触发器。默认情况下,启用时间触发,值为20 ms。这意味着实际的数据发送在20毫秒后,provided update() is called evenly。用户还可以指定大小触发:当发送缓冲区的大小超过指定大小,将数据发送。最后,用户可以强制调用flush()发送。

非阻塞的接收如何工作
每个接收线程在它的sockets上(CServerReceiveTask)执行一个select()。当传入数据到来时,方法CServerBufSock::receivePart()试图读取一个块(这是由长度前缀和一个有效负载缓冲区)。如果实际收到的数据小于预期,它就在接收缓冲区中保留,以供日后完成。当它是完整的,就被推入主接收队列。

非阻塞的发送如何工作
由发送队列中的所有数据复制到一个缓冲区,然后再实际发送。如果发送没有全部完成(或者它阻塞),部分的缓冲区保存稍后发送。

处理断开连接
当接收线程在它的sockets上检测到一个套接字断开,断开事件被推入接收队列的下一次CBufServer::update()。当断开事件处理时(在接收队列的顶部找到一个),Socket被添加到同步移除连接的线程中。它将在下次select前有效的移除。

唤醒管道(UNIX)
在每一个select set 添加一个UNIX管道,以便当有一个新的连接添加到它的set或当服务器需要退出时select可以停止。同样,侦听线程在侦听套接字和唤醒管道上执行select。

在Windows下,唤醒机制没有实现。相反,select超时时间较短。

线程同步
由于不同线程间不是数据共享,一些互斥锁用于同步数据的访问/修改,接收队列,线程池,连接,删除连接的集合和套接字的连接属性(注:以确保公平访问的变量,在GNU / Linux实现使用一个信号,而不是一个pthread_mutex)

收集统计数据
有几种方法可以知道CBufServer有多少字节被读取和写入。

客户端(服务器相关)
客户端提供了一个接收队列和一个发送队列。接收是一个单独的线程(CClientReceiveTask),但实际发送的flush()是在CBufClient::update()中完成的。 socket处于非阻塞模式。不同于服务器,这里没有连接广播。当接收线程或发送中检测到断线,一个断线事件被推入接收队列。此外,客户端不在断开后移除socket,而是在销毁时,因为用户可以再次通过调用connect()断开后,重复使用相同的CBufClient对象。

Forums » Ryzom » Nel