我正在尝试了解websockets。
我看过2个例子here in doc和here。
这两个示例都使用无限循环循环,在新客户端连接时进行侦听,何时进行有趣的操作以及何时断开连接。
我的问题是:使用websockets(无限循环循环)比每x次http请求的ajax解决方案更好吗?
答案 0 :(得分:4)
AJAX和WebSockets有很大不同。询问一个人是否比另一个好,就像问一把螺丝刀是否比锤子更好。
WebSockets用于实时交互式通信。 WebSocket连接的两端都可以发送数据,另一端会在几毫秒内收到数据。连接保持打开状态,减少了因连接协商而导致的延迟。
但是,它只能与HTTP很好地配合。也就是说,它可以很好地与WebSocket识别的代理和防火墙一起使用。 WebSocket流量绝对不是HTTP流量,除了客户端的第一个数据包,它请求从HTTP切换到WebSocket协议。
另一方面,AJAX是纯HTTP。 AJAX和标准Web请求之间的唯一区别是AJAX请求由客户端脚本启动,响应可用于同一脚本而不是重新加载页面。在AJAX和WebSockets中,客户端脚本可以接收数据并在同一脚本中使用它。这就是相似之处的结束。
WebSockets建立永久连接,双方可以随时发送数据,也可以随时静静地坐着。使用AJAX,客户端发出请求,服务器响应。
例如,如果您要设置新的消息通知系统,如果您使用的是WebSockets,则只要有新消息可用,服务器就会将其直接发送到浏览器。如果没有新消息,则服务器保持安静。如果您使用的是AJAX,客户端会定期向服务器发送请求,该服务器始终会响应,要么说没有新消息,要么发送待处理的通知。服务器无法在其结束时启动,它必须等待AJAX请求。
服务器端,事情与传统的PHP Web开发范例不同。典型的WebSocket服务器将是一个独立的CLI应用程序,作为守护进程运行。 (如果最后一句话没有意义,请花些时间花时间真正了解如何管理服务器。)
这意味着多个客户端将连接到同一个脚本,而$_GET
和$_SESSION
等超全局变量将毫无意义。在一个小用例中概念化似乎很容易,但请记住,您很可能希望从站点的其他部分获取信息,这通常意味着使用绝对没有访问HTTP请求之外的数据的概念的库和框架/响应模型。
因此,为简单起见,您通常希望坚持使用AJAX请求和定期轮询,除非您有办法重新考虑网络数据并可能重新实现图书馆自动化的内容,如果您这样做的话。重新寻找更新标准网络流量。
至于服务器的循环:
这不是一个繁忙的循环,它是一个IO阻塞循环。
如果服务器尝试读取网络数据并且没有可用,则操作系统将阻止(暂停)脚本并继续执行其他任何需要完成的操作。在我的WS服务器中,我阻止等待网络流量一次最多1秒,然后脚本返回检查并查看是否还有其他新事件发生,我应该通知我的客户。通常,在服务器返回其IO阻塞状态等待线路上的新数据之前,这几乎是几毫秒。其他一些人使用LibEv实现了我的服务器,这允许他们响应网络IO之外的事件,而不必等待阻止超时。
这几乎是每个服务器都能做到的事情。这就是为什么你可以让Apache主动监听和服务网络流量,而不管每台运行Apache的服务器都是以100%CPU使用率挂钩,即使没有流量也是如此。
最后,WebSockets是一项很棒的技术,但Web库和框架根本不是为了使用而构建的。因此,除非您在一个完整的AJAX请求等待3秒的系统中工作太长,否则最好使用AJAX。如果您正在编写多人互动游戏或聊天系统,那么您已经找到了完美的WebSockets用途。
我衷心鼓励每个人学习WebSockets ...但它并不是一个神奇的子弹,网络的很少部分都是以人们可以真正使用它的方式设计的。
答案 1 :(得分:3)
是的,在许多情况下,套接字更好。
它不是 Request processing failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: Timed out after 30000 ms while waiting for a server that matches WritableServerSelector. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSecurityException: Exception authenticating}, caused by {com.mongodb.MongoCommandException: Command failed with error 18: 'auth failed' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "auth failed", "code" : 18 }}}]; nested exception is com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches WritableServerSelector. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSecurityException: Exception authenticating}, caused by {com.mongodb.MongoCommandException: Command failed with error 18: 'auth failed' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "auth failed", "code" : 18 }}}]
,它只是liveloop,它存在于每个守护程序应用程序中。
同步forever loop with 100% cpu utilizing
操作是我们99.99%的时间。
Ajax心跳是更多的流量,更多的服务器CPU和内存。
答案 2 :(得分:0)
我也处于学习阶段。我已经构建了一个基于php的websocket服务器,并与网页进行通信。也许我的2c视角很有用。
使用可用的源作为起点使websocket服务器(wss)工作并不困难,但接下来要做的就是。
wss在CLI的CLI版本中运行。后期模型浏览器加载包含对wss的请求的普通http或https页面,以及页面需要执行的任何其他操作,发生握手。然后可以在浏览器和wss之间直接进行通信。这是低开销,因此快速而简单。很酷。关于该链接的内容需要被两端理解 - 子协议。你可能不得不在php和javascript中自己推出。没有更多的http标题,网址等等。
wss是一个长寿的,有状态的php实例(非常不像apache等,忘了发送页面)。整个应用程序可以在wss实例中运行,为自己和每个连接的客户端保持状态。曾经有人说,php太长时间没有泄漏,但我再也听不到这么多了。但我相信你还是要小心记忆。
但是,作为单个php实例,客户端实例之间通常没有分离。例如,类中的静态与每个类实例共享,因此与每个客户端共享。因此,对于与一堆客户端共享数据的单个用户样式应用程序,这非常棒。我可以看到Ajax类型的调用可以用这种方式替换,但如果应用程序仍然需要重建状态来为每个客户端提供服务,然后释放它以节省资源,那么这似乎会减少优势。
更进一步,为客户保持真正有状态的实例似乎可能是下一步。复制传统的基于会话的系统是一种可能性,或者分叉新的PHP解释器并通过套接字等来管理父母和孩子之间的通信。但是,这将需要每个客户端的资源,这将严重限制任何非平凡的应用程序。
或者也许可以将大部分应用程序放在父级中,让孩子们只做客户特定的事情。或者将应用程序设计分解为可以通过套接字直接通信的小型独立单元。现在,套接字通信似乎正在流行起来。
正如Ghedpunk在很多方面所说,现实世界似乎还没有准备好实现Web套接字概念的全部潜力,但它肯定可以取代Ajax。服务器发送而不被问到的额外优势开启了以前难以考虑的新可能性。