纯前端的进军6--套接字(Socket)与socket.io
更新日期:
《纯前端的进军》系列主要作为曾经的纯前端,对后台和底层的一些弥补,涉及进程、网络通信,以及对node.js和相关框架的学习。本节我们来一起认识认识套接字(Socket)和socket.io。
socket.io
套接字(Socket)概念
套接字(Socket)起源于UNIX,在Unix一切皆文件哲学的思想下,Socket是一种”打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个”文件”,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。0
Socket是一种进程间通信机制,提供一种供应用程序访问通信协议的操作系统调用,并且通过将Socket与Unix系统文件描述符相整合,使得网络读写数据(或者服务调用)和读写本地文件一样容易。
Socket是一序列的“指令” ,按汉语的理解,已经具备了“套接”(建立网络通讯或进程间通讯)和“字”(可交互的有序指令串)的概念,故称套接字。
Socket与网络进程通信
Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
扯回第一节《node.js聊天室1–网络进程通信和TCP/IP协议》中的进程通信,两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一。
我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。
应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
建立Socket连接
上面提到,Socket是”打开—读/写—关闭”模式的实现。
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
服务器监听:
服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:
指客户端的套接字提出连接请求,要连接的目标是服务器端的套接S字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
连接确认:
当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
以使用TCP协议通讯的Socket为例,其交互流程大概是这样子的:
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
socket.io
socket.io是基于Socket连接后对网络输入输出流的处理。
socket.io是一个面向实时web应用的JavaScript库。它使得服务器和客户端之间实时双向的通信成为可能。socket.io将WebSocket和轮询(Polling)机制以及其它的实时通信方式封装成了通用的接口,并且在服务端实现了这些实时机制的相应代码。
socket.io有两个部分:在浏览器中运行的客户端库,和一个面向Node.js的服务端库。两者有着几乎一样的API。
像Node.js一样,socket.io也是事件驱动的。
socket.io主要使用WebSocket协议。但是如果需要的话,socket.io可以回退到几种其它方法,例如Adobe Flash Sockets,JSONP拉取,或是传统的AJAX拉取,并且在同时提供完全相同的接口。
尽管可以被用作WebSocket的包装库,它还是提供了许多其它功能,比如广播至多个套接字,存储与不同客户有关的数据,和异步io操作。
优势:socket.io会自动选择合适双向通信协议,仅仅需要程序员对套接字的概念有所了解。
劣势:socket.io要求客户端与服务器端均须使用该框架
socket.io并不是一个基本的、独立的、能够回退到其它实时协议的WebSocket库,它实际上是一个依赖于其它实时传输协议的自定义实时传输协议的实现。该协议的协商部分使得支持标准WebSocket的客户端不能直接连接到socket.io服务器,并且支持socket.io的客户端也不能与非socket.io框架的WebSocket或Comet服务器通信。
使用socket.io
函数
服务器还是客户端都有emit
和on
这两个函数,可以说socket.io的核心就是这两个函数了,通过emit
和on
可以轻松地实现服务器与客户端之间的双向通信。
emit
- 用来发射一个事件或者说触发一个事件
- 第一个参数为事件名,第二个参数为要发送的数据,第三个参数为回调函数(一般省略,如需对方接受到信息后立即得到确认时,则需要用到回调函数)
on
:- 用来监听一个
emit
发射的事件 - 第一个参数为要监听的事件名,第二个参数为一个匿名函数用来接收对方发来的数据,该匿名函数的第一个参数为接收的数据,若有第二个参数,则为要返回的函数
- 用来监听一个
在服务器端区分以下三种情况:
socket.emit()
:向建立该连接的客户端广播socket.broadcast.emit()
:向除去建立该连接的客户端的所有客户端广播io.sockets.emit()
:向所有客户端广播,等同于上面两个的和
事件
socket.io提供了三种默认的事件(客户端和服务器都有):connect
、message
、disconnect
。当与对方建立连接后自动触发connect
事件,当收到对方发来的数据后触发message
事件(通常为socket.send()
触发),当对方关闭连接后触发disconnect
事件。
此外,socket.io还支持自定义事件。
参考
- 《Socket基本原理》
- 《简单理解Socket》
- 《揭开Socket编程的面纱》
- 《Linux Socket编程(不限Linux)》
- Socket.IO - 维基百科,自由的百科全书
- 《第一章 socket.io 简介及使用》
结束语
本节我们主要介绍了套接字(Socket),以及相关的JavaScript库–socket.io。
其实前面几节作为知识补充,大部分都是网络搜刮汇总来的,本骚年自身的功力也没成长到能有一定的思考产物,这块或许也需要增长呢。
查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢
码生艰难,写文不易,给我家猪囤点猫粮了喵~