<?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. golang 防SQL注入 基于反射、TAG标记实现的不定参数检查器

    收到一个任务,所有http的handler要对入参检查,防止SQL注入.刚开始笨笨的,打算为所有的结构体写一个方法,后来统计了下,要写几十上百,随着业务增加,以后还会重复这个无脑力的机械劳作.想想就l ...

  2. OAuth(开放授权)

    HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使 ...

  3. 20155207实验2 Windows口令破解

    20155207实验2 Windows口令破解 实验目的 了解Windows口令破解原理 对信息安全有直观感性认识 能够运用工具实现口令破解 实验原理 口令破解方法 口令破解主要有两种方法:字典破解和 ...

  4. 20155323 第三次实验 敏捷开发与XP实践

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

  5. ABP 框架集成EF批量增加、删除、修改只针对使用mmsql的

    AppService 层使用nuget 添加 EFCore.BulkExtensions 引用 using Abp.Application.Services.Dto; using Abp.Domain ...

  6. arduino蜂鸣器的使用

    一:蜂鸣器的使用 控制要求:模拟救护车响声 实物连接图: 电路原理图: 控制代码: //智慧自动化2018.6.11 ;//设置控制蜂鸣器的数字IO脚 void setup() { pinMode(b ...

  7. 书写可维护的javascript

    内容介绍 编写可维护的代码很重要,因为大部分开发人员都花费大量时间维护他人代码. 1.什么是可维护的代码? 一般来说可维护的代码都有以下一些特征: 可理解性---------其他人可以接手代码并理解它 ...

  8. 人脸辨识,用树莓派Raspberry Pi实现舵机云台追踪脸孔

    影像辨识作为近年最热门的专业技术之一,广泛用于智慧监视器.车电监控.智慧工厂.生物医疗电子等等:其中,人脸辨识是一个很重要的部分,网络上已经有相当多的资源可供下载使用:于是我们使用舵机云台作为镜头旋转 ...

  9. Redis 哨兵 Sentinel

    Redis Sentinel:redis集群应用,分布式系统.   多个Sentinal进程之间通过 gossip 协议来接收主服务器是否下线的信息,通过 Raft 一致性协议来决定故障转移及转移服务 ...

  10. Java飞机大战MVC版

    PlaneWar Java飞机大战MVC版 //无聊时偷的雷霆战机素材写了一个飞机大战,本意是练习mvc,但写得还是不清晰 github下载:https://github.com/dejavudwh/ ...