댓글 검색 목록

[php] Websocket으로 PHP 라이브 채팅을 만드는 방법

페이지 정보

작성자 운영자 작성일 20-04-19 16:57 조회 1,356 댓글 0

실시간 채팅 사업 


WebSocket으로 PHP 라이브 채팅 응용 프로그램을 만드는 방법에 대한 자습서에 오신 것을 환영합니다. 

실시간 PHP 응용 프로그램 및 WebSocket에 대한 조사를 수행하는 동안 여러 라이브 채팅이 나타났습니다. 

놀랍게도, 대부분은 유료이거나 AJAX 긴 폴링에서 실행됩니다.


내가 찾던 것이 아니고, 내 생각에 하나를 만들어 팔아 버리겠다는 사악한 생각이 나왔지만… 저의 Jedi 블로거 측은 결국이 안내서의 목적을 인수했습니다 – WebSockets의 작동 방식, 실시간 애플리케이션에 어떻게 사용할 수 있는지, 인터넷의 석기 시대가 끝났다는 점을 공유합니다. 알아 보려면 계속 읽으십시오!


ⓘ이 튜토리얼의 시작 부분에 모든 소스 코드가 포함 된 zip 파일이 포함되어 있으므로 모든 것을 복사하여 붙여 넣을 필요가 없습니다.



소스 코드 다운로드 


먼저 약속 한대로 소스 코드에 대한 다운로드 링크가 있습니다.


소스 코드 다운로드 


소스 코드를 다운로드하려면 여기를 클릭하십시오. MIT 라이센스에 따라 릴리스되었으므로 그 위에 빌드하거나 자신의 프로젝트에서 자유롭게 사용하십시오.


빠른 시작 


  • 폴더에 다운로드하여 압축을 풉니다.
  • zip 파일에는 2 개의 코드 세트가 있습니다. 1-server.php와 1-client.html은 라이브 채팅이 아니라 WebSocket의 간단한 데모입니다.
  • 2-chat-server.php와 2-chat-client.html은 라이브 채팅입니다.
  • 명령 행에서 2-chat-server.php를 실행하십시오.
  • 웹 브라우저에서 2-chat-client.html에 액세스하십시오.

당신이 버그를 발견하면, 아래에 의견을 주시기 바랍니다. 나도 질문에 대답하려고 하지만 전 세계 대 한 사람입니다… 긴급한 답변이 필요한 경우, 웹 사이트 목록을 확인하여 프로그래밍에 대한 도움을 받으십시오.


개요 


코드를 작성하기 전에 시스템 개요 섹션과 필요한 항목으로 시작하겠습니다.


시스템 개요 


php-live-chat-overview.jpg 


이 라이브 채팅 시스템에는 3 가지 부분이 있습니다.


  • 데이터베이스 – 대화를 저장합니다.
  • 서버 – 채팅을 호스팅 할 PHP 스크립트.
  • 클라이언트 – 서버에 연결할 HTML / 자바 스크립트입니다.

AJAX LONG POLLING VS 웹 소켓 


위의 소개에서 "AJAX 긴 폴링"이 언급되어 있음을 기억하십니까? 그것은 무엇이고 WebSocket은 어떻게 다른가? 긴 이야기는 짧습니다.

  • AJAX는 서버에 대한 비동기 연결입니다. 일단 데이터를 받으면 연결이 닫힙니다. 장기 폴링은 실시간 연결을 시뮬레이션하기 위해 오랜 시간 동안 서버에 여러 AJAX 요청을 실행하여 작동합니다.
  • 반면에 소켓은 "영구적"연결입니다. 일단 서버에 연결하면 수동으로 연결을 끊을 때까지 연결이 유지됩니다.


그렇습니다. 여러분 중 일부는 날카로운 코드 사용자가 이것을 알아 냈을 것입니다. "항상 켜짐" WebSocket 연결은 실시간 응용 프로그램의 컨텍스트에서 더 잘 작동합니다.


PHP 소켓 확장 


이 프로젝트가 작동하려면 소켓 확장을 활성화해야 합니다. php.ini 파일의 확장자 섹션을 보고 그에 따라 활성화하십시오 :


extension=sockets 



웹 소켓 기본 


WebSockets는 초보자에게 매우 어려울 수 있으므로 간단한 예제와 충돌 과정으로 시작하겠습니다. 이 멋진 WebSocket 예제에 대해 Vladimir Kovpak에게 특별한 감사를 드립니다.


서버 측 PHP 스크립트 


<?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); } ?> 


서버 측 스크립트를 작성하여 프로젝트를 시작합니다.


  • 이 스크립트는 지정된 주소, 포트 번호에서 소켓을 열고 클라이언트 연결을 수신합니다.
  • 이해하기 어려운 부분은 PHP가 WebSockets를 기본적으로 지원하지 않는다는 것입니다. 우리는 클라이언트에게 핸드 셰이크 헤더를 직접 제공해야 합니다.
  • 원하는 경우 MDN 웹 문서에서 WebSocket 헤더에 대한 자세한 내용을 읽을 수 있습니다.
  • 마지막 부분은 실제로 그렇게 많은 미스터리가 아닙니다. 우리는 단순히 이 스크립트를 계속 실행하고 무한한 while 루프로 연결된 클라이언트에 더미 타임 스탬프를 출력합니다.


클라이언트 자바 스크립트 


<!DOCTYPE html> <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 


그런 다음 웹 브라우저에서 클라이언트 스크립트에 액세스하십시오.


php-websocket-ss.jpg 


서버 측 스크립트 


WebSocket의 작동 방식을 이해 했으므로 스크립트를 “업그레이드”하여 실제 라이브 채팅으로 전환 해 보겠습니다.


스크립트 


<?php /* (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 = ""; } } } ?> 


설명 


이런 젠장. 여러분 중 일부는 이 서버 측 스크립트의“소규모 개선 사항”에서 입안에서 거품이 날 수 있습니다… 그러나 그것이 작동하는 방식은 여전히 ​​근본적으로 동일합니다. 유일한 예외는 벙어리 "출력 타임 스탬프"대신 여러 클라이언트 연결을 허용하고 양방향 통신을 허용하는 기능을 추가 한 것입니다. 요약은 다음과 같습니다.


  1. 평소와 같이 설정 및 지원 기능으로 시작합니다.
  2. WebSocket을 만들고 엽니다.
  3. 무한 루프를 만듭니다.
  4. 새로운 연결을 듣고 WebSocket 마술 핸드 셰이크를 하십시오.
  5. 사용자의 채팅 입력을 듣고 버퍼에 저장하십시오.
  6. 채팅 버퍼를 연결된 모든 클라이언트에 출력하여 업데이트합니다.

클라이언트 측 스크립트 


마지막으로 클라이언트 측 스크립트도 업데이트하고 서버에 메시지를 보내는 기능을 추가합니다.


스크립트 


<!DOCTYPE html> <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에서 만든 "개선"을 통해 입안에서 다시 거품을 낼 것입니다. 그러나 침착하게 주의 깊게 살펴보십시오.


  • 채팅을 위한 텍스트 입력을 받을 수 있는 간단한 양식 만 추가했습니다.
  • 상황이 복잡해 보일 수 있지만 모든 채팅 관련 내용을 var chat에 넣어서 더 잘 정리할 수 있습니다.
  • 작업 주체는 위의 간단한 예와 동일합니다.
  • 서버에 더 많은 메시지를 수신하면 서버에 연결하고 채팅 양식을 활성화 하고 보기를 업데이트하십시오.

엔진 재시동 


남아있는 것은 이전과 동일합니다 – 명령 행에서 서버 측 스크립트를 실행하고 웹 브라우저에서 클라이언트 측 스크립트에 액세스하십시오.


유용한 비트 및 제한 


이것이 이 프로젝트의 전부이며, 여기에 도움이 될만한 추가 정보에 대한 작은 섹션이 있습니다.


참조 


소켓에 대한 자세한 내용은 공식 링크를 참조하십시오.


한계 


이 채팅 스크립트는 매우 단순합니다. 사용자 식별이 없으며 사용자가 연결을 닫은 경우 서버 측에서 감지하지 않습니다. 오류 관리도 없습니다. 이 모든 것은 모든 사람의 프로젝트 요구에 달려 있으며, 더 이상 추가하지 않겠습니다… 무료 점심은 제공하지 마십시오. ?



댓글목록 0

등록된 댓글이 없습니다.

웹학교 로고

온라인 코딩학교

코리아뉴스 2001 - , All right reserved.