<?php
$demo = new ws('192.168.90.47',12345);
$demo->run(); class ws
{
//当前服务端主连接
private $currentFirstSocket;
//存放客户端socket连接
private $socketList = array();
//存放自定义的客户端连接
private $clientList = array(); public function __construct($address, $port)
{
$this->currentFirstSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($this->currentFirstSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($this->currentFirstSocket, $address, $port);
socket_listen($this->currentFirstSocket,2); $this->socketList[] = $this->currentFirstSocket;
self::notice('Server Started ...');
self::notice('Listening on : ' . $address . ' port ' . $port);
} public function run()
{
while (TRUE) {
$connect = $this->socketList;
$write = NULL;
$except = NULL;
self::notice(count($this->socketList) . " wait to connect ....");
socket_select($connect, $write, $except, NULL); foreach ($connect as $currentConnect) {
self::notice($currentConnect . " into connect"); //第一次连接
if ($currentConnect === $this->currentFirstSocket) {
$connectSuccessHandle = socket_accept($this->currentFirstSocket);
$this->socketList[] = $connectSuccessHandle;
$this->clientList[] = array(
"handshake" => false,
"clientHandle" => $connectSuccessHandle
);
self::notice($connectSuccessHandle. " new connect success ...");
} else {
$currentConnectKey = $this->searchSocketByHandle($currentConnect);
//第二次接收到的是客户端发送的websocket头协议
$len = @socket_recv($currentConnect, $buffer, 2048, 0);
self::notice("len ".$len);
if ($len < 10) { //如果接收到的信息长度小于10当作客户端退出
$this->socketExit($currentConnectKey);
self::notice($currentConnect . " exit" . " have:" . count($this->socketList));
break;
}
//检查是否握手,去握手
if ($this->clientList[$currentConnectKey]['handshake'] === false) {
self::notice($currentConnect." handshake success...");
$this->handshake($currentConnectKey, $buffer);
} else {
//正式连接,解包客户端的信息
$buffer = $this->unmask($buffer);
self::notice($currentConnect." send to server..."); $this->send($buffer);
}
}
}
}
} /*
* 握手
* */
private function handshake($currentConnectKey, $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($this->clientList[$currentConnectKey]['clientHandle'], $new_message, strlen($new_message));
$this->clientList[$currentConnectKey]['handshake'] = true;
} /*
* 客户端退出处理
* */
private function socketExit($currentConnectKey)
{
$currentSocket = $this->clientList[$currentConnectKey]['clientHandle'];
socket_shutdown($currentSocket);
socket_close($currentSocket);
foreach ($this->socketList as $key => $val) {
if ($val === $currentSocket) {
self::notice("delete " . $this->socketList[$key]);
unset($this->socketList[$key]);
}
}
unset($this->clientList[$currentConnectKey]);
} /*
* 发送信息给所有客户端
* */
private function send($sendMsg)
{
$sendMsg = $this->mask($sendMsg);
foreach ($this->clientList as $val) {
self::notice("write to " . $val['clientHandle'] . " " . $sendMsg);
socket_write($val['clientHandle'], $sendMsg, strlen($sendMsg));
}
} /*
* 解包客户端发送的信息
* */
function unmask($text)
{
$length = ord($text[1]) & 127;
if ($length == 126) {
$masks = substr($text, 4, 4);
$data = substr($text, 8);
} elseif ($length == 127) {
$masks = substr($text, 10, 4);
$data = substr($text, 14);
} else {
$masks = substr($text, 2, 4);
$data = substr($text, 6);
}
$text = "";
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i % 4];
}
return $text;
}
/*
* 封包信息发送给客户端
* */
function mask($text)
{
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text); if ($length <= 125)
$header = pack('CC', $b1, $length);
elseif ($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif ($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header . $text;
} private function searchSocketByHandle($handle)
{
foreach ($this->clientList as $key => $value) {
if ($value['clientHandle'] === $handle) {
return $key;
}
}
return false;
} private static function notice($message, $num = 1)
{
echo date("H:i:s") . " " . $message;
echo str_repeat("\n", $num);
}
}

客户端

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>client</title>
<script src="bootstrap/js/jq.js"></script>
<script>
var socket;
$(document).ready(function(e) {
connect();
}); function connect(){
var url='ws://192.168.174.132:12345';
socket = new WebSocket(url);
socket.onopen=function(){
if(socket.readyState==1){
socket.send("hello this is html");
}else{
console.log("login fail");
}
}
socket.onmessage=function(msg){
console.log(msg);
} socket.onclose=function(){
console.log("close");
}
} function sendMsg()
{
var contetent = $("#test").val();
console.log("send: "+contetent);
socket.send(contetent);
} </script>
</head>
<body> <input type="input" id="test">
<input type="button" onclick="sendMsg()" value="send"> </body>
</html>

websocket服务器+客户端的更多相关文章

  1. 开源的C#实现WebSocket协议客户端和服务器websocket-sharp组件解析

    很久没有写博客了(至少自己感觉很长时间没有写了),没办法啊,楼主也是需要生活的人啊,这段一直都在找工作什么的.(整天催我代码的人,还望多多谅解啊,我会坚持写我们的项目的,还是需要相信我的,毕竟这是一个 ...

  2. C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析

    看到这篇文章的题目,估计很多人都会问,这个组件是不是有些显的无聊了,说到web通信,很多人都会想到ASP.NET SignalR,或者Nodejs等等,实现web的网络实时通讯.有关于web实时通信的 ...

  3. HTTPS请求HTTP接口被浏览器阻塞,python实现websocket客户端,websocket服务器,跨域问题,dwebsocket,https,拦截,服务端

    HTTPS请求HTTP接口被浏览器阻塞,python实现websocket客户端,websocket服务器,跨域问题,dwebsocket,https,拦截,服务端 发表时间:2020-03-05 1 ...

  4. HTML5学习总结-08 WebSocket 服务器推送

    一 WebSocket 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展 ...

  5. WebSocket 服务器4

    Java Websocket实例 Websocket   2015-04-11 14:11:54 发布 您的评价:       4.4   收藏     6收藏 介绍 现很多网站为了实现即时通讯,所用 ...

  6. 根据Unix哲学来编写你的HTML5 Websocket服务器来实现全双工通信

    websocketd代表WebSocket的守护进程 websocketd处理的是浏览器和服务器之间的WebSocket连接,它会启动你所指定的服务器端应用来对WebSockets进行处理,然后在浏览 ...

  7. 实现一个websocket服务器-理论篇

    本文是Writing WebSocket servers的中文文档,翻译自MDNWriting WebSocket servers.篇幅略长,个人能力有限难免有所错误,抛砖引玉共同进步. websoc ...

  8. 如何实现websocket服务器-理论篇

    WebSocket 服务器简单来说就是一个遵循特殊协议监听服务器任意端口的tcp应用.搭建一个定制服务器的任务通常会让让人们感到害怕.然而基于实现一个简单的Websocket服务器没有那么麻烦. 一个 ...

  9. node实现一个WEBSOCKET服务器

    早点时候翻译了篇实现一个websocket服务器-理论篇,简单介绍了下理论基础,本来打算放在一起,但是感觉太长了大家可能都看不下去.不过发现如果拆开的话,还是不可避免的要提及理论部分.用到的地方就简要 ...

随机推荐

  1. scala (5) 可变序列和不可变序列

    /** * 序列分为可变长和不可变长,序列其实就是list,底层是链表结构 * 特点:插入有序,可重复,增加和移除元素很快,查询慢 * 不可变长序列:List * 可变长序列:ListBuffer * ...

  2. 114. Unique Paths [by Java]

    Description A robot is located at the top-left corner of a m x n grid. The robot can only move eithe ...

  3. IDEA的基本配置

    一.安装 常规下载安装,换路径即可. 亲测可用破解方法:进入ide主页面,help-register-license server,然后输入 http://idea.iteblog.com/key.P ...

  4. 20155231 实验三 敏捷开发与XP实践

    20155231 实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 相关工具 实验要求 没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器&g ...

  5. 20155310 2016-2017-2 《Java程序设计》第九周学习总结

    20155310 2016-2017-2 <Java程序设计>第九周学习总结 教材学习内容总结 JDBC入门 •数据库本身是个独立运行的应用程序 •撰写应用程序是利用通信协议对数据库进行指 ...

  6. 电信NB-IOT的温湿度采集器开发记录

    1. 首先打开浏览器,登录电信商用服务器,上传profile文件 2. 上传编解码插件在,注意的是,上传编解码插件是电信测试用服务器平台(不同的网址),反正不明白电信搞啥幺蛾子,得两个地方去上传 3. ...

  7. Airflow使用入门指南

    Airflow能做什么 关注公众号, 查看更多 http://mp.weixin.qq.com/s/xPjXMc_6ssHt16J07BC7jA Airflow是一个工作流分配管理系统,通过有向非循环 ...

  8. nmap保存结果

    nmap 192.168.0.2 -oX D:\myscan.xml 参数解释: -oN <filespec> (标准输出) -oX <filespec> (XML输出) -o ...

  9. 车架号识别,VIN码识别 助力汽车后市场

    又有一家汽配圈新贵引入了小译家的 车架号识别(VIN码识别)技术 那就是明觉科技 是一个服务于汽车后市场 集数据服务.行业数据挖掘 及“互联网+”为一体的汽配信息协作平台 旗下拥有一款全车零配件信息智 ...

  10. Qt 利用XML文档,写一个程序集合 二

    接上一篇文章https://www.cnblogs.com/DreamDog/p/9213915.html XML文档的读写 一个根节点,下面每一个子节点代表一个子程序,内容为子程序名字,图标路径,e ...