2017-03-22 146 views
4

我有下面的代碼PHP客戶端Web套接字發送消息

的index.php

<!DOCTYPE html> 
<html> 
<head> 
<meta name="viewport" content="width=device-width, initial-scale=1"> 
<style type="text/css"> 

.panel{ 


margin-right: 3px; 
} 

.button { 
    background-color: #4CAF50; 
    border: none; 
    color: white; 
    margin-right: 30%; 
    margin-left: 30%; 
    text-decoration: none; 
    display: block; 
    font-size: 16px; 
    cursor: pointer; 
    width:30%; 
    height:40px; 
    margin-top: 5px; 

} 
input[type=text]{ 
     width:100%; 
     margin-top:5px; 

    } 


.chat_wrapper { 
    width: 70%; 
    height:472px; 
    margin-right: auto; 
    margin-left: auto; 
    background: #3B5998; 
    border: 1px solid #999999; 
    padding: 10px; 
    font: 14px 'lucida grande',tahoma,verdana,arial,sans-serif; 
} 
.chat_wrapper .message_box { 
    background: #F7F7F7; 
    height:350px; 
     overflow: auto; 
    padding: 10px 10px 20px 10px; 
    border: 1px solid #999999; 
} 
.chat_wrapper input{ 
    //padding: 2px 2px 2px 5px; 
} 
.system_msg{color: #BDBDBD;font-style: italic;} 
.user_name{font-weight:bold;} 
.user_message{color: #88B6E0;} 

@media only screen and (max-width: 720px) { 
    /* For mobile phones: */ 
    .chat_wrapper { 
     width: 95%; 
    height: 40%; 
    } 


    .button{ width:100%; 
    margin-right:auto; 
    margin-left:auto; 
    height:40px;} 






} 

</style> 
</head> 
<body> 
<?php 
$colours = array('007AFF','FF7000','FF7000','15E25F','CFC700','CFC700','CF1100','CF00BE','F00'); 
$user_colour = array_rand($colours); 
?> 


<script src="jquery-3.1.1.js"></script> 


<script language="javascript" type="text/javascript"> 
$(document).ready(function(){ 
    //create a new WebSocket object. 
    var wsUri = "ws://localhost:9000/demo/server.php"; 
    websocket = new WebSocket(wsUri); 

    websocket.onopen = function(ev) { // connection is open 
     $('#message_box').append("<div class=\"system_msg\">Connected!</div>"); //notify user 
    } 

    $('#send-btn').click(function(){ //use clicks message send button 
     var mymessage = $('#message').val(); //get message text 
     var myname = $('#name').val(); //get user name 

     if(myname == ""){ //empty name? 
      alert("Enter your Name please!"); 
      return; 
     } 
     if(mymessage == ""){ //emtpy message? 
      alert("Enter Some message Please!"); 
      return; 
     } 
     document.getElementById("name").style.visibility = "hidden"; 

     var objDiv = document.getElementById("message_box"); 
     objDiv.scrollTop = objDiv.scrollHeight; 
     //prepare json data 
     var msg = { 
     message: mymessage, 
     name: myname, 
     color : '<?php echo $colours[$user_colour]; ?>' 
     }; 
     //convert and send data to server 
     websocket.send(JSON.stringify(msg)); 
    }); 

    //#### Message received from server? 
    websocket.onmessage = function(ev) { 
     var msg = JSON.parse(ev.data); //PHP sends Json data 
     var type = msg.type; //message type 
     var umsg = msg.message; //message text 
     var uname = msg.name; //user name 
     var ucolor = msg.color; //color 

     if(type == 'usermsg') 
     { 
      $('#message_box').append("<div><span class=\"user_name\" style=\"color:#"+ucolor+"\">"+uname+"</span> : <span class=\"user_message\">"+umsg+"</span></div>"); 
     } 
     if(type == 'system') 
     { 
      $('#message_box').append("<div class=\"system_msg\">"+umsg+"</div>"); 
     } 

     $('#message').val(''); //reset text 

     var objDiv = document.getElementById("message_box"); 
     objDiv.scrollTop = objDiv.scrollHeight; 
    }; 

    websocket.onerror = function(ev){$('#message_box').append("<div class=\"system_error\">Error Occurred - "+ev.data+"</div>");}; 
    websocket.onclose = function(ev){$('#message_box').append("<div class=\"system_msg\">Connection Closed</div>");}; 
}); 




</script> 
<div class="chat_wrapper"> 
<div class="message_box" id="message_box"></div> 
<div class="panel"> 
<input type="text" name="name" id="name" placeholder="Your Name" maxlength="15" /> 

<input type="text" name="message" id="message" placeholder="Message" maxlength="80" 
onkeydown = "if (event.keyCode == 13)document.getElementById('send-btn').click()" /> 





</div> 

<button id="send-btn" class=button>Send</button> 

</div> 

</body> 
</html> 

server.php

<?php 
$host = 'localhost'; //host 
$port = '9000'; //port 
$null = NULL; //null var 

//Create TCP/IP sream socket 
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
//reuseable port 
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); 

//bind socket to specified host 
socket_bind($socket, 0, $port); 

//listen to port 
socket_listen($socket); 

//create & add listning socket to the list 
$clients = array($socket); 

//start endless loop, so that our script doesn't stop 
while (true) { 
    //manage multipal connections 
    $changed = $clients; 
    //returns the socket resources in $changed array 
    socket_select($changed, $null, $null, 0, 10); 

    //check for new socket 
    if (in_array($socket, $changed)) { 
     $socket_new = socket_accept($socket); //accpet new socket 
     $clients[] = $socket_new; //add socket to client array 

     $header = socket_read($socket_new, 1024); //read data sent by the socket 
     perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake 

     socket_getpeername($socket_new, $ip); //get ip address of connected socket 
     $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected'))); //prepare json data 
     send_message($response); //notify all users about new connection 

     //make room for new socket 
     $found_socket = array_search($socket, $changed); 
     unset($changed[$found_socket]); 
    } 

    //loop through all connected sockets 
    foreach ($changed as $changed_socket) { 

     //check for any incomming data 
     while(socket_recv($changed_socket, $buf, 1024, 0) >= 1) 
     { 
      $received_text = unmask($buf); //unmask data 
      $tst_msg = json_decode($received_text); //json decode 
      $user_name = $tst_msg->name; //sender name 
      $user_message = $tst_msg->message; //message text 
      $user_color = $tst_msg->color; //color 

      //prepare data to be sent to client 
      $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color))); 
      send_message($response_text); //send data 
      break 2; //exist this loop 
     } 

     $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ); 
     if ($buf === false) { // check disconnected client 
      // remove client for $clients array 
      $found_socket = array_search($changed_socket, $clients); 
      socket_getpeername($changed_socket, $ip); 
      unset($clients[$found_socket]); 

      //notify all users about disconnected connection 
      $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected'))); 
      send_message($response); 
     } 
    } 
} 
// close the listening socket 
socket_close($socket); 

function send_message($msg) 
{ 
    global $clients; 
    foreach($clients as $changed_socket) 
    { 
     @socket_write($changed_socket,$msg,strlen($msg)); 
    } 
    return true; 
} 


//Unmask incoming framed message 
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; 
} 

//Encode message for transfer to client. 
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; 
} 

//handshake new client. 
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'))); 
    //hand shaking header 
    $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . 
    "Upgrade: websocket\r\n" . 
    "Connection: Upgrade\r\n" . 
    "WebSocket-Origin: $host\r\n" . 
    "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n". 
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n"; 
    socket_write($client_conn,$upgrade,strlen($upgrade)); 
} 

上面的代碼工作fine.But現在我正在尋找客戶端作爲PHP。可以提供一些例子,使客戶端websocket使用PHP

最新通報

我需要使用PHP或JavaScript庫通過WebSocket的發送字節數組

更新2 我發現簡單的類的WebSocket的,但不知道如何使用

https://github.com/paragi/PHP-websocket-client/blob/master/websocket_client.php

也按Niket Pathak回答我試過但得到以下錯誤

<?php 
$host = 'ws://echo.websocket.org'; // your websocket server 
$port = 80; 
$local = "http://localhost"; // url where this script run | Client 
$data = '{"id": 2,"command": "server_info"}'; // data to be sent 

$head = "GET/HTTP/1.1"."\r\n". 
     "Upgrade: WebSocket"."\r\n". 
     "Connection: Upgrade"."\r\n". 
     "Origin: $local"."\r\n". 
     "Host: $host"."\r\n". 
     "Sec-WebSocket-Version: 13"."\r\n". 
     "Sec-WebSocket-Key: asdasdaas76da7sd6asd6as7d"."\r\n". 
     "Content-Length: ".strlen($data)."\r\n"."\r\n"; 
// WebSocket handshake 
$sock = fsockopen($host, $port, $errno, $errstr, 2); 
fwrite($sock, $head) or die('error:'.$errno.':'.$errstr); 
$headers = fread($sock, 2000); 
fwrite($sock, hybi10Encode($data)) or die('error:'.$errno.':'.$errstr); 
$wsdata = fread($sock, 2000); 
fclose($sock); 

var_dump(hybi10Decode($wsdata)); 

// hibi10 decoding of data 
function hybi10Decode($data) 
{ 
    $bytes = $data; 
    $dataLength = ''; 
    $mask = ''; 
    $coded_data = ''; 
    $decodedData = ''; 
    $secondByte = sprintf('%08b', ord($bytes[1])); 
    $masked = ($secondByte[0] == '1') ? true : false; 
    $dataLength = ($masked === true) ? ord($bytes[1]) & 127 : ord($bytes[1]); 
    if($masked === true) 
    { 
     if ($dataLength === 126) { 
      $mask = substr($bytes, 4, 4); 
      $coded_data = substr($bytes, 8); 
     } 
     elseif ($dataLength === 127) { 
      $mask = substr($bytes, 10, 4); 
      $coded_data = substr($bytes, 14); 
     } 
     else { 
      $mask = substr($bytes, 2, 4);  
      $coded_data = substr($bytes, 6);   
     } 
     for ($i = 0; $i < strlen($coded_data); $i++) {  
      $decodedData .= $coded_data[$i]^$mask[$i % 4]; 
     } 
    } 
    else { 
     if ($dataLength === 126) {   
      $decodedData = substr($bytes, 4); 
     } 
     elseif ($dataLength === 127) {   
      $decodedData = substr($bytes, 10); 
     } 
     else {    
      $decodedData = substr($bytes, 2);  
     }  
    } 

    return $decodedData; 
} 

// hibi10 encoding of data 
function hybi10Encode($payload, $type = 'text', $masked = true) { 
    $frameHead = array(); 
    $frame = ''; 
    $payloadLength = strlen($payload); 

    switch ($type) { 
     case 'text': 
      // first byte indicates FIN, Text-Frame (10000001): 
      $frameHead[0] = 129; 
      break; 
     case 'close': 
      // first byte indicates FIN, Close Frame(10001000): 
      $frameHead[0] = 136; 
      break; 
     case 'ping': 
      // first byte indicates FIN, Ping frame (10001001): 
      $frameHead[0] = 137; 
      break; 
     case 'pong': 
      // first byte indicates FIN, Pong frame (10001010): 
      $frameHead[0] = 138; 
      break; 
    } 

    // set mask and payload length (using 1, 3 or 9 bytes) 
    if ($payloadLength > 65535) { 
     $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); 
     $frameHead[1] = ($masked === true) ? 255 : 127; 
     for ($i = 0; $i < 8; $i++) { 
      $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); 
     } 

     // most significant bit MUST be 0 (close connection if frame too big) 
     if ($frameHead[2] > 127) { 
      $this->close(1004); 
      return false; 
     } 
    } elseif ($payloadLength > 125) { 
     $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); 
     $frameHead[1] = ($masked === true) ? 254 : 126; 
     $frameHead[2] = bindec($payloadLengthBin[0]); 
     $frameHead[3] = bindec($payloadLengthBin[1]); 
    } else { 
     $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength; 
    } 

    // convert frame-head to string: 
    foreach (array_keys($frameHead) as $i) { 
     $frameHead[$i] = chr($frameHead[$i]); 
    } 
    if ($masked === true) { 
     // generate a random mask: 
     $mask = array(); 
     for ($i = 0; $i < 4; $i++) { 
      $mask[$i] = chr(rand(0, 255)); 
     } 
     $frameHead = array_merge($frameHead, $mask); 
    } 
    $frame = implode('', $frameHead); 
    // append payload to frame: 
    for ($i = 0; $i < $payloadLength; $i++) { 
     $frame .= ($masked === true) ? $payload[$i]^$mask[$i % 4] : $payload[$i]; 
    } 

    return $frame; 
} 

錯誤

Warning: fsockopen(): unable to connect to ws://echo.websocket.org:80 (Unable to find the socket transport "ws" - did you forget to enable it when you configured PHP?) in G:\XAMPP\htdocs\a\server.php on line 16

Warning: fwrite() expects parameter 1 to be resource, boolean given in G:\XAMPP\htdocs\a\server.php on line 17 error:407024:Unable to find the socket transport "ws" - did you forget to enable it when you configured PHP?

+1

主要因爲最後一段,這似乎過於寬泛的一個問題。 「_請編輯問題以將其限制爲具有足夠細節的特定問題以確定合適的答案。避免一次詢問多個不同的問題。請參閱[如何提問](http://stackoverflow.com/help/how-to -ask)頁面以幫助澄清此問題._「 –

+0

您可以使用Ratchet Websocket(http://socketo.me/),但它也是一個服務器端實現。我在這裏做了一些CodeIgniter框架。請通過它。 https://github.com/kishor10d/CodeIgniter-Ratchet-Websocket – kishor10d

+0

@ kishor10d.is有可能發送字節數組 – iCoders

回答

2

如果您正在討論使用Php連接到WebSocket,那麼它是可行的。有幾個庫,如Php WebSocket clientWebsocket php可以作爲客戶端連接到您的websocket。

您還可以查看此Websocket Client爲例。

另一個工作實例沒有使用任何庫和實施hybi10幀編碼爲每specification

$host = 'www.host.com'; // your websocket server 
$port = 443; 
$local = "http://localhost"; // url where this script runs | Client 
$data = '{"id": 2,"command": "server_info"}'; // data to be sent 

$head = "GET/HTTP/1.1"."\r\n". 
     "Upgrade: WebSocket"."\r\n". 
     "Connection: Upgrade"."\r\n". 
     "Origin: $local"."\r\n". 
     "Host: $host"."\r\n". 
     "Sec-WebSocket-Version: 13"."\r\n". 
     "Sec-WebSocket-Key: asdasdaas76da7sd6asd6as7d"."\r\n". 
     "Content-Length: ".strlen($data)."\r\n"."\r\n"; 
// WebSocket handshake 
$sock = fsockopen($host, $port, $errno, $errstr, 2); 
fwrite($sock, $head) or die('error:'.$errno.':'.$errstr); 
$headers = fread($sock, 2000); 
fwrite($sock, hybi10Encode($data)) or die('error:'.$errno.':'.$errstr); 
$wsdata = fread($sock, 2000); 
fclose($sock); 

var_dump(hybi10Decode($wsdata)); 

// hibi10 decoding of data 
function hybi10Decode($data) 
{ 
    $bytes = $data; 
    $dataLength = ''; 
    $mask = ''; 
    $coded_data = ''; 
    $decodedData = ''; 
    $secondByte = sprintf('%08b', ord($bytes[1])); 
    $masked = ($secondByte[0] == '1') ? true : false; 
    $dataLength = ($masked === true) ? ord($bytes[1]) & 127 : ord($bytes[1]); 
    if($masked === true) 
    { 
     if ($dataLength === 126) { 
      $mask = substr($bytes, 4, 4); 
      $coded_data = substr($bytes, 8); 
     } 
     elseif ($dataLength === 127) { 
      $mask = substr($bytes, 10, 4); 
      $coded_data = substr($bytes, 14); 
     } 
     else { 
      $mask = substr($bytes, 2, 4);  
      $coded_data = substr($bytes, 6);   
     } 
     for ($i = 0; $i < strlen($coded_data); $i++) {  
      $decodedData .= $coded_data[$i]^$mask[$i % 4]; 
     } 
    } 
    else { 
     if ($dataLength === 126) {   
      $decodedData = substr($bytes, 4); 
     } 
     elseif ($dataLength === 127) {   
      $decodedData = substr($bytes, 10); 
     } 
     else {    
      $decodedData = substr($bytes, 2);  
     }  
    } 

    return $decodedData; 
} 

// hibi10 encoding of data 
function hybi10Encode($payload, $type = 'text', $masked = true) { 
    $frameHead = array(); 
    $frame = ''; 
    $payloadLength = strlen($payload); 

    switch ($type) { 
     case 'text': 
      // first byte indicates FIN, Text-Frame (10000001): 
      $frameHead[0] = 129; 
      break; 
     case 'close': 
      // first byte indicates FIN, Close Frame(10001000): 
      $frameHead[0] = 136; 
      break; 
     case 'ping': 
      // first byte indicates FIN, Ping frame (10001001): 
      $frameHead[0] = 137; 
      break; 
     case 'pong': 
      // first byte indicates FIN, Pong frame (10001010): 
      $frameHead[0] = 138; 
      break; 
    } 

    // set mask and payload length (using 1, 3 or 9 bytes) 
    if ($payloadLength > 65535) { 
     $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); 
     $frameHead[1] = ($masked === true) ? 255 : 127; 
     for ($i = 0; $i < 8; $i++) { 
      $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); 
     } 

     // most significant bit MUST be 0 (close connection if frame too big) 
     if ($frameHead[2] > 127) { 
      $this->close(1004); 
      return false; 
     } 
    } elseif ($payloadLength > 125) { 
     $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); 
     $frameHead[1] = ($masked === true) ? 254 : 126; 
     $frameHead[2] = bindec($payloadLengthBin[0]); 
     $frameHead[3] = bindec($payloadLengthBin[1]); 
    } else { 
     $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength; 
    } 

    // convert frame-head to string: 
    foreach (array_keys($frameHead) as $i) { 
     $frameHead[$i] = chr($frameHead[$i]); 
    } 
    if ($masked === true) { 
     // generate a random mask: 
     $mask = array(); 
     for ($i = 0; $i < 4; $i++) { 
      $mask[$i] = chr(rand(0, 255)); 
     } 
     $frameHead = array_merge($frameHead, $mask); 
    } 
    $frame = implode('', $frameHead); 
    // append payload to frame: 
    for ($i = 0; $i < $payloadLength; $i++) { 
     $frame .= ($masked === true) ? $payload[$i]^$mask[$i % 4] : $payload[$i]; 
    } 

    return $frame; 
} 

最後,您可以通過它編碼爲Base64發送您的字節數據作爲JSON對象第一。 檢查此SO Post看看如何做到這一點。希望這可以幫助。

+0

@ niket.Thanks尋求答案。但我只需要發送字節數組而不需要編碼,因爲c程序代碼的寫法是這樣的 – iCoders

+0

我通過更改主機來運行上面的代碼,但出現錯誤。 警告:fsockopen():無法連接到ws://echo.websocket.org:80(無法找到套接字傳輸「ws」 - 您忘記在配置PHP時啓用它?)在G:\ XAMPP \ htdocs \ a \ server.php on line 16 警告:fwrite()期望參數1是資源,布爾在第17行給出的G:\ XAMPP \ htdocs \ a \ server.php中存在 錯誤:407024:無法找到套接字傳輸「ws」 - 你忘了在配置PHP時啓用它嗎? – iCoders

+0

$ host ='ws://echo.websocket.org'; $ port = 80; $ local =「http:// localhost」; – iCoders

2

我unswer NO。您不能完全使用websocket客戶端登錄,僅使用服務器部分(例如php)。因爲服務器端知道關於瀏覽器的任何信息。服務器 - 接收請求並返回靜態結果。瀏覽器中的所有魔法都是JavaScript。 Javascript可以動態偵聽所有用戶事件,將查詢發佈到服務器並從服務器向頁面插入響應。 WebSocket在瀏覽器中無法使用JavaScript。 這是WebSocket的定義:

WebSockets are a bi-directional, full-duplex, persistent connection from a web browser to a server. Once a WebSocket connection is established the connection stays open until the client or server decides to close this connection. With this open connection, the client or server can send a message at any given time to the other. This makes web programming entirely event driven, not (just) user initiated. It is stateful. As well, at this time, a single running server application is aware of all connections, allowing you to communicate with any number of open connections at any given time.

你能做的唯一的事情,就是學會節點JS。它將允許您使用一種語言編寫瀏覽器(客戶端)部分和服務器部分 - javascript。但是,這將是不同的應用程序部分,並且您將使用不同的方法來編程每個部分

+0

@ Nutscracker.thanks for answer.is有任何php或javacript代碼發送wqebsocket.even字節數組庫alos對我來說好吧 – iCoders

+0

@iCoders你可以使用javascript函數ArrayBuffer https://developer.mozilla.org/en/docs/Web/JavaScript/Typed_arrays,https://developer.mozilla.org/en/docs/Web/ API/XMLHttpRequest/Sending_and_Receiving_Binary_Data。 PHP有方法打包和解壓縮二進制數據 – Nutscracker

+0

@ Nutscracker.Thanks你可以給我一個簡單的例子來發送使用php packe和解壓縮字節數組。因爲我已經嘗試.http://stackoverflow.com/questions/43092252/php -send-array-bytes-in-web-socket – iCoders

相關問題