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 onload="init()">
<h3>WebSocket v2.00</h3>
<div id="log"></div>
<input id="msg" type="textbox" onkeypress="onkey(event)"/>
<button onclick="send()">Send</button>
<button onclick="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 ...
- 基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET
基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET 基于libevent, libuv和android L ...
- C# socket编程实践
C# socket编程实践——支持广播的简单socket服务器 在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# ...
- PHP Socket 编程进阶指南
学习准备 Linux 或者 Mac 环境: 安装有 Sockets 扩展: 了解 TCP/IP 协议. socket函数只是PHP扩展的一部分,编译PHP时必须在配置中添加 --enable-sock ...
- 转 网络编程学习笔记一:Socket编程
题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器兼容性搞死人:但主要是因为这段时间一直在看html5的东西,看到web socket时觉得很有 ...
- 老雷socket编程之认识常用协议
老雷socket编程之常见网络协议 1.ip IP协议是将多个包交换网络连接起来,它在源地址和目的地址之间传送一种称之为数据包的东西, 它还提供对数据大小的重新组装功能,以适应不同网络对包大小的要求. ...
- Linux下的C Socket编程 -- server端的继续研究
Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
- java socket编程(li)
一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以 ...
随机推荐
- 一个完整openlayer的例子,包括marker,popup等
整理转自:http://www.blogjava.net/siriusfx/archive/2007/11/26/163104.html openlayers提供了几十个示例,虽然每个示例都很简单,但 ...
- 团队项目-smart原则
Smart原则 Specific ——明确性 所谓明确就是要用具体的语言清楚地说明要达成的行为标准.明确的目标几乎是所有成功团队的一致特点.很多团队不成功的重要原因之一就因为目标定的模棱两可,或没有将 ...
- 【BZOJ】【1565】【NOI2009】PVZ 植物大战僵尸
网络流/最大权闭合子图+拓扑排序 感动死了>_<,一年多以前刚知道网络流的时候听说了这道名字很带感的题目,现在终于有实力切掉它了. 这题是最大权闭合子图模型的经典应用<_<,首 ...
- 本地不安装oracle-client,使用pl/sql developer连接数据库
一.问题描述 本地未安装oracle-client端,由于机器资源有限,希望通过pl/sql developer进行远程数据库连接.单纯的安装pl/sql developer无法远程连接数据库. 二. ...
- nenu contest
http://vjudge.net/vjudge/contest/view.action?cid=54393#overview A n^2能过 对第二个n我二分了一下,快了一点点,nlogn #inc ...
- poj 2362
回溯加剪枝 #include <cstdio> #include <cstdlib> #include <cmath> #include <map> # ...
- SPOJ 3643 /BNUOJ 21860 Traffic Network
题意:现在已有m条单向路,问在给你的k条双向路中选择一条,使得s到t的距离最短 思路:设双向路两端点为a,b;长度为c. s到t的有三种情况: 1:原本s到t的路径 2:从s到a,a到b,b再到t的路 ...
- java集合--java.util.ConcurrentModificationException异常
ConcurrentModificationException 异常:并发修改异常,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常.一个线程对collection集合迭代,另一个线程对Co ...
- ElasticSearch小操之Marvel,Sense
慢慢弄弄,说不好马上就要用呢,,, 嘿嘿 参考网址: http://es.xiaoleilu.com/ Elasticsearch 权威指南(中文版) 阅读地址:Elasticsearch权威指南(中 ...
- java登陆验证码与JS无刷新验证
最近公司的项目的登陆模块由我负责,所以就做了个登陆小功能进行练手,其包括了用jQuery对用户名和密码进行不为null验证,和出于安全性考虑加了一个验证码的校验 别的不说先上代码 controller ...