Answer the question
In order to leave comments, you need to log in
Online consultant on sockets?
Hey! The task is quite ordinary: Add an online consultant to the site.
So, I decided that ajax requests with periodic updates for such a task would be the wrong solution and chose how to implement the solution on sockets, I collected a script from the Internet in order to understand how this technology works in general, and now I’m thinking whether it’s worth delving into her, because it is not very easy and it is given.
Script: a regular chat where users chat with each other.
Problem: the script works fine, but if you add saving messages to the database, then the script starts loading the site and the database for a long time so that you can’t connect to them, make a request, or even open other pages.
<?php
// СЕРВЕР
set_time_limit(0); // задаём скрипту постоянную работу
// ----- ПОДКЛЮЧЕНИЕ К БАЗЕ ДАННЫХ ----- \\
$db_host = 'localhost';
$db_name = 'rata_db';
$db_user = 'mysql';
$db_pass = 'mysql';
$db = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
mysqli_set_charset($db, "utf8");
$host = 'rata'; // адрес хоста
$port = '936'; // порт прослушивания
$null = NULL; // null var
// создаём TCP/IP стрим сокет
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, $host, $port);
socket_listen($socket);
socket_set_block($socket);
$clients = array($socket);
while (true) {
$changed = $clients;
socket_select($changed, $null, $null, 0, 10);
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket);
socket_set_block($socket_new);
$clients[] = $socket_new;
$header = socket_read($socket_new, 1024);
perform_handshaking($header, $socket_new, $host, $port);
socket_getpeername($socket_new, $ip);
$response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected')));
send_message($response);
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
foreach ($changed as $changed_socket) {
while(socket_recv($changed_socket, $buf, 1024, 0) >= 1) {
$received_text = unmask($buf);
$tst_msg = json_decode($received_text);
$user_name = $tst_msg->name;
$user_message = $tst_msg->message;
$user_color = $tst_msg->color;
if($changed_socket) {
$ins_msg = mysqli_query($db, "INSERT INTO chat
(msg_nick,msg_txt)
VALUES
('$user_name','$user_message')")
or die("Ошибка: ".mysqli_error($db));
}
// подготовить данные для отправки клиенту
$response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color)));
send_message($response_text); // отправляем данные
break 2; // exist this loop
}
$buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
if ($buf === false) { // проверка отсоединения клиента
// поиск сокета в массиве $clients
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]); // удалить из массива
// уведомляем всех об отсоединении клиента
$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;
}
// раскодируем входящее сообщение
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;
}
// кодируем сообщение клиенту
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;
}
// рукопожатие с новым клиентом
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')));
// отправляемые заголовки
$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));
}
echo 'Время выполнения скрипта: '.round(microtime(true) - $start, 4).' сек.';
?>
<?php
set_time_limit(0); // задаём скрипту постоянную работу
?>
<?php
$colours = array('007AFF','FF7000','FF7000','15E25F','CFC700','CFC700','CF1100','CF00BE','F00');
$user_colour = array_rand($colours);
?>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function(){
//create a new WebSocket object.
var wsUri = "ws://rata:936/sock3/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;
}
//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
};
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="10" style="width:20%" />
<input type="text" name="message" id="message" placeholder="Message" maxlength="80" style="width:60%" />
<button id="send-btn">Send</button>
</div>
</div>
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question