`
daojin
  • 浏览: 697818 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Socket拉屎模型之二--实践篇

 
阅读更多

前言:本篇没有介绍最好的IO模型 epoll(非阻塞异步),是性能最好的。但是本篇不做介绍。

http://www.ibm.com/developerworks/cn/linux/l-async/

http://blog.csdn.net/piggyxp/article/details/6922277

http://daojin.iteye.com/admin/blogs/1300709

连接中的那篇socket拉屎模型严重脱离实际,有人可能觉得这感觉不实在,或者说,没有接触实际。本篇文章就对上述进行补充,请看如下时序图:

 

关键概念:

 

1.同步意思是发送一个Read/Write(读和写,是一种抽象概念)命令来获得数据,如果发了两个命令 如 select和read/write 才能把数据弄到数,那么就叫做异步。

2.阻塞的意思是 一个Read/write函数,如果没有数据,就不返回。叫做阻塞,是一种局部概念。

 

1.同步阻塞模型。

 

我们注意到,大部分的 socket 接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是 IO 接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。

实际上,除非特别指定,几乎所有的 IO 接口 ( 包括 socket 接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用 send() 的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。这给多客户机、多业务逻辑的网络编程带来了挑战。这时,很多程序员可能会选择多线程的方式来解决这个问题。


2.多线程的服务器程序(同步阻塞模型之二)

 

多线程的服务器程序

应对多客户机的网络应用,最简单的解决方式是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。

具体使用多进程还是多线程,并没有一个特定的模式。传统意义上,进程的开销要远远大于线程,所以,如果需要同时为较多的客户机提供服务,则不推荐使用多进程;如果单个服务执行体需要消耗较多的 CPU 资源,譬如需要进行大规模或长时间的数据运算或文件访问,则进程较为安全。通常,使用 pthread_create () 创建新线程,fork() 创建新进程。

我们假设对上述的服务器 / 客户机模型,提出更高的要求,即让服务器同时为多个客户机提供一问一答的服务。于是有了如下的模型。



 

在上述的线程 / 时间图例中,主线程持续等待客户端的连接请求,如果有连接,则创建新线程,并在新线程中提供为前例同样的问答服务。

很多初学者可能不明白为何一个 socket 可以 accept 多次。实际上,socket 的设计者可能特意为多客户机的情况留下了伏笔,让 accept() 能够返回一个新的 socket。下面是 accept 接口的原型:

 

	 int accept(int s, struct sockaddr *addr, socklen_t *addrlen); 

输入参数 s 是从 socket(),bind() 和 listen() 中沿用下来的 socket 句柄值。执行完 bind() 和 listen() 后,操作系统已经开始在指定的端口处监听所有的连接请求,如果有请求,则将该连接请求加入请求队列。调用 accept() 接口正是从 socket s 的请求队列抽取第一个连接信息,创建一个与 s 同类的新的 socket 返回句柄。新的 socket 句柄即是后续 read() 和 recv() 的输入参数。如果请求队列当前没有请求,则 accept() 将进入阻塞状态直到有请求进入队列。

上述多线程的服务器模型似乎完美的解决了为多个客户机提供问答服务的要求,但其实并不尽然。如果要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,而线程与进程本身也更容易进入假死状态。

很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如 websphere、tomcat 和各种数据库等。

但是,“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用 IO 接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。

对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。

总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型并不是最佳方案。下一章我们将讨论用非阻塞接口来尝试解决这个问题。


3.非阻塞同步IO(一个不好的例子)

 

在非阻塞状态下,recv() 接口在被调用后立即返回,返回值代表了不同的含义。如在本例中,

  • recv() 返回值大于 0,表示接受数据完毕,返回值即是接受到的字节数;
  • recv() 返回 0,表示连接已经正常断开;
  • recv() 返回 -1,且 errno 等于 EAGAIN,表示 recv 操作还没执行完成;
  • recv() 返回 -1,且 errno 不等于 EAGAIN,表示 recv 操作遇到系统错误 errno。

可以看到服务器线程可以通过循环调用 recv() 接口,可以在单个线程内实现对所有连接的数据接收工作。

但是上述模型绝不被推荐。因为,循环调用 recv() 将大幅度推高 CPU 占用率;此外,在这个方案中,recv() 更多的是起到检测“操作是否完成”的作用,实际操作系统提供了更为高效的检测“操作是否完成“作用的接口,例如 select()。



4.改善轮询(异步阻塞IO)select 和poll

 

 

 

使用 select() 接口的基于事件驱动的服务器模型

大部分 Unix/Linux 都支持 select 函数,该函数用于探测多个文件句柄的状态变化。下面给出 select 接口的原型:

 

 FD_ZERO(int fd, fd_set* fds) 
 FD_SET(int fd, fd_set* fds) 
 FD_ISSET(int fd, fd_set* fds) 
 FD_CLR(int fd, fd_set* fds) 
 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 
        struct timeval *timeout) 

这里,fd_set 类型可以简单的理解为按 bit 位标记句柄的队列,例如要在某 fd_set 中标记一个值为 16 的句柄,则该 fd_set 的第 16 个 bit 位被标记为 1。具体的置位、验证可使用 FD_SET、FD_ISSET 等宏实现。在 select() 函数中,readfds、writefds 和 exceptfds 同时作为输入参数和输出参数。如果输入的 readfds 标记了 16 号句柄,则 select() 将检测 16 号句柄是否可读。在 select() 返回后,可以通过检查 readfds 有否标记 16 号句柄,来判断该“可读”事件是否发生。另外,用户可以设置 timeout 时间。

下面将重新模拟上例中从多个客户端接收数据的模型。

 


上述模型只是描述了使用 select() 接口同时从多个客户端接收数据的过程;由于 select() 接口可以同时对多个句柄进行读状态、写状态和错误状态的探测,所以可以很容易构建为多个客户端提供独立问答服务的服务器系统。

 

  • 大小: 16.1 KB
  • 大小: 32.4 KB
  • 大小: 23.7 KB
  • 大小: 26 KB
分享到:
评论

相关推荐

    swift-socket.io-client-swiftSocket.IO客户端

    1. **事件驱动**:Socket.IO客户端基于事件模型,允许开发者订阅特定的事件并响应它们。例如,你可以监听“connect”、“message”和“disconnect”等事件,从而实现客户端和服务器之间的即时交互。 2. **连接管理*...

    HP用SOCKET实现(客户端---服务端)

    标题:HP用SOCKET实现(客户端---服务端) 描述:HP用SOCKET实现(客户端---服务端)通信 本文将深入解析如何利用PHP中的Socket编程技术实现客户端与服务端之间的通信,通过分析提供的代码示例,我们将理解其工作原理、...

    perl-IO-Socket-SSL-1.94-7.el7.noarch.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    perl-IO-Socket-IP-0.21-5.el7.noarch.rpm

    linux centos7的perl-IO-Socket-IP-0.21-5.el7.noarch.rpm包

    socket.io-server-cpp.tar.gz

    Socket.IO 是一个实时应用框架,它为开发人员提供了一种简单的方式来实现实时、双向通信。这个框架在浏览器和服务器之间构建了一座桥梁,使得数据能够实时、可靠地传输。Socket.IO 支持多种传输机制,包括 WebSocket...

    HP-Socket文档

    HP-Socket 提供了大量的 Demo 示例如:PUSH 模型示例、PULL 模型示例、PACK 模型示例、性能测试示例以及其它编程语言示例,以便让使用者能方便快速地学习和使用 HP-Socket。 HP-Socket 的特点 * 高性能:HP-Socket...

    单路情况下的CS模型 tcp-socket udp-socket ud-socket

    在本文中,我们将深入探讨标题所提到的"单路情况下的CS模型",以及TCP Socket、UDP Socket和UD Socket之间的差异。 首先,让我们来理解一下“CS模型”。这里的“CS”代表Client-Server(客户端-服务器)模型,这是...

    Delphi-Cross-Socket-master.zip

    要深入学习和利用这个库,你需要做的是解压"Delphi-Cross-Socket-master",阅读源代码,理解其设计思想和实现方式,然后根据提供的示例逐步实践。此外,你还可以参考Git库中的README文件或相关文档,了解如何集成这...

    HP-Socket压力测试 易源代码

    HP-Socket是一款高性能、易用且稳定的网络通信框架,它主要应用于服务器端的开发,尤其在需要处理大量并发连接和高吞吐量的场景下表现出色。本话题将聚焦于HP-Socket的压力测试及其易源代码,这对于我们理解和优化...

    socket.io-cpp-client-sample:Socket.IO C++ 客户端示例

    socket.io-cpp-client-sample Socket.IO C++ 客户端示例。 该程序将本机客户端外壳上的命令结果提供给 Web 浏览器。 这个程序在有解释。 如何使用。 编译本机客户端。 $ git clone ...

    perl-IO-Socket-IP-0.39-6.module_el8.4.0+646+45e06e4a.noarch.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    socket.io-client-0.5.0.jar

    socket.io-client-0.5.0.jar包,在使用socket开发websocket的时候,用到的包。 socket.io-client-0.5.0.jar包,在使用socket开发websocket的时候,用到的包。

    socket简单应用---------一个可异机聊天的程序

    Socket编程是计算机网络通信的核心技术之一,主要用于实现不同设备之间的数据传输。在这个“socket简单应用——一个可异机聊天的程序”中,我们将探讨如何利用Socket进行简单的客户端-服务器架构的聊天程序设计。 ...

    Go实现socket.io-emitter-Go-下载

    1. **Socket.IO协议**:理解Socket.IO的数据传输格式和事件模型,包括连接、断开、心跳、以及自定义事件的处理。 2. **Go的网络编程**:Go语言提供了强大的net/http库来处理HTTP请求,同时,你需要熟悉如何创建TCP...

    计算机网络实验SOCKET编程----WEB服务器[C#版本].

    计算机网络实验中的SOCKET编程是网络通信领域的重要学习内容,特别是在构建WEB服务器时,SOCKET接口扮演着核心角色。本实验以C#语言为开发工具,深入探讨如何使用SOCKET实现一个简单的WEB服务器。 首先,我们需要...

    socket.io-server-java-3.0.0

    socket.io-server-java-3.0.0,Socket.IO 是一个库,可以在客户端和服务器之间实现低延迟, 双向和基于事件的通信:socket.io-server-java-3.0.0.tar.gzsocket.io-server-java-3.0.0.zip

    基于HPSocket实现 socket 通讯 - 修正版 ( C# demo 、 C++ dll )

    在IT行业中,网络通信是至关重要的一个领域,而Socket编程是构建网络应用程序的基础。本资源“基于HPSocket实现socket通讯 - 修正版 ( C# demo 、 C++ dll )”提供了一种实用的方法,帮助开发者高效地实现跨平台的...

    socket错误代码对应表

    ### Socket错误代码对应表 #### 引言 在进行网络编程的过程中,经常会遇到各种各样的错误,特别是当涉及到Socket通信时。了解这些错误的具体含义及其解决方法对于开发人员来说至关重要。本文将详细介绍一些常见的...

    socket通信-------vb.net(2005)

    Socket通信在IT行业中是网络编程的一个重要组成部分,特别是在VB.NET(Visual Basic .NET)环境下,它为开发者提供了创建网络应用程序的基础。VB.NET 2005版本虽然相对较老,但仍然广泛应用于各种项目中,尤其是那些...

    socket.io-client-2.2.0.zip

    标题中的"socket.io-client-2.2.0.zip"指的是Socket.IO客户端的2.2.0版本的源码或库文件,它是一个流行的JavaScript库,用于实现实时、双向通信在Web应用程序中。Socket.IO利用WebSocket协议,但在WebSocket不支持的...

Global site tag (gtag.js) - Google Analytics