分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > IT知识

WebSocket 长连接

发布时间:2023-09-06 02:29责任编辑:白小东关键词:Web
<?phpclass SocketService{ ???private $address ?= ‘localhost‘; ???private $port = 80; ???private $_sockets; ???public function __construct($address = ‘‘, $port=‘‘) ???{ ???????if(!empty($address)){ ???????????$this->address = $address; ???????} ???????if(!empty($port)) { ???????????$this->port = $port; ???????} ???} ???public function service(){ ???????//获取tcp协议号码。 ???????$tcp = getprotobyname("SOL_TCP"); ??????????# 获取与协议名称关联的协议号 ???????$sock = socket_create(AF_INET, SOCK_STREAM, $tcp); ?# 创建一个套接字(通讯节点) ???????socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1); ?# 设置套接字选项 ???????if($sock < 0) ???????{ ???????????throw new Exception("failed to create socket: ".socket_strerror($sock)."\n"); ???????} ???????socket_bind($sock, $this->address, $this->port); ???# 绑定 ???????socket_listen($sock, $this->port); ?????# 监听套接字上的连接 ???????$this->_sockets = $sock; ??????} ???public function run(){ ???????$this->service(); ???????$clients[] = $this->_sockets; ??# 数组存储 每个socket ???????# 让服务器无限获取客户端传过来的信息 ???????while (true){ ???????????$changes = $clients; ???????????$write = NULL; ???????????$except = NULL; ???????????socket_select($changes, ?$write, ?$except, NULL); ???????????foreach ($changes as $key => $_sock){ ???????????????if($this->_sockets == $_sock){ ?# 判断是不是新接入的socket ???????????????????if(($newClient = socket_accept($_sock)) ?=== false){ ???# 接受新的套接字上的连接 ??socket_accept的作用就是接受socket_bind()所绑定的主机发过来的套接流 ???????????????????????die(‘failed to accept socket: ‘.socket_strerror($_sock)."\n"); ?# 返回描述套接字错误的字符串 ???????????????????} ???????????????????$line = trim(socket_read($newClient, 1024)); ?# 读取客户端传过来的资源,并转化为字符串 ????socket_read的作用就是读出socket_accept()的资源并把它转化为字符串 ???????????????????$this->handshaking($newClient, $line); ???????????????????//获取client ip ???????????????????socket_getpeername ($newClient, $ip); ??????????????????????????????????# 查询给定套接字的远程端,这可能导致主机/端口或UNIX文件系统路径,具体取决于其类型。 ???????????????????$clients[$ip] = $newClient; ???????????????} else { ???????????????????# 读取该socket的信息,注意:第二个参数是引用传参即接收数据,第三个参数是接收数据的长度 ???????????????????$lenght = socket_recv($_sock, $buffer, ?2048, 0); ??????????????# 从已连接的socket接收数据 ??$lenght 接收到字符串长度 ???????????????????$msg = $this->message($buffer); ?????????# 接收到的信息 ???????????????????//在这里业务代码 ???????????????????fwrite(STDOUT, ‘Please input a argument:‘); ???????????????????$response = trim(fgets(STDIN));// ???????????????????$this->send($_sock, $response); ??????????????????????????????????????????????????????# 第二个参数是获取数据 ???要发送的信息 ???????????????????$this->send($_sock, ‘在线‘); ???????????????} ???????????} ???????} ???} ???/** ????* 握手处理 ????* @param $newClient socket ????* @return int ?接收到的信息 ????*/ ???public function handshaking($newClient, $line){ ???????$headers = array(); ???????$lines = preg_split("/\r\n/", $line); ??# 通过一个正则表达式分隔字符串。 ???????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: $this->address\r\n" . ???????????"WebSocket-Location: ws://$this->address:$this->port/服务器地址\r\n". ???????????"Sec-WebSocket-Accept:$secAccept\r\n\r\n"; ???????return socket_write($newClient, $upgrade, strlen($upgrade)); ???# socket_write的作用是向socket_create的套接流写入信息,或者向socket_accept的套接流写入信息 ???} ???/** ????* 解析接收数据 ????* @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 $newClinet 新接入的socket ????* @param $msg ??要发送的数据 ????* @return int|string ????*/ ???public function send($newClinet, $msg){ ???????$msg = $this->frame($msg); ???????socket_write($newClinet, $msg, strlen($msg)); ??# 写入套接字 ???} ???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; ???} ???/** ????* 关闭socket ????*/ ???public function close(){ ???????# socket_close的作用是关闭socket_create()或者socket_accept()所建立的套接流 ???????return socket_close($this->_sockets); ???}}$sock = new SocketService();$sock->run();

WebSocket 长连接

原文地址:https://www.cnblogs.com/G921123/p/10254762.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved