2017-07-21 207 views
0

我在服務器端使用PHP web套接字。我目前只測試客戶端和服務器之間的連接,所以我還沒有配置套接字來響應特定的事件。這是基本的模板是什麼樣子:與PHP websocket的Socket.io握手?

#!/php -q 
<?php /* >php -q server.php */ 

error_reporting(E_ALL); 
set_time_limit(0); 
ob_implicit_flush(); 

$master = WebSocket("example.com",8080); 
$sockets = array($master); 
$users = array(); 
$debug = false; 

while(true){ 
    $changed = $sockets; 
    socket_select($changed,$write=NULL,$except=NULL,NULL); 
    foreach($changed as $socket){ 
    if($socket==$master){ 
     $client=socket_accept($master); 
     if($client<0){ console("socket_accept() failed"); continue; } 
     else{ connect($client); } 
    } 
    else{ 
     $bytes = @socket_recv($socket,$buffer,2048,0); 
     if($bytes==0){ disconnect($socket); } 
     else{ 
     $user = getuserbysocket($socket); 
     if(!$user->handshake){ dohandshake($user,$buffer); } 
     else{ process($user,$buffer); } 
     } 
    } 
    } 
} 

//--------------------------------------------------------------- 
function process($user,$msg){ 
    $action = unwrap($msg); 
    say("< ".$action); 
    switch($action){ 
case "hello" : send($user->socket,"hello human");      break; 
case "hi" : send($user->socket,"zup human");       break; 
case "name" : send($user->socket,"my name is Multivac, silly I know"); break; 
case "age" : send($user->socket,"I am older than time itself");  break; 
case "date" : send($user->socket,"today is ".date("Y.m.d"));   break; 
case "time" : send($user->socket,"server time is ".date("H:i:s"));  break; 
case "thanks": send($user->socket,"you're welcome");     break; 
case "bye" : send($user->socket,"bye");        break; 
default  : send($user->socket,$action." not understood");   break; 
    } 
} 

function send($client,$msg){ 
    say("> ".$msg); 
    $msg = wrap($msg); 
    socket_write($client,$msg,strlen($msg)); 
} 

function WebSocket($address,$port){ 
    $master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)  or die("socket_create() failed"); 
    socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed"); 
    socket_bind($master, $address, $port)     or die("socket_bind() failed"); 
    socket_listen($master,20)        or die("socket_listen() failed"); 
    echo "Server Started : ".date('Y-m-d H:i:s')."\n"; 
    echo "Master socket : ".$master."\n"; 
    echo "Listening on : ".$address." port ".$port."\n\n"; 
    return $master; 
} 

function connect($socket){ 
    global $sockets,$users; 
    $user = new User(); 
    $user->id = uniqid(); 
    $user->socket = $socket; 
    array_push($users,$user); 
    array_push($sockets,$socket); 
    console($socket." CONNECTED!"); 
} 

function disconnect($socket){ 
    global $sockets,$users; 
    $found=null; 
    $n=count($users); 
    for($i=0;$i<$n;$i++){ 
    if($users[$i]->socket==$socket){ $found=$i; break; } 
    } 
    if(!is_null($found)){ array_splice($users,$found,1); } 
    $index = array_search($socket,$sockets); 
    socket_close($socket); 
    console($socket." DISCONNECTED!"); 
    if($index>=0){ array_splice($sockets,$index,1); } 
} 

function dohandshake($user,$buffer){ 
    console("\nRequesting handshake..."); 
    console($buffer); 
    list($resource,$host,$origin,$strkey1,$strkey2,$data) = getheaders($buffer); 
    console("Handshaking..."); 

    $pattern = '/[^\d]*/'; 
    $replacement = ''; 
    $numkey1 = preg_replace($pattern, $replacement, $strkey1); 
    $numkey2 = preg_replace($pattern, $replacement, $strkey2); 

    $pattern = '/[^ ]*/'; 
    $replacement = ''; 
    $spaces1 = strlen(preg_replace($pattern, $replacement, $strkey1)); 
    $spaces2 = strlen(preg_replace($pattern, $replacement, $strkey2)); 

    if ($spaces1 == 0 || $spaces2 == 0 || $numkey1 % $spaces1 != 0 || $numkey2 % $spaces2 != 0) { 
    socket_close($user->socket); 
    console('failed'); 
    return false; 
    } 

    $ctx = hash_init('md5'); 
    hash_update($ctx, pack("N", $numkey1/$spaces1)); 
    hash_update($ctx, pack("N", $numkey2/$spaces2)); 
    hash_update($ctx, $data); 
    $hash_data = hash_final($ctx,true); 

    $upgrade = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" . 
       "Upgrade: WebSocket\r\n" . 
       "Connection: Upgrade\r\n" . 
       "Sec-WebSocket-Origin: " . $origin . "\r\n" . 
       "Sec-WebSocket-Location: ws://" . $host . $resource . "\r\n" . 
       "\r\n" . 
       $hash_data; 

    socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0))); 
    $user->handshake=true; 
    console($upgrade); 
    console("Done handshaking..."); 
    return true; 
} 

function getheaders($req){ 
    $r=$h=$o=null; 
    if(preg_match("/GET (.*) HTTP/" ,$req,$match)){ $r=$match[1]; } 
    if(preg_match("/Host: (.*)\r\n/" ,$req,$match)){ $h=$match[1]; } 
    if(preg_match("/Origin: (.*)\r\n/",$req,$match)){ $o=$match[1]; } 
    if(preg_match("/Sec-WebSocket-Key2: (.*)\r\n/",$req,$match)){ $key2=$match[1]; } 
    if(preg_match("/Sec-WebSocket-Key1: (.*)\r\n/",$req,$match)){ $key1=$match[1]; } 
    if(preg_match("/\r\n(.*?)\$/",$req,$match)){ $data=$match[1]; } 
    return array($r,$h,$o,$key1,$key2,$data); 
} 

function getuserbysocket($socket){ 
    global $users; 
    $found=null; 
    foreach($users as $user){ 
    if($user->socket==$socket){ $found=$user; break; } 
    } 
    return $found; 
} 

function  say($msg=""){ echo $msg."\n"; } 
function wrap($msg=""){ return chr(0).$msg.chr(255); } 
function unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); } 
function console($msg=""){ global $debug; if($debug){ echo $msg."\n"; } } 

class User{ 
    var $id; 
    var $socket; 
    var $handshake; 
} 

?> 

,我想從我的雨燕客戶端Socket.io連接到這個插座:

let io:SocketIOClient = SocketIOClient(socketURL: URL(string: "example.com:8080/server.php")!, config: [.log(true), .compress]) 

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.io.on(clientEvent: .connect) { (data:[Any], ack:SocketAckEmitter) in 
     NSLog("Socket connected!") 
    } 
    self.io.on(clientEvent: .disconnect) { (data:[Any], ack:SocketAckEmitter) in 
     NSLog("Socket disconnected!") 
    } 
    self.io.connect() 
} 

我跑我的Mac上的終端服務器與SSH。 PHP網絡套接字表示它正在監聽連接,但它不響應socket.io連接。服務器和客戶端都給我任何錯誤,所以我假設我錯過了連接過程中的關鍵步驟。我想知道當你試圖連接到一個PHP web套接字時,是否可以用Socket.IO swift客戶端進行握手。這是一個兼容性問題還是我忘記了什麼?順便說一下,現在你可能已經注意到我對web套接字編程非常陌生(我不到一週前就發現了websocket),所以請原諒,如果這是一個真正的問題。我感謝任何幫助,我可以得到。謝謝!

回答

0

socket.io != webSocket。您無法將socket.io客戶端連接到webSocket服務器。 Socket.io在webSocket上添加自己的協議。雖然socket.io在封面下使用webSocket傳輸,但如果您只有一個webSocket服務器,則客戶端將無法連接。

您必須將webSocket客戶端連接到webSocket服務器。或者,將一個socket.io客戶端連接到一個socket.io服務器。

因此,就你的情況而言,如果你有一個socket.io客戶端,那麼你需要爲你的服務器環境獲取一個socket.io服務器,然後使用它。

+0

Socket.io服務器僅在Javascript(Node.js)中可用,我不熟悉這一點。我知道的唯一的服務器端語言是PHP,所以不可能僅僅替換連接的客戶端呢?舉個例子,Starscream說它是一個websocket客戶端(不像Socket.io那樣),所以我不能使用它來代替Socket.io? –

+0

@MarkCarols - socket.io服務器可用於許多其他環境(Java,PHP,C#等)。對於PHP,請參閱[this](https://www.google.com/search?q=socket.io+php&rlz=1C1CHFX_enUS515US515&oq=socket.io+php&aqs=chrome..69i57j0l5.1720j0j7&sourceid=chrome&ie=UTF-8)。瀏覽器內置了對webSocket的支持,所以你可以在瀏覽器中使用普通的webSocket。你只是不會有一些在這個答案中列出的socket.io功能:[從socket.io移動到原始websockets?](https://stackoverflow.com/questions/38546496/moving-from-socket-io -to-原始的WebSockets/38546537#38546537)。 – jfriend00

+0

謝謝!我會查看一些鏈接,看看哪一個最容易實現。 –