前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WebSocket协议 与 IO多路复用

WebSocket协议 与 IO多路复用

作者头像
nnngu
发布2021-01-05 14:35:29
2.6K0
发布2021-01-05 14:35:29
举报
文章被收录于专栏:nnngu

最近在把 Facebook Message 接入客服系统,由于与 Facebook Message 对接的收发消息都是通过调用 http 接口来实现的,如果想实现即时通讯,还需要在中间加一个 WebSocket 来转发消息。如下图:

其中用到了 WebSocket 协议和 IO多路复用相关的知识。在这里做一个学习记录。

为什么需要 WebSocket 协议

  • 因为 HTTP 协议有一个缺陷:通信只能先由客户端发起,然后服务器再作出响应,并不能由服务器主动向客户端推送消息。
  • WebSocket 协议最大的特点是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息。

WebSocket 与 socket 的之间关系

  • WebSocket 是一个网络通信协议,是属于网络七层模型中的应用层的协议,同样属于应用层的协议还有 HTTP 协议、FTP协议、SMTP协议等等。
  • 而 socket 是操作系统提供的一套接口,利用这一套接口就可以编写程序实现进程之间的通信、网络通信等功能。

一个 WebSocket 连接是如何建立起来的

WebSocket 连接的初期是基于 HTTP 协议的,假如 WebSocket 的地址是这个:wss://www.xxx.com/websocket ,在连接 WebSocket 的初期浏览器首先会向这个地址发出一个 HTTP GET 请求,请求头信息截图如下:

红色框标出的是比较重要的请求头:

  • Connection: Upgrade 告诉服务端这个连接需要升级。
  • Upgrade: websocket 告诉服务端需要升级到 WebSocket 协议。
  • Sec-WebSocket-Key: d97OXZzuRlSJV/6SrX+uUA== 是浏览器随机生成的一个字符串。

服务端接收到这个 HTTP 请求,会作出响应,响应头的截图如下:

红色框标出的是比较重要的响应头:

  • HTTP/1.1 101 Switching Protocols 告诉浏览器,服务端已经成功切换了协议。
  • Sec-WebSocket-Accept: axMY+KY1i8F9y9zyUMPhrfuYtPw= 这个是服务端拿到请求头中的 Sec-WebSocket-Key: d97OXZzuRlSJV/6SrX+uUA==,在 d97OXZzuRlSJV/6SrX+uUA== 后面拼接一个固定的字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ,对拼接后的字符串做SHA1,得到16进制表示的字符串,将每两位当作一个字节进行分隔,得到字节数组,再对这个字节数组做Base64,得到最后的结果,把最后的结果放到 Sec-WebSocket-Accept 响应头里返回。

浏览器也会使用同样的算法把请求头中的 Sec-WebSocket-Key 算出一个结果,将这个结果与服务端返回的 Sec-WebSocket-Accept 做对比。就像对暗号一样,两边的暗号相同,WebSocket 连接就会被建立起来。这个过程也叫做握手,握手成功后,就可以愉快的使用这个 WebSocket 连接来收发消息了。

操作系统提供的 socket 接口

WebSocket 的通信,其实是利用了操作系统给我们提供的一套 socket 编程接口。接下来,我把 Linux 系统中给我们提供的 socket 头文件找出来,看看里面有哪些接口提供给我们使用,以及每个接口的作用是什么。找到 socket.h 头文件在如下位置:

打开 socket.h 文件:

打开另一个目录下的 socket.h 文件:

socket 编程的流程如下:

在 socket 服务端除了用到上面流程图列出来的函数,还用到了 setsockopt() 函数,这个函数可以用来设置一些 socket 选项。比如:我在开发调试的过程中,改完代码后需要杀掉运行中的 socket 进程,重新运行新编译出来的 socket。这时候经常会运行失败,原因是进程是立马被杀掉了,但是原来被进程监听的那个端口会进入 TIME_WAIT 状态,而不会立即被释放出来。解决方法有两个:1、杀掉进程后等一会儿,端口被释放了就能被再次使用了。2、在绑定端口之前,利用 setsockopt() 函数,给端口设置一个 SO_REUSEPORT 选项,这样杀掉这个进程后立马重新运行这个进程,也不会运行失败。

IO 多路复用(IO Multiplexing)

在项目中还用到了IO 多路复用:

  • 什么是 IO ?答:计算机的输入和输出(Input、Output)
  • 什么是 IO 多路复用?答:网上看到一个例子比较有意思。假如一个班有 50 名学生,老师在黑板上布置了一道题目让学生做, 如果老师按照学号先看 1 号学生做出来没有,做出来了就检查他,还没做出来就在原地等他做出来,然后检查他,检查完 1 号学生才轮到 2 号学生......这个就是单进程/单线程。 如果老师能分身,一共分出 50 个分身,每个学生旁边站一个老师......这就是多进程/多线程。 如果老师站在讲台上,有哪位学生做完了就举手,老师下去检查他,检查完老师又回到讲台上,看有哪位同学举手,然后去检查他......这就是 IO 多路复用。

IO 多路复用有3 种:select、poll、epoll。在项目中用到的是 epoll。接下来,我把 Linux 系统中给我们提供的 epoll 头文件找出来,看看里面有哪些接口提供给我们使用,以及每个接口的作用是什么。找到 epoll.h 头文件在如下位置:

打开 epoll.h 文件:

epoll 的使用流程如下:

看到网上有文章说 redis 和 nginx 也有使用 epoll,为了验证他讲的是不是真的。我们找 redis 和 nginx 的源码看一看:

果然 redis 和 nginx 的源码里面都有使用 epoll。

WebSocket 编程,还有其他方案

Swoole 扩展:

  • 需要 php-7.1 或更高版本
  • 用法如下:
代码语言:javascript
复制
//创建WebSocket Server对象,监听0.0.0.0:9502端口
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9502);

//监听WebSocket连接打开事件
$ws->on('open', function ($ws, $request) {
    var_dump($request->fd, $request->server);
    $ws->push($request->fd, "hello, welcome\n");
});

//监听WebSocket消息事件
$ws->on('message', function ($ws, $frame) {
    echo "Message: {$frame->data}\n";
    $ws->push($frame->fd, "server: {$frame->data}");
});

//监听WebSocket连接关闭事件
$ws->on('close', function ($ws, $fd) {
    echo "client-{$fd} is closed\n";
});

$ws->start();

想了解更多,请参考 Swoole 官方文档:https://wiki.swoole.com/#/

Workerman:

在学习 WebSocket 的过程中,还发现了一个纯 PHP 实现的框架:Workerman

  • 需要 PHP 5.3.3 或更高版本
  • 用法如下:
代码语言:javascript
复制
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';

// 注意:这里与上个例子不同,使用的是websocket协议
$ws_worker = new Worker("websocket://0.0.0.0:2000");

// 启动4个进程对外提供服务
$ws_worker->count = 4;

// 当收到客户端发来的数据后返回hello $data给客户端
$ws_worker->onMessage = function($connection, $data)
{
    // 向客户端发送hello $data
    $connection->send('hello ' . $data);
};

// 运行worker
Worker::runAll();

想了解更多,请参考 Workerman 官方文档:http://doc.workerman.net/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-01-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要 WebSocket 协议
  • WebSocket 与 socket 的之间关系
  • 一个 WebSocket 连接是如何建立起来的
  • 操作系统提供的 socket 接口
  • IO 多路复用(IO Multiplexing)
  • WebSocket 编程,还有其他方案
    • Swoole 扩展:
      • Workerman:
      相关产品与服务
      云数据库 Redis®
      腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档