研究了一周,重要搞明白liunx网络编程的socket函数。下面是通过socket_select阻塞的方式实现php公共聊天的简易聊天室。啥都不说了,上代码。

<?phpclass webSocket
{/*** 服务端地址** @var [type]*/private $address;/*** 服务端绑定的端口号** @var [type]*/private $port;/*** 监听端口** @var [type]*/private $socket;public function __construct($address='127.0.0.1',$port=9501){$socket=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);socket_bind($socket,$address,$port);socket_listen($socket);$this->socket=$socket;$this->port=$port;$this->address=$address;echo '已启动websockt服务器地址:'.$address.';端口:'.$port.PHP_EOL;}   public function run(){//将原客户端加入监听连接池$sockets[]=$this->socket;  //定义写入监听连接池$write=null;//定义权限接受连接池$except=null;//定义超时时间$time_out=null;//启动循环阻塞任务while(true){//复制连接池$changes=$sockets;//设置同步阻塞监听函数socket_select($changes,$write,$except,$time_out);//监听端口可读后操作foreach ($changes as $sock) {//如果监听到的是原端口if($sock==$this->socket){//读取错误if(($client=socket_accept($sock))===false){die('failed to accept socket: '.socket_strerror($sock)."\n");}//获取客户端发送内容$content=trim(socket_read($client,1024));//执行http协议升级websocket$this->handshaking($client,$content);$id=rand(1000,9999);$message='id:'.$id.'客户端已加入连接池';   //通知全体客户端$this->sendAll($sockets,$sock,$message);//客户端加入连接池$sockets[$id]=$client; //服务端提示echo 'id:'.$id.'客户端已加入连接池'.PHP_EOL;}//已经握手完毕else{//接收数据socket_recv($sock,$buf,1024,0); //群发消息 $str='';foreach ($sockets as $k => $v) {if($sock==$v){$str='来自 '.$k.' 的消息:';break;}}     $this->sendAll($sockets,$sock,$str.$this->message($buf));}}}}/*** 升级协议** @param [type] $client* @param [type] $content* @return void*/public function handshaking($client,$content){//定义头部信息$headers=array();if(preg_match('/Sec-WebSocket-Key:.*\r\n/',$content,$matchs)){$headers['Sec-WebSocket-Key'] =trim(chop(str_replace('Sec-WebSocket-Key:',"",$matchs[0])));}//设置返回头$secKey = $headers['Sec-WebSocket-Key'];$websocket_accept=base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));$upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" ."Upgrade: websocket\r\n" ."Connection: Upgrade\r\n" ."WebSocket-Origin: $this->address\r\n" ."WebSocket-Location: ws://$this->address:$this->port/websocket/websocket\r\n"."Sec-WebSocket-Accept:$websocket_accept\r\n\r\n";//写入缓冲return socket_write($client,$upgrade,strlen($upgrade));}/*** 解析接收数据* @param $buffer* @return null|string*/public function message($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 [type] $socket* @param [type] $sock* @param [type] $message* @return void*/public function sendAll($socket,$sock,$message){foreach ($socket as $so) {if($so!=$sock && $so!=$this->socket){$this->send($so,$message);}}}/*** 发送数据* @param $newClinet 新接入的socket* @param $msg   要发送的数据* @return int|string*/public function send($clinet, $msg){$msg = $this->frame($msg);socket_write($clinet, $msg, strlen($msg));}/*** 处理数据帧** @param [type] $s* @return void*/public function frame($s) {$a = str_split($s, 125);if (count($a) == 1) {return "\x81" . chr(strlen($a[0])) . $a[0];}$ns = "";foreach ($a as $o) {$ns .= "\x81" . chr(strlen($o)) . $o;}return $ns;}
}$socketobj=new webSocket();
$socketobj->run();

这里是前端内容

<!doctype html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no"><title>websocket</title></head><body><input id="text" value=""><input type="submit" value="send" onclick="start()">
<div id="msg"></div><script>/***0:未连接*1:连接成功,可通讯*2:正在关闭*3:连接已关闭或无法打开*///创建一个webSocket 实例var webSocket  = new  WebSocket("ws://127.0.0.1:9501");webSocket.onerror = function (event){onError(event);};// 打开websocketwebSocket.onopen = function (event){onOpen(event);};//监听消息webSocket.onmessage = function (event){onMessage(event);};webSocket.onclose = function (event){onClose(event);}//关闭监听websocketfunction onError(event){document.getElementById("msg").innerHTML = "<p>close</p>";console.log("error"+event.data);};function onOpen(event){console.log("open:"+sockState());document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";};function onMessage(event){console.log("onMessage");document.getElementById("msg").innerHTML += "<p>response:"+event.data+"</p>"};function onClose(event){document.getElementById("msg").innerHTML = "<p>close</p>";console.log("close:"+sockState());webSocket.close();}function sockState(){var status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];return status[webSocket.readyState];}function start(event){console.log(webSocket);var msg = document.getElementById('text').value;document.getElementById('text').value = '';console.log("send:"+sockState());console.log("msg="+msg);webSocket.send("msg="+msg);document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"};function close(event){webSocket.close();}</script></body>
</html>

通过PHP(socket_select)阻塞函数实现公共即时聊天相关推荐

  1. R语言merge函数全连接dataframe数据(Full (outer) join)、merge函数进行全连接必须将参数all设置为true(all=TRUE)、默认merge函数通过公共列名合并数

    R语言merge函数全连接dataframe数据(Full (outer) join).merge函数进行全连接必须将参数all设置为true(all=TRUE).默认merge函数通过公共列名合并数 ...

  2. R语言merge函数左连接dataframe数据(Left (outer) join in R)、左连接必须将参数all设置(all.x = TRUE)、默认merge函数通过公共列名合并数据集

    R语言merge函数左连接dataframe数据(Left (outer) join in R).merge函数进行左连接必须将参数all设置为(all.x = TRUE).默认merge函数通过公共 ...

  3. linux中c语言kbhit函数用法,C语言判断用户是否输入-非阻塞函数kbhit

    一.基础研究 要从地址读取数据,肯定是要定义一个指针变量p,用它来实现变换地址和取值的功能.另外程序是当两个条件中的某一个出现时才停止,所以应该用while~do循环语句循环输出n和d,并用while ...

  4. 阻塞函数和非阻塞函数的区别

    简单理解: 阻塞函数就是:程序一直停在此函数处,等待后续操作,有相关操作之后程序才能继续执行,而非阻塞函数是:程序运行在此不会中断,继续向下执行,当此处有操作时,继续此条件的后续操作 如c++中: k ...

  5. Web端即时聊天项目实现(基于WebSocket)

    Web端即时聊天项目实现 项目背景  其实这个项目算是我做过的花时间最长也投入心血最多的一个项目了,当时决定开始做这个的时候我几乎什么都不会,那时我个人的情况是: JavaEE方面: 会jsp+ser ...

  6. 使用PHP+Swoole实现的网页即时聊天工具:PHPWebIM(转)

    使用PHP+Swoole实现的网页即时聊天工具 全异步非阻塞Server,可以同时支持数百万TCP连接在线同时支持websocket+comet2种兼容协议,可用于所有种类的浏览器包括IE拥有完整的U ...

  7. 简洁版即时聊天---I/O多路复用使用

    一.基于select接口+有名管道的I/O 多路复用 1.注意提示点: 1.基于客户端以及服务器两端的使用 2 .对于有名管道,须注意有名管道的链接顺序,否则,可能发生死锁,或链接不成功. 3.学会s ...

  8. golang从简单的即时聊天来看架构演变

    前言 俗话说的好,架构从来都不是一蹴而就的,没有什么架构一开始设计就是最终版本,其中需要经过很多步骤的变化,今天我们就从一个最简单的例子来看看,究竟架构这个东西是怎么变的. 我将从一个最简单的聊天室的 ...

  9. android简单即时聊天sdk

    android简单即时聊天sdk 切换用户登录的实现 联系人列表的实现 聊天页的实现 消息缓存与排序 消息接收和分发--数据库队列和投递队列 有序列表的维护 切换用户登录的实现 由于不同的登录用户需要 ...

最新文章

  1. 本机无法访问虚拟机上的nignx
  2. php 分页参数丢失,THINKPHP3.2搜索分页丢失参数,实现保留搜索条件解决办法
  3. Android WebView 和 javaScript的互相调用(三)
  4. python获取计算机信息系统数据罪_工作心得:破坏计算机信息系统罪与非法获取计算机信息系统数据罪的区分...
  5. 使用ln -s解决库冲突的问题
  6. 单片机原理及其应用——单片机定时器中断实验(八段数码管依次显示0~9数字)
  7. jaba窗体连接mysql增删改查_知识实现——Java使用jdbc连接MySql数据库,实现增删改查...
  8. 搜狐视频怎么更改头像
  9. 在列表中根据条件来筛选数据
  10. mysql 使用jdbctemplate_SpringBoot学习笔记-使用jdbcTemplate访问mysql
  11. 重庆将打造区块链产业高地
  12. 二手房六大产权问题最关键
  13. 2月26日 光流,跟踪算法的尝试
  14. 【转】What is an entity system framework for game development?
  15. 大一大学计算机期末考试题库,大学计算机基础 大一 考试必备题库
  16. Android 腾讯地图定位
  17. PTA 7-18 新浪微博热门话题
  18. 历史上最“好”的皇帝--宋仁宗
  19. 下载哔哩哔哩网页上的视频
  20. 如何测试充电宝输出电压-20210127

热门文章

  1. OpenCV图像算法汇总
  2. PCB模块化设计09——RJ45-以太网口PCB布局布线设计规范
  3. 轻骑逐单于,大雪满弓刀:华为分布式存储的一骑绝尘
  4. HP ALM、LoadRunner、QuickTest11.5下载地址
  5. C语言程序设计运动会管理系统(一)
  6. 本地文件服务器,使用http -server 搭建本地简易文件服务器
  7. vue.js海康威视监控使用,以及遇到的问题
  8. 白板上的记号笔字迹如何去除?
  9. Ansible 系列之 Inventory 资源清单介绍
  10. (简单)华为Mate9 MHA-AL00的Usb调试模式在哪里开启的步骤