set_time_limit(0);

class 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();

网上看到很多说会断开链接,设置心跳包也没有用

我这里直接配置了下 set_time_limit(0);   改变 php.ini中的 max_execution_time设置时间 然后就没有断线的问题了! 也保证了持久连接!

html部分

socket 测试

html, body {

min-height: 100%; }

body {

margin: 0;

padding: 0;

width: 100%;

font-family: "microsoft yahei",sans-serif, arial; }

.container {

text-align: center; }

.title {

font-size: 16px;

color: rgba(0, 0, 0, 0.3);

position: fixed;

line-height: 30px;

height: 30px;

left: 0px;

right: 0px;

background-color: white; }

.content {

background-color: #f1f1f1;

border-top-left-radius: 6px;

border-top-right-radius: 6px;

margin-top: 30px; }

.content .show-area {

text-align: left;

padding-top: 8px;

padding-bottom: 168px; }

.content .show-area .message {

width: 70%;

padding: 5px;

word-wrap: break-word;

word-break: normal; }

.content .write-area {

position: fixed;

bottom: 0px;

right: 0px;

left: 0px;

background-color: #f1f1f1;

z-index: 10;

width: 100%;

height: 160px;

border-top: 1px solid #d8d8d8; }

.content .write-area .send {

position: relative;

top: -28px;

height: 28px;

border-top-left-radius: 55px;

border-top-right-radius: 55px; }

.content .write-area #name{

position: relative;

top: -20px;

line-height: 28px;

font-size: 13px; }

socket 测试长连接
发送

var wsurl = 'ws://localhost:80/websocket/test2.php';

var websocket;

websocket = new websocket(wsurl);

//连接建立

websocket.onopen = function(evevt){

console.log("connected to websocket server.");

$('.show-area').append('

connected to websocket server!

');

}

//收到消息

websocket.onmessage = function(event) {

console.log(event);

$('.show-area').append('

'+event.data+'

');

}

//发生错误

websocket.onerror = function(event){

console.log("connected to websocket server error");

$('.show-area').append('

connect to websocket server error.

');

}

//连接关闭

websocket.onclose = function(event){

console.log('websocket connection closed. ');

$('.show-area').append('

websocket connection closed.

');

}

// 发送信息

function send(){

var name = $('#name').val();

var message = $('#message').val();

if(!name){

alert('请输入用户名!');

return false;

}

if(!message){

alert('发送消息不能为空!');

return false;

}

var msg = {

message: message,

name: name

};

try{

websocket.send(json.stringify(msg));

} catch(ex) {

console.log(ex);

}

}

//点发送按钮发送消息

$('.send').bind('click',function(){

send();

});

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐