1.socket服务器搭建思路

1) 目的:理解socket服务器工作机制

2) 思路:创建socket -> 把socket加入连接池 -> 处理接收信息 -> 握手动作 -> 发送信息

2.socket服务器代码

​ 注:复制到php文件,直接命令行可以运行,不需要其他支持

​ 特别注意:为了能传输中文_sendMsg做了json_encode()

<?php

/**
* Socket服务器
* @author wuchangliang 2018/1/17
*/
class SocketServer
{
private $sockets; //连接池
private $master;
private $handshake; /**
* @param $address
* @param $port
*/
public function run($address, $port)
{
//配置错误级别、运行时间、刷新缓冲区
echo iconv('UTF-8', 'GBK', "欢迎来到PHP Socket测试服务。 \n");
error_reporting(0);
set_time_limit(0);
ob_implicit_flush(); //创建socket
$this->master = $this->_connect($address, $port);
$this->sockets[] = $this->master; //运行socket
while (true) {
$sockets = $this->sockets;
$write = NULL;
$except = NULL;
socket_select($sockets, $write, $except, NULL); //$write,$except传引用
foreach ($sockets as $socket) {
if ($socket == $this->master) {
$client = socket_accept($socket);
$this->handshake = false;
if ($client) {
$this->sockets[] = $client; //加入连接池
}
} else {
//接收信息
$bytes = @socket_recv($socket, $buffer, 2048, 0);
if ($bytes <= 6) {
$this->_disConnect($socket);
continue;
}; //处理信息
if (!$this->handshake) {
$this->_handshake($socket, $buffer);
} else {
$buffer = $this->_decode($buffer);
$this->_sendMsg($buffer, $socket);
}
} }
}
} /**
* 创建socket连接
* @param $address
* @param $port
* @return resource
*/
private function _connect($address, $port)
{
//创建socket
$master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
or die("socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n");
socket_bind($master, $address, $port)
or die("socket_bind() failed: reason: " . socket_strerror(socket_last_error($master)) . "\n");
socket_listen($master, 5)
or die("socket_listen() failed: reason: " . socket_strerror(socket_last_error($master)) . "\n");
return $master;
} /**
* 握手动作
* @param $socket
* @param $buffer
*/
private function _handshake($socket, $buffer)
{
//握手动作信息
$buf = substr($buffer, strpos($buffer, 'Sec-WebSocket-Key:') + 18);
$key = trim(substr($buf, 0, strpos($buf, "\r\n")));
$new_key = base64_encode(sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
$new_message = "HTTP/1.1 101 Switching Protocols\r\n";
$new_message .= "Upgrade: websocket\r\n";
$new_message .= "Sec-WebSocket-Version: 13\r\n";
$new_message .= "Connection: Upgrade\r\n";
$new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; //记录握手动作
socket_write($socket, $new_message, strlen($new_message));
$this->handshake = true;
} /**
* 断开socket连接
* @param $socket
*/
private function _disConnect($socket)
{
$index = array_search($socket, $this->sockets);
socket_close($socket);
if ($index >= 0) {
array_splice($this->sockets, $index, 1);
}
} /**
* 发送信息
* @param $buffer
* @param $client
*/
private function _sendMsg($buffer, $client)
{
$send_buffer = $this->_frame(json_encode($buffer));
foreach ($this->sockets as $socket) {
if ($socket != $this->master && $socket != $client) { //广播发送(除了自己)
socket_write($socket, $send_buffer, strlen($send_buffer));
}
}
} /**
* 解析数据帧
* @param $buffer
* @return null|string
*/
private function _decode($buffer)
{
$len = $masks = $data = $decoded = null;
$len = ord($buffer[1]) & 127;
if ($len === 126) {
$masks = substr($buffer, 4, 4);
$data = substr($buffer, 8);
} else if ($len === 127) {
$masks = substr($buffer, 10, 4);
$data = substr($buffer, 14);
} else {
$masks = substr($buffer, 2, 4);
$data = substr($buffer, 6);
}
for ($index = 0; $index < strlen($data); $index++) {
$decoded .= $data[$index] ^ $masks[$index % 4];
}
return $decoded;
} /**
* 处理返回帧
* @param $buffer
* @return string
*/
private function _frame($buffer)
{
$len = strlen($buffer);
if ($len <= 125) {
return "\x81" . chr($len) . $buffer;
} else if ($len <= 65535) {
return "\x81" . chr(126) . pack("n", $len) . $buffer;
} else {
return "\x81" . char(127) . pack("xxxxN", $len) . $buffer;
}
}
} $sc = new SocketServer();
$sc->run('127.0.0.1', 2046);
 

3.客户端代码

​ 注:直接复制到html,和上面的php文件在同一文件夹即可,特别注意onmessage解析的两层 parse

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript"type="text/javascript">
websocket = new WebSocket('ws://127.0.0.1:2046/');
websocket.onopen = function(evt) {
console.log('connect');
websocket.send('{"data":"您好,世界!"}');
};
websocket.onclose = function(evt) {
console.log('onclose');
console.log(evt);
};
websocket.onmessage = function(evt) {
console.log('onmessage');
if (evt.data) {
console.log(JSON.parse(JSON.parse(evt.data)));
}
};
websocket.onerror = function(evt) {
console.log('onerror');
console.log(evt);
};
function sendMsg(){
var sendData = { 'data': document.getElementById('name').value};
websocket.send(JSON.stringify(sendData));
}
</script>
</head>
<body>
<h2>WebSocket Test</h2>
<input type="text" name="name" id="name" />
<a href="javascript:;" onclick="sendMsg()">点击发送</a>
</body>
</html>

4.测试示例

PHP Socket服务器搭建和测试的更多相关文章

  1. kafka服务器搭建与测试

    kafka服务器搭建 kafka自身集群信息的管理以及对producer和consumer的信息管理是通过zookeeper实现的,zookeepr是kafka不可分割的一部分,所以搭建zookeep ...

  2. 【转】 Ubuntu samba服务器搭建及测试--不错

    原文网址:http://blog.csdn.net/longfeey/article/details/5937968 Ubuntu samba服务配置是很不错的文件应用很有学习价值, 这里我主要讲解U ...

  3. 通过线程监控socket服务器是否done机

    现实中的socket可能会因为各种原因done机,但这么重要的服务器怎么能允许这种事情发生?这次我们就来通过一个线程去监控socket服务器,如果done机重新将其启动. 下面是监控项目和socket ...

  4. Socket实现仿QQ聊天(可部署于广域网)附源码(2)-服务器搭建

    1.前言 这是本系列的第二篇文章,第一篇文章得到了很多朋友们的支持,在这里表示非常的感谢.对于这一系列文章需要补充的是这只是一篇入门级别的Socket通信文章,对于专业人员来说完全可以跳过.本文只介绍 ...

  5. Okra框架(二) 搭建Socket服务器

    本文将介绍使用Okra框架帮助开发者快速搭建高性能应用程序Socket服务端. 博主接触的网络游戏(包含但不限于网页, 手机)的服务端通信使用的协议基本上就Socket,Http或是WebSocket ...

  6. Service系统服务(四):搭建单区域DNS服务器、特殊DNS解析、配置DNS子域授权、搭建并测试缓存DNS

    一.搭建单区域DNS服务器 目标: 本例要求要求为DNS区域tedu.cn搭建一台DNS服务器,以便用户能通过域名的方式访问网站.测试阶段主要提供以下正向记录: svr7.tedu.cn ---> ...

  7. Nginx 服务器搭建

    什么是Nginx ? Nginx与Apache IIS等软件一样,是一款服务器软件,为web站点提供服务 除此之外,Nginx 还是一款反向代理服务器,我们可以利用Nginx实现负载均衡 所谓负载均衡 ...

  8. Java游戏服务器搭建

    一.前言 此游戏服务器架构是一个单服的形式,也就是说所有游戏逻辑在一个工程里,没有区分登陆服务器.战斗服务器.世界服务器等.此架构已成功应用在了多款页游服务器 .在此框架中没有实现相关业务逻辑,只有简 ...

  9. WebRTC 入门教程(二)| WebRTC信令控制与STUN/TURN服务器搭建

    WebRTC 入门教程(二)| WebRTC信令控制与STUN/TURN服务器搭建 四月 4, 2019 作者:李超,音视频技术专家.本文首发于 RTC 开发者社区,欢迎在社区留言与作者交流. htt ...

随机推荐

  1. css颜色 hsla 和line-gradient

    h 表示色调 从0-360 s 饱和度  0 - 100% l 亮度    0 -100% a 透明度  0-1

  2. window下隐藏apache版本和PHP脚本等敏感信息

    隐藏Apache信息 1.1 主配置中启用httpd-default.conf 文件: conf/httpd.Conf 找到httpd-default.conf,删除前面的注释“#”,改成如下 Inc ...

  3. Android打包异常

    Android在打包的时候,报错: 找不到类,或者打包之后运行找不到类,都可以在混淆文件中添加这个属性: -dontoptimize 通过测试,都可以解决. 来自为知笔记(Wiz)

  4. Javascript基础--运算符与表达式

    一.运算符 1.运算符分类: 按功能:算术运算符:+.-.*./.%.++.-- 例:12+12-11+5*6+20/5+5%2+(5%-2)+(-5++2)+(a++)+(++a)+(--a)+(a ...

  5. [Maven]Eclipse集成遇到的问题

    当maven项目导入到eclipse中后使用eclipse提供的maven命令执行任意一个出现 Exception in thread "main" java.lang.Unsup ...

  6. 怎样学习webpack - 走心分享

    很多朋友可能都知道webpack,也见过webpack的代码,但是不明白里面一坨一坨的东西是什么意思,到底有什么用处!我们每个人学习一个新东西可能都会有这个过程,但是我个人觉得webpack可能是最混 ...

  7. SqlServer-Cursor讲解一

    原创文章,转载必需注明出处:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/introduce-for-sqlserver-s-cu ...

  8. 377. Combination Sum IV 70. Climbing Stairs

    back function (return number) remember the structure class Solution { int res = 0; //List<List< ...

  9. PASCAL VOC数据集分析

    http://blog.csdn.net/zhangjunbob/article/details/52769381

  10. bootstrap suggest搜索建议插件

    近日因工作需要看了下此插件. 首先下载bootstrap js包.添加此插件的引用.注意css样式要引用,不能忘记. 前台页面代码,因为楼主做的是选项卡切换查询不同的结果. <tr> &l ...