Websocket和PHP Socket编程
本来是搜一些html5 websocket资料看的,结果被引去看了php的socket编程。下面是一些简单的例子,在命令行运行php脚本就行
[命令行运行PHP]PHP中有一个php.exe文件,可以用命令执行PHP脚本。如:D:/php.exe -f F:/test.php ; 可以使用php.exe -h查看更多参数 :
server端:
<?php /** * 服务器端代码 * */ //确保在连接客户端时不会超时 set_time_limit(0); //设置IP和端口号 $address = "localhost"; $port = 1234; //调试的时候,可以多换端口来测试程序! //创建一个SOCKET if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { echo "socket_create() 失败的原因是:" . socket_strerror(socket_last_error()) . "/n"; die; } //阻塞模式 if (socket_set_block($sock) == false) { echo "socket_set_block() 失败的原因是:" . socket_strerror(socket_last_error()) . "/n"; die; } //绑定到socket端口 if (socket_bind($sock, $address, $port) == false) { echo "socket_bind() 失败的原因是:" . socket_strerror(socket_last_error()) . "/n"; die; } //开始监听 if (socket_listen($sock, 4) == false) { echo "socket_listen() 失败的原因是:" . socket_strerror(socket_last_error()) . "/n"; die; } do { if (($msgsock = socket_accept($sock)) === false) { echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error()) . "/n"; die; } //发到客户端 $msg = "welcome /n"; if (socket_write($msgsock, $msg, strlen($msg)) === false) { echo "socket_write() failed: reason: " . socket_strerror(socket_last_error()) ."/n"; die; } echo "读取客户端发来的信息/n"; $buf = socket_read($msgsock, 8192); echo "收到的信息: $buf /n"; socket_close($msgsock); } while (true); socket_close($sock); ?>
client端:
<?php /** * 客户端代码 */ error_reporting(0); set_time_limit(0); echo " TCP/IP Connection /n"; $service_port = 10001; $address = '127.0.0.1'; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket === false) { die; } else { echo "OK"; } echo "试图连接 "; if (socket_connect($socket, $address, $service_port) == false) { $error = socket_strerror(socket_last_error()); echo "socket_connect() failed./n","Reason: {$error} /n"; die; } else { echo "连接OK/n"; } $in = "Hello World/r/n"; if (socket_write($socket, $in, strlen($in)) === false) { echo "socket_write() failed: reason: " . socket_strerror(socket_last_error()) ."/n"; die; } else { echo "发送到服务器信息成功!/n","发送的内容为: $in /n"; } $out = ""; while ($out = socket_read($socket, 8192)) { echo "接受的内容为: ".$out; } echo "关闭SOCKET…/n"; socket_close($socket); echo "关闭OK/n"; ?>
再看websocket协议,是HTTP协议升级来的。看其消息头:
所以server端需要解析一下,并返回握手的协议内容:
在网上找到解析的相关代码 phpwebsocket - url: http://code.google.com/p/phpwebsocket/
// Usage: $master=new WebSocket("localhost",12345); class WebSocket{ var $master; var $sockets = array(); var $users = array(); var $debug = false; function __construct($address,$port){ error_reporting(E_ALL); set_time_limit(0); ob_implicit_flush(); $this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed"); socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed"); socket_bind($this->master, $address, $port) or die("socket_bind() failed"); socket_listen($this->master,20) or die("socket_listen() failed"); $this->sockets[] = $this->master; $this->say("Server Started : ".date('Y-m-d H:i:s')); $this->say("Listening on : ".$address." port ".$port); $this->say("Master socket : ".$this->master."/n"); while(true){ $changed = $this->sockets; socket_select($changed,$write=NULL,$except=NULL,NULL); foreach($changed as $socket){ if($socket==$this->master){ $client=socket_accept($this->master); if($client<0){ $this->log("socket_accept() failed"); continue; } else{ $this->connect($client); } } else{ $bytes = @socket_recv($socket,$buffer,2048,0); if($bytes==0){ $this->disconnect($socket); } else{ $user = $this->getuserbysocket($socket); if(!$user->handshake){ $this->dohandshake($user,$buffer); } else{ $this->process($user,$this->unwrap($buffer)); } } } } } } function process($user,$msg){ /* Extend and modify this method to suit your needs */ /* Basic usage is to echo incoming messages back to client */ $this->send($user->socket,$msg); } function send($client,$msg){ $this->say("> ".$msg); $msg = $this->wrap($msg); socket_write($client,$msg,strlen($msg)); $this->say("! ".strlen($msg)); } function connect($socket){ $user = new User(); $user->id = uniqid(); $user->socket = $socket; array_push($this->users,$user); array_push($this->sockets,$socket); $this->log($socket." CONNECTED!"); $this->log(date("d/n/Y ")."at ".date("H:i:s T")); } function disconnect($socket){ $found=null; $n=count($this->users); for($i=0;$i<$n;$i++){ if($this->users[$i]->socket==$socket){ $found=$i; break; } } if(!is_null($found)){ array_splice($this->users,$found,1); } $index=array_search($socket,$this->sockets); socket_close($socket); $this->log($socket." DISCONNECTED!"); if($index>=0){ array_splice($this->sockets,$index,1); } } function dohandshake($user,$buffer){ $this->log("/nRequesting handshake..."); $this->log($buffer); list($resource,$host,$origin,$key1,$key2,$l8b) = $this->getheaders($buffer); $this->log("Handshaking..."); //$port = explode(":",$host); //$port = $port[1]; //$this->log($origin."/r/n".$host); $upgrade = "HTTP/1.1 101 WebSocket Protocol Handshake/r/n" . "Upgrade: WebSocket/r/n" . "Connection: Upgrade/r/n" . //"WebSocket-Origin: " . $origin . "/r/n" . //"WebSocket-Location: ws://" . $host . $resource . "/r/n" . "Sec-WebSocket-Origin: " . $origin . "/r/n" . "Sec-WebSocket-Location: ws://" . $host . $resource . "/r/n" . //"Sec-WebSocket-Protocol: icbmgame/r/n" . //Client doesn't send this "/r/n" . $this->calcKey($key1,$key2,$l8b) . "/r/n";// . //"/r/n"; socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0))); $user->handshake=true; $this->log($upgrade); $this->log("Done handshaking..."); return true; } function calcKey($key1,$key2,$l8b){ //Get the numbers preg_match_all('/([/d]+)/', $key1, $key1_num); preg_match_all('/([/d]+)/', $key2, $key2_num); //Number crunching [/bad pun] $this->log("Key1: " . $key1_num = implode($key1_num[0]) ); $this->log("Key2: " . $key2_num = implode($key2_num[0]) ); //Count spaces preg_match_all('/([ ]+)/', $key1, $key1_spc); preg_match_all('/([ ]+)/', $key2, $key2_spc); //How many spaces did it find? $this->log("Key1 Spaces: " . $key1_spc = strlen(implode($key1_spc[0])) ); $this->log("Key2 Spaces: " . $key2_spc = strlen(implode($key2_spc[0])) ); if($key1_spc==0|$key2_spc==0){ $this->log("Invalid key");return; } //Some math $key1_sec = pack("N",$key1_num / $key1_spc); //Get the 32bit secret key, minus the other thing $key2_sec = pack("N",$key2_num / $key2_spc); //This needs checking, I'm not completely sure it should be a binary string return md5($key1_sec.$key2_sec.$l8b,1); //The result, I think } function getheaders($req){ $r=$h=$o=null; if(preg_match("/GET (.*) HTTP/" ,$req,$match)){ $r=$match[1]; } if(preg_match("/Host: (.*)/r/n/" ,$req,$match)){ $h=$match[1]; } if(preg_match("/Origin: (.*)/r/n/" ,$req,$match)){ $o=$match[1]; } if(preg_match("/Sec-WebSocket-Key1: (.*)/r/n/",$req,$match)){ $this->log("Sec Key1: ".$sk1=$match[1]); } if(preg_match("/Sec-WebSocket-Key2: (.*)/r/n/",$req,$match)){ $this->log("Sec Key2: ".$sk2=$match[1]); } if($match=substr($req,-8)) { $this->log("Last 8 bytes: ".$l8b=$match); } return array($r,$h,$o,$sk1,$sk2,$l8b); } function getuserbysocket($socket){ $found=null; foreach($this->users as $user){ if($user->socket==$socket){ $found=$user; break; } } return $found; } function say($msg=""){ echo $msg."/n"; } function log($msg=""){ if($this->debug){ echo $msg."/n"; } } function wrap($msg=""){ return chr(0).$msg.chr(255); } function unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); } } class User{ var $id; var $socket; var $handshake; }
继承类:可以自己按需写,这里我添加了几行代码,sendAll()等,很方便就改成了一个即时的网页版聊天室。
// Run from command prompt > php -q chatbot.demo.php include "websocket.class.php"; // Extended basic WebSocket as ChatBot class ChatBot extends WebSocket{ function process($user,$msg){ if (isset($user->first)) { $this->send($user->socket,''); $user->first = true; } $this->say("< ".$msg); switch($msg){ case "hello" : $this->send($user->socket,"hello human"); break; case "hi" : $this->send($user->socket,"zup human"); break; case "name" : $this->send($user->socket,"my name is Multivac, silly I know"); break; case "age" : $this->send($user->socket,"I am older than time itself"); break; case "date" : $this->send($user->socket,"today is ".date("Y.m.d")); break; case "time" : $this->send($user->socket,"server time is ".date("H:i:s")); break; case "thanks": $this->send($user->socket,"you're welcome"); break; case "bye" : $this->send($user->socket,"bye"); break; //default : $this->send($user->socket,$msg." not understood"); break; default : $this->sendAll($user, $msg); break; } } function sendAll($currentUser, $msg){ $usersList = $this->users; foreach ($usersList as $user){ if ($user !== $currentUser) // 自己发送的消息就不再接收一次了 $this->send($user->socket, $msg); } } } $master = new ChatBot("localhost",12345);
客户端代码:
<html>
<head>
<title>WebSocket</title>
<style>
html,body{font:normal 0.9em arial,helvetica;}
#log {width:440px; height:200px; border:1px solid #7F9DB9; overflow:auto;}
#msg {width:330px;}
</style>
<script>
var socket;
function init(){
var host = "ws://localhost:12345/websocket/server.php";
try{
socket = new WebSocket(host);
log('WebSocket - status '+socket.readyState);
socket.onopen = function(msg){ log("Welcome - status "+this.readyState); };
socket.onmessage = function(msg){ log("Received: "+msg.data); };
socket.onclose = function(msg){ log("Disconnected - status "+this.readyState); };
}
catch(ex){ log(ex); }
$("msg").focus();
}
function send(){
var txt,msg;
txt = $("msg");
msg = txt.value;
if(!msg){ alert("Message can not be empty"); return; }
txt.value="";
txt.focus();
try{ socket.send(msg); log('Sent: '+msg); } catch(ex){ log(ex); }
}
function quit(){
log("Goodbye!");
socket.close();
socket=null;
}
// Utilities
function $(id){ return document.getElementById(id); }
function log(msg){ $("log").innerHTML+="<br>"+msg; }
function onkey(event){ if(event.keyCode==13){ send(); } }
</script>
</head>
<body οnlοad="init()">
<h3>WebSocket v2.00</h3>
<div id="log"></div>
<input id="msg" type="textbox" οnkeypress="onkey(event)"/>
<button οnclick="send()">Send</button>
<button οnclick="quit()">Quit</button>
<div>Commands: hello, hi, name, age, date, time, thanks, bye</div>
</body>
</html>
PS:
* 这个websocket的类文件可能有一点问题,客户端握手后应该接收的第一条信息都丢失了,没细看代码,以后再检查吧。
Websocket和PHP Socket编程相关推荐
- C# socket编程实践——支持广播的简单socket服务器
在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# socket编程基本知识,写一个支持广播的简单server/clie ...
- WebSocket 协议以及 Socket 接口
目录 前言 一.websocket 协议 1.使用 websocket 协议请求过程解析 2.创建一个 WebSocket 对象 3.WebSocket 的实例方法 和 WebSocket 的事件 ( ...
- 老雷socket编程之认识常用协议
老雷socket编程之常见网络协议 1.ip IP协议是将多个包交换网络连接起来,它在源地址和目的地址之间传送一种称之为数据包的东西, 它还提供对数据大小的重新组装功能,以适应不同网络对包大小的要求. ...
- WebSocket入门介绍及编程实战
前言:最近看了几天的WebSocket,从以前的只闻其名,到现在也算是有一点点的了解了.所以就准备用博客记录一下自己的学习过程,希望也能帮助其它学习的人,因为我本人学习的过程中也是参考了很多其它人的博 ...
- Windows Socket编程笔记之最简单的小Demo
Windows Socket编程的大致过程: 服务器端: ----过程-------------对应的API------- 0.初始化 | WSAStartup() 1.创建So ...
- Linux下Socket编程
Linux下Socket编程 网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符.Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的S ...
- [Python_7] Python Socket 编程
0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*-"&qu ...
- 打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们能够借助WebSocket来更加方便地打通BS与CS -- 由于B/S中的WebSocket能够直接连接到C/S的服务端,并进行双向通信.例 ...
- C# Socket编程(5)使用TCP Socket
TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer) ...
最新文章
- pandas 读写 excel 数据
- zigzag扫描matlab,ZIGZAG扫描的MATLAB实现 | 学步园
- TypeScript 入门
- 【SDL的编程】VC环境搭建
- JZOJ5143:无心行挽
- mysql数据库相关基础知识02
- 190629每日一句
- Webstorm全版本汉化包
- 无符号整型转点分十进制
- 医院计算机房相关制度,医院机房管理制度.docx
- WordPress如何变更图片存储目录uploads并取消按年月存放?
- excel制作项目甘特图
- 高校大数据专业教学实训资源解决方案
- java 远程视频监控系统_基于android的远程视频监控系统 附完整源码
- 很酷的瞄准镜样式光标效果
- 【机器学习】西瓜书一些关键词
- FTP主动和被动模式区别
- 游戏物理中的碰撞测试(一) - 如何检测碰撞
- 关系型数据库理论基础阐释
- VIM_readme