실시간 채팅 사업
WebSocket으로 PHP 라이브 채팅 응용 프로그램을 만드는 방법에 대한 자습서에 오신 것을 환영합니다.
실시간 PHP 응용 프로그램 및 WebSocket에 대한 조사를 수행하는 동안 여러 라이브 채팅이 나타났습니다.
놀랍게도, 대부분은 유료이거나 AJAX 긴 폴링에서 실행됩니다.
내가 찾던 것이 아니고, 내 생각에 하나를 만들어 팔아 버리겠다는 사악한 생각이 나왔지만… 저의 Jedi 블로거 측은 결국이 안내서의 목적을 인수했습니다 – WebSockets의 작동 방식, 실시간 애플리케이션에 어떻게 사용할 수 있는지, 인터넷의 석기 시대가 끝났다는 점을 공유합니다. 알아 보려면 계속 읽으십시오!
ⓘ이 튜토리얼의 시작 부분에 모든 소스 코드가 포함 된 zip 파일이 포함되어 있으므로 모든 것을 복사하여 붙여 넣을 필요가 없습니다.
소스 코드 다운로드
먼저 약속 한대로 소스 코드에 대한 다운로드 링크가 있습니다.
소스 코드 다운로드
소스 코드를 다운로드하려면 여기를 클릭하십시오. MIT 라이센스에 따라 릴리스되었으므로 그 위에 빌드하거나 자신의 프로젝트에서 자유롭게 사용하십시오.
빠른 시작
당신이 버그를 발견하면, 아래에 의견을 주시기 바랍니다. 나도 질문에 대답하려고 하지만 전 세계 대 한 사람입니다… 긴급한 답변이 필요한 경우, 웹 사이트 목록을 확인하여 프로그래밍에 대한 도움을 받으십시오.
개요
코드를 작성하기 전에 시스템 개요 섹션과 필요한 항목으로 시작하겠습니다.
시스템 개요
이 라이브 채팅 시스템에는 3 가지 부분이 있습니다.
AJAX LONG POLLING VS 웹 소켓
위의 소개에서 "AJAX 긴 폴링"이 언급되어 있음을 기억하십니까? 그것은 무엇이고 WebSocket은 어떻게 다른가? 긴 이야기는 짧습니다.
그렇습니다. 여러분 중 일부는 날카로운 코드 사용자가 이것을 알아 냈을 것입니다. "항상 켜짐" WebSocket 연결은 실시간 응용 프로그램의 컨텍스트에서 더 잘 작동합니다.
PHP 소켓 확장
이 프로젝트가 작동하려면 소켓 확장을 활성화해야 합니다. php.ini 파일의 확장자 섹션을 보고 그에 따라 활성화하십시오 :
extension=sockets
웹 소켓 기본
WebSockets는 초보자에게 매우 어려울 수 있으므로 간단한 예제와 충돌 과정으로 시작하겠습니다. 이 멋진 WebSocket 예제에 대해 Vladimir Kovpak에게 특별한 감사를 드립니다.
서버 측 PHP 스크립트
// CHANGE THE ADDRESS AND PORT TO YOUR OWN! $address = '192.168.0.101'; $port = 12345; // CREATE WEBSOCKET + LISTEN FOR CONNECTION $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($socket, $address, $port); socket_listen($socket); $client = socket_accept($socket); // WEBSOCKET HANDSHAKE HEADERS // https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers $request = socket_read($client, 5000); preg_match('#Sec-WebSocket-Key: (.*)\r\n#', $request, $matches); $key = base64_encode(pack('H*', sha1($matches[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); $headers = "HTTP/1.1 101 Switching Protocols\r\n"; $headers .= "Upgrade: websocket\r\n"; $headers .= "Connection: Upgrade\r\n"; $headers .= "Sec-WebSocket-Version: 13\r\n"; $headers .= "Sec-WebSocket-Accept: $key\r\n\r\n"; socket_write($client, $headers, strlen($headers)); // ENDLESS LOOP - SEND MESSAGES INTO WEBSOCKET while (true) { $content = 'Now: ' . time(); $response = chr(129) . chr(strlen($content)) . $content; socket_write($client, $response); sleep(1); }
서버 측 스크립트를 작성하여 프로젝트를 시작합니다.
클라이언트 자바 스크립트
<html> <head> <title>Simple WebSocket Example</title> <script> window.addEventListener("load", function(){ // CHANGE THE HOST TO YOUR OWN! var host = 'ws://192.168.0.101:12345/'; // CREATE WEB SOCKET & LISTEN FOR UPDATES var socket = new WebSocket(host); socket.onmessage = function (e) { document.getElementById('messages').innerHTML = e.data; }; }); </script> </head> <body> <div id="messages"></div> </body> </html>
다음으로, 이것은 클라이언트 측에서 얻는 것만 큼 간단합니다. 우리가 해야 할 일은 서버 소켓에 연결하고 업데이트가 진행되는 동안 업데이트하는 것입니다.
엔진을 시작하십시오!
서버와 클라이언트 측 모두에서 스크립트가 준비되면 명령 프롬프트 (또는 터미널)에서 스크립트를 시작할 수 있습니다.
D:\http\test>php 1-server.php
그런 다음 웹 브라우저에서 클라이언트 스크립트에 액세스하십시오.
서버 측 스크립트
WebSocket의 작동 방식을 이해 했으므로 스크립트를 “업그레이드”하여 실제 라이브 채팅으로 전환 해 보겠습니다.
스크립트
/* (1) SETTINGS + SUPPORT FUNCTIONS */ // VERBOSE - SHOWS SYSTEM MESSAGES $verbose = true; // CHANGE THE ADDRESS AND PORT TO YOUR OWN! $address = '192.168.0.101'; $port = 12345; // SUPPORT FUNCTION // Source: https://srchea.com/build-a-real-time-application-using-html5-websockets function unmask ($payload) { $length = ord($payload[1]) & 127; if ($length == 126) { $masks = substr($payload, 4, 4); $data = substr($payload, 8); } elseif ($length == 127) { $masks = substr($payload, 10, 4); $data = substr($payload, 14); } else { $masks = substr($payload, 2, 4); $data = substr($payload, 6); } $text = ''; for ($i = 0; $i < strlen($data); ++$i) { $text .= $data[$i] ^ $masks[$i%4]; } return $text; } /* (2) CREATE WEBSOCKET + LISTEN FOR CONNECTIONS */ $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($socket, $address, $port); socket_listen($socket); socket_set_nonblock($socket); // Allow multiple client connections /* (3) ENDLESS LOOP */ $clients = []; $buffer = ""; while (true) { /* (4) LISTEN FOR NEW CONNECTIONS */ // WEBSOCKET HANDSHAKE HEADERS if (($client = socket_accept($socket)) !== false) { if ($verbose) { echo "New client connection\r\n"; } $request = socket_read($client, 5000); if ($verbose) { echo $request; } preg_match('#Sec-WebSocket-Key: (.*)\r\n#', $request, $matches); $key = base64_encode(pack('H*', sha1($matches[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); $headers = "HTTP/1.1 101 Switching Protocols\r\n"; $headers .= "Upgrade: websocket\r\n"; $headers .= "Connection: Upgrade\r\n"; $headers .= "Sec-WebSocket-Version: 13\r\n"; $headers .= "Sec-WebSocket-Accept: $key\r\n\r\n"; socket_write($client, $headers, strlen($headers)); $clients[] = $client; if ($verbose) { echo "Total " . count($clients) . " client connection(s)\r\n"; } } if (count($clients)>0) { /* (5) LISTEN FOR DATA INPUT */ foreach ($clients as $c) { if (($chat = socket_read($c, 5000)) !== false) { // The client message is masked! // We need to unmask it to get back the original message $buffer .= unmask($chat) . "<br>"; if ($verbose) { echo "Buffer - " . $buffer . "\r\n"; } } } /* (6) UPDATE CHAT TO ALL CONNECTED CLIENTS */ if ($buffer != "") { $chat = chr(129) . chr(strlen($buffer)) . $buffer; if ($verbose) { echo "Output Buffer - " . $chat . "\r\n"; } foreach ($clients as $c) { socket_write($c, $chat); } $buffer = ""; } } }
설명
이런 젠장. 여러분 중 일부는 이 서버 측 스크립트의“소규모 개선 사항”에서 입안에서 거품이 날 수 있습니다… 그러나 그것이 작동하는 방식은 여전히 근본적으로 동일합니다. 유일한 예외는 벙어리 "출력 타임 스탬프"대신 여러 클라이언트 연결을 허용하고 양방향 통신을 허용하는 기능을 추가 한 것입니다. 요약은 다음과 같습니다.
클라이언트 측 스크립트
마지막으로 클라이언트 측 스크립트도 업데이트하고 서버에 메시지를 보내는 기능을 추가합니다.
스크립트
<html> <head> <title>Simple WebSocket Example</title> <script> var chat = { // CHANGE THE HOST TO YOUR OWN! host : "ws://192.168.0.101:12345/", socket : null, // Will hold the socket object // HTML ELEMENTS ewrap : null, // Chat message container etext : null, // Text input esend : null, // Send message button init : function () { // chat.init() : initialize // Get HTML elements chat.ewrap = document.getElementById("chat-wrap"); chat.etext = document.getElementById("chat-text"); chat.esend = document.getElementById("chat-send"); // READY - connected to server chat.socket.onopen = function (e) { chat.esend.disabled = false; }; // On connection close chat.socket.onclose = function (e) { chat.esend.disabled = true; }; // On connection error chat.socket.onerror = function (e) { chat.esend.disabled = true; console.log(e); }; }, send : function () { // chat.send() : send message to server chat.socket.send(chat.etext.value); chat.etext.value = ""; return false; } }; window.addEventListener("load", chat.init); </script> </head> <body> <div id="chat-wrap"></div> <form onsubmit="return chat.send()"> <input type="text" id="chat-text" required/> <input type="submit" id="chat-send" value="Send" disabled/> </form> </body> </html>
설명
여러분 중 일부는 Javascript에서 만든 "개선"을 통해 입안에서 다시 거품을 낼 것입니다. 그러나 침착하게 주의 깊게 살펴보십시오.
엔진 재시동
남아있는 것은 이전과 동일합니다 – 명령 행에서 서버 측 스크립트를 실행하고 웹 브라우저에서 클라이언트 측 스크립트에 액세스하십시오.
유용한 비트 및 제한
이것이 이 프로젝트의 전부이며, 여기에 도움이 될만한 추가 정보에 대한 작은 섹션이 있습니다.
참조
소켓에 대한 자세한 내용은 공식 링크를 참조하십시오.
한계
이 채팅 스크립트는 매우 단순합니다. 사용자 식별이 없으며 사용자가 연결을 닫은 경우 서버 측에서 감지하지 않습니다. 오류 관리도 없습니다. 이 모든 것은 모든 사람의 프로젝트 요구에 달려 있으며, 더 이상 추가하지 않겠습니다… 무료 점심은 제공하지 마십시오. ?
등록된 댓글이 없습니다.