阅读(2664) (9)

启用 Socket 服务器

2017-06-13 15:39:52 更新

ModPHP 提供了一个默认的 Socket 服务器程序逻辑,用以配合模块数据操作。

要启动默认的 Socket 服务器,你只需要在服务器的控制台中运行站点根目录的 socket-server.php 文件即可。如果你使用 Apache 服务器,你也可以在浏览器中开启,但需要验证管理员权限。注意:浏览器可能无法加载 socket-server.php 页面输出的内容,访问后直接关闭窗口即可。

监听端口由 config('mod.SocketServer.port') 设置,默认为 8080。

开启 Socket 服务器不会影响正常的 Apache 网站,但是如果你的程序代码经过改动(例如更新系统),则需要重新启动 Socket 服务。如果你是在浏览器中启用 Socket 服务器的,那么你需要通过关闭 Apache 来关闭 Socket 服务器,然后才能再次重启它。

当 Socket 服务器启动之后,你就可以通过 JSON 进行数据交换了,所有能够通过 URL 访问 mod.php 进行请求的操作,也能通过 Socket 服务器进行。

该 Socket 服务器仅用于传输文本数据(JSON),不支持传输二进制数据,但是,你可以将二进制数据转换为文本(例如图像转 base64)进行传输,或者自己编写另外的 Socket 程序逻辑。

客户端通过发送 JSON 数据向服务器提交请求,服务器将操作结果回应以 JSON 数据,实现前后端一致。需要注意的是,除非是重现会话,否则 JSON 中必须包含 {obj} 和 {act} 属性,其他属性将作为请求参数。

重现会话:


如果客户端已经通过其他方式进行了用户登录,如 AJAX,那么可以将 cookie 中的 Session ID 传给 Socket 服务器,从而在 WebSocket 中恢复登录状态。当然,如果你没有通过其他方式进行登录,也可以使用 WebSocket 进行登录,登录后会将用户信息和 Session ID 通过 JSON 同时返回给客户端,客户端将 Session ID 写入 Cookie 中,从而在浏览其他页面时也保持会话。

重现会话示例:

var ws = new WebSocket('ws://localhost:8080');
ws.open = function(){
    var sid = document.cookie.match(/PHPSESSID=(.*)b/)[1];
    ws.send(JSON.stringify({PHPSESSID: sid}));
}

登录示例:

var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function(){
    var data = {
        obj: 'user',
        act: 'login',
        user: 'someone',
        user_password: 'not_show_here'
    };
    ws.send(JSON.stringify(data));
}
ws.onmessage = function(e){
    var result = JSON.parse(e.data);
    if(result.success && result.PHPSESSID){
        document.cookie += 'PHPSESSID='+result.PHPSESSID; //将 Session ID 写到 cookie 中
    }
}

需要注意的是,在重现会话或者使用 WebSocket 进行登录之后,之后的其他操作就已经运行在已登录状态了,服务器会保存登录信息,不需要客户端再提交 Session ID。例如,要获取当前登录用户的信息,只需要这样做:

ws.send(JSON.stringify({obj: 'user', act: 'getMe'}));

Socket 服务器也支持页面判断功能,需要客户端发送数据时同时发送 HTTP_REFERER 为当前 URL 地址给服务器(自定义来路页面)。例如上面获取当前用户信息的例子,可以这样:

ws.send(JSON.stringify({obj: 'user', act: 'getMe', HTTP_REFERER: location.href}));

虽然,ModPHP 提供了非常便捷的搭建 Socket 服务器的方法,但是你必不可滥用它。例如,在一个 HTML 页面,你应该只设置一个指向同一服务器的 WebSocket 的实例。更好的就是,使用 iframe 等方式,实现多个页面使用同一个 WebSocket 实例。这样可以有效地节约服务器资源,从而加快网站运行速度。

其他客户端类型连接服务器:

其他客户端类型或者其他编程语言编写得 Socket 客户端的连接和通讯与 WebSocket 大同小异,但和 WebSocket 协议相比,这些客户端不需要使用复杂的编码和解码过程,直接发送原始报文即可。

ModPHP 提供了在 Socket 服务器下进行网站地址判断的功能(如果網站地址未固定),这个特性,是依赖客户端发送的握手包来实现的。在 WebSocket 协议中,客户端会将一个 HTTP 请求头作为握手包发送给服务器。ModPHP 利用这个请求头,来计算出网站的 URL 地址。

因此,你也可以在普通的 Socket 连接中,发送一个 HTTP 请求头格式的数据,作为握手包,来让服务器自动“计算”网站的 URL 地址。

将 WebSocket 运行于多线程中:

请查看《将 Socket 服務器运行于多线程环境中》。