这只是一种技术

<?php
$host = "127.0.0.1";
// 指定监听的端口,注意该端口不能与现有应用的端口冲突
$port = '9505';
$null = null;
// 创建Socket。AF_INET:代表通信时使用IPv4协议;SOCK_STREAM:代表传输的数据是二进制流数据;SOL_TCP:代表底层使用的协议是TCP
$socket = socket_create ( AF_INET, SOCK_STREAM, SOL_TCP );
// 指定Socket相应的属性。SOL_SOCKET:设定协议的等级;SO_REUSEADDR:设置端口释放之后可以立即被使用
socket_set_option ( $socket, SOL_SOCKET, SO_REUSEADDR, 1 );
// 绑定端口
socket_bind ( $socket, 0, $port );
// 监听端口
socket_listen ( $socket );
// 声明一个数组,用于存放所有的客户端连接
$clients = array (
$socket
);
while ( true ) {
$changed_socket = $clients;
// 在当前数组中获取活跃的Socket连接,即当前正在发送请求的连接或正在传输数据的连接等
socket_select ( $changed_socket, $null, $null, 0, 10 );
// 判断当前的Socket是否为活跃的Socket,如果是,说明客户端在请求连接
if (in_array ( $socket, $changed_socket )) {
echo "client connecting";
// 接受连接
$socket_new = socket_accept ( $socket );
$clients [] = $socket_new;
// 发送握手信息
$header = socket_read ( $socket_new, 1024 );
perform_handshaking ( $header, $socket_new, $host, $port );
// 在连接成功后,当前Socket要从活跃Socket列表中删除,否则会陷入死循环
$key = array_search ( $socket, $changed_socket );
unset ( $changed_socket [$key] );
} else {
// 不是新连接,是客户端在发送数据
// 服务器开始读取客户端发送的数据
foreach ( $changed_socket as $v ) {
while ( socket_recv ( $v, $buf, 1024, 0 ) >= 1 ) {
// 解包数据
$received_text = unmask ( $buf );
// 将数据解包后转成JSON对象
$msgJson = json_decode ( $received_text );
// 读取数据
$namer = $msgJson->namer;
$content = $msgJson->content;
// 将数据进行编码
$message = mask ( json_encode ( [
'namer' => $namer,
'content' => $content,
'type' => 'usermsg'
] ) );
// 广播编码后的数据。服务器进行广播的消息会触发客户端的onmessage事件
send_message ( $message );
// 跳出foreach循环
break 2;
}
// 删除已经关闭的Socket
$buf = @socket_read ( $v, 1024, PHP_NORMAL_READ );
if ($buf === false) {
$key = array_search ( $v, $clients );
socket_getpeername ( $v, $ip );
unset ( $clients [$key] );
$msg = mask ( json_encode ( [
'type' => 'system',
'content' => $ip . "已经下线。"
] ) );
send_message ( $msg );
}
}
}
}
// 发送消息的方法
function send_message($msg) {
global $clients;
foreach ( $clients as $changed_socket ) {
@socket_write ( $changed_socket, $msg, strlen ( $msg ) );
}
return true;
}
// 以下3个函数,我们只需了解总体结构即可。在有需要时可以直接使用
// 解码数据。服务器解码客户端发送过来的数据
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;
} // 握手的逻辑。客户端与服务端相互识别的过程
function perform_handshaking($receved_header, $client_conn, $host, $port) {
$headers = array ();
$lines = preg_split ( "/\r\n/", $receved_header );
foreach ( $lines as $line ) {
$line = chop ( $line );
if (preg_match ( '/\A(\S+): (.*)\z/', $line, $matches )) {
$headers [$matches [1]] = $matches [2];
}
}
$secKey = $headers ['Sec-WebSocket-Key'];
$secAccept = 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: $host\r\n" . "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write ( $client_conn, $upgrade, strlen ( $upgrade ) );
}

php使用Socket实现聊天室功能(书中的代码)的更多相关文章

  1. [Python] socket发送UDP广播实现聊天室功能

    一.说明 本文主要使用socket.socket发送UDP广播来实现聊天室功能. 重点难点:理解UDP通讯流程.多线程.UDP广播收发等. 测试环境:Win10\Python3.5. 程序基本流程:创 ...

  2. node+express+socket.io制作一个聊天室功能

    首先是下载包: npm install express npm install socket.io 建立文件: 服务器端代码:server.js var http=require("http ...

  3. Socket.IO聊天室~简单实用

    小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...

  4. java基于socket公共聊天室的实现

    项目:一个公共聊天室功能的实现,实现了登录聊天,保存聊天记录等功能. 一.实现代码 1.客户端 ChatClient.java import java.io.BufferedReader; impor ...

  5. Android 基于Socket的聊天室(一)

    Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信. Client A ...

  6. Netty学习笔记(四) 简单的聊天室功能之服务端开发

    前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...

  7. 使用epoll实现聊天室功能,同时比较epoll和select的异同

    1.首先介绍一下select和epoll的异同,如下(摘抄自https://www.cnblogs.com/Anker/p/3265058.html) select的几大缺点: (1)每次调用sele ...

  8. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  9. Android进阶(十五)socket通信——聊天室

    想做一个聊天室,花费了将近一天的时间,各种错误.讲解知识点之前,絮叨几句:动手能力还是很重要的,有时看似简单的一个问题,当你真正着手去解决的时候就有可能会遇到各种各样的问题,原因之一就是因为你的知识储 ...

随机推荐

  1. 安卓手机通过有线连接PC上网

    因手机wifi坏了,速度上限为2.5m/s.无法发挥出100m带宽的威力. 这里探索各大神的指导,记录下其中一种方式. :链接       主题:使用openvpn和手机的USB共享网络 通过mico ...

  2. linux运维、架构之路-KVM虚拟化技术

    一.云计算概述 云计算:是一种资源使用和交付模式 虚拟化:一种具体的技术,用来将物理机虚拟成为多个相互独立的虚拟机.云计算不等于虚拟化,云计算是使用了虚拟化的技术做支撑 二.KVM配置使用 1.系统环 ...

  3. css3 中的2D转换

    一.CSS3转换 通过转换实现对对元素进行旋转.缩放.移动.拉伸的效果:这种原来必须要通过JS或者图片处理才可以实现的效果,现在都可以通过CSS3来完成. 2D转换采用transform属性来实现效果 ...

  4. 2017年cocoaPods 1.2.1升级

    还在用老版本的ccoaPods,安装三方库时,会报错 : [!] Invalid `Podfile` file: [!] The specification of `link_with` in the ...

  5. Comet OJ - Contest #4 D求和 思维题

    Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...

  6. k8s从Harbor拉取启动镜像测试

    登陆harbor [root@k8s-master ~]# docker login 192.168.180.105:1180 Username: admin Password: WARNING! Y ...

  7. Java数据结构之排序---冒泡排序

    冒泡排序的基本思想: 通过对待排序序列从前到后(从下标小的元素开始),依次比较相邻位置的元素的值,若发现与给定的次序冲突,则交换位置(假设数值大的数放在序列的后面),使数值较大的元素逐渐从前移动到后部 ...

  8. 一台电脑多个git使用 push 时候出现denied

    http://my.oschina.net/silentboy/blog/220158 当一台电脑上多个git account 的时候, 出现如下问题, $ git push origin maste ...

  9. movable-view组件

    movable-view组件:可以移动方块 movable-view组件必须是movable-area的直接子元素,才可以进行操作,才可以移动方块 movable-view组件的属性: directi ...

  10. AppStore IPv6-only 解决--看我就够了

    自2016年6月1日起,苹果要求所有提交App Store的iOS应用必须支持IPv6-only环境,背景也是众所周知的,IPv4地址已基本分配完毕,同时IPv6比IPv4也更加高效,向IPv6过渡是 ...