有三个疑问:
1.连接成功后,我想服务器发送消息,为什么只有第一次服务器会返回信息
2.第一次向服务器发送信息,服务器会返回信息,但是返回的信息是125个字符的,并不是一次返回全部,如图
3.为什么发汉字多了会报错,服务器直接关闭,发几个字不会
> 这是服务器代码,php的
<?php
set_time_limit(0);
$address = '127.0.0.1';
$port = '231';
if( ($sock = socket_create( AF_INET, SOCK_STREAM, SOL_TCP )) === false ) die( "套接字创建失败:" . socket_strerror(socket_last_error( )) );
if ( ($ok = socket_bind( $sock , $address , $port )) === false ) die( "服务器绑定失败:" . mb_convert_encoding(socket_strerror( socket_last_error( $sock )) , "utf-8","GBK") );
if ( socket_listen($sock, 4) === false ) die( "服务器监听失败:" . socket_strerror( socket_last_error( $sock ) ) );
print_r('服务器开启成功');
while (true){
if (($client = socket_accept($sock)) === false) die( "套接字接收客户端创建失败:" . socket_strerror(socket_last_error( $sock )) );
$buf = socket_read($client, 8192); //读取请求
$response = hand_shake($buf); //跟websocket握手
socket_write($client,$response,strlen($response));//发送响应
//正式开始通信...
$msg = socket_read($client, 8192);
$msg = frame(decode($msg));
socket_write($client, $msg, strlen($msg));
//$msg = code($msg);
//if( socket_write($client,$msg,strlen($msg)) === false ) die("socket_write() failed: reason: " . socket_strerror(socket_last_error()) ."/n"); //发送数据
//else echo'发送信息成功';
//socket_close($client);
}
//socket_close($sock);
function hand_shake($buf){
$buf = substr($buf,strpos($buf,'Sec-WebSocket-Key:')+18);
$key = trim(substr($buf,0,strpos($buf,"\r\n")));
$new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
$new_message = "HTTP/1.1 101 Switching Protocols\r\n";
$new_message .= "Upgrade: websocket\r\n";
$new_message .= "Sec-WebSocket-Version: 13\r\n";
$new_message .= "Connection: Upgrade\r\n";
$new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
return $new_message;
}
// 解析数据帧
function decode($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;
}
// 返回帧信息处理
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;
}
// 返回数据
function send($client, $msg){
$msg = $this->frame($msg);
socket_write($client, $msg, strlen($msg));
}
?>
前端代码
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<div style="width:410px;height:500px;margin:0 auto;">
<h2>超迷你简易网页聊天</h2>
<textarea id="history" style="width:400px;height:300px;padidng:10px;font:16px/24px '宋体';display:block;margin-bottom:20px;" readonly="readonly"></textarea>
<select name="" style="width:60px;height:35px;"><option value="妈妈" selected>妈妈</option><option value="爸爸">爸爸</option></select><input id="cont" type="text" style="width:260px;height:30px;" placeholder="输入内容">
<input id="send" type="button" value="发送" style="width:70px;height:35px;">
</div>
<script>
function $(ele){
return document.getElementById(ele);
}
var ws = new WebSocket("ws://127.0.0.1:231");
ws.onopen = function(){ log("连接服务器成功"); }
ws.onerror = function(){ log("连接服务器失败"); }
ws.onclose = function(){ log("服务器已关闭"); }
$('send').onclick = function(){
ws.send( $('cont').value );
ws.onmessage = function(e){
log('新消息:'+ e.data);
}
}
function log(html){ $('history').value += '->'+html+'\n' ; }
</script>
</body>
以下内容仅为查阅相关资料后得出的结论,如果错误请指出。
仅作为学习参考,如需用于生产,请选择已有的一些解决方案。
问题1:
在完成握手后, socket_read 开始阻塞接受输入,输入完成后发给浏览器后,就又回到了上面的 接受客户端连接,所以 你就只能发送一条消息,如果要想一直发送,就需要把 正式开始通信那一部分放进 while true 里面,让他一直阻塞接受输入。就可以一直发送消息了。
问题2:
关于第二个问题问题,详见RFC 6455
问题3:
发送中文在发送时是对的,但是浏览器在接受到响应后会发生
Could not decode a text frame as UTF-8.
错误。这是服务器在接收数据时被拆分成了几个帧(通常是发送的数据太长,在 socket_read 时被当成了几个帧接收(见2),此时是按照帧进行回复的,因为读取并不一定恰好是一个完整的汉字,就造成了 utf-8 编码错误。)关于 socket 相关例子请查阅