Клиент отключается до того, как сервер получил все сообщения - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь привыкнуть к программированию сокетов в PHP (это только для обучения). Я уже написал простой эхо-сервер, который, кажется, работает правильно (протестировано с PuTTY) Моя проблема только на стороне клиента.
Вот что я получил (пока нет обработки ошибок, пожалуйста, потерпите меня):

server.php :

$host = '127.0.0.1';
$port = 10000;
$null = null;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_nonblock($socket);
socket_bind($socket, $host, $port);
socket_listen($socket);

echo("[Listening...]\r\n");

$client_list = [$socket];

while(true) {
    $changed_clients = $client_list;

    $select = socket_select($changed_clients, $null, $null, 0, 10);
    if($select < 1) {
        continue;
    }

    if(in_array($socket, $changed_clients)) {
        $client_list[] = $new_client = socket_accept($socket);
        $msg = "Welcome to the server!\r\n";
        socket_write($new_client, $msg, strlen($msg));
        socket_getpeername($new_client, $ip);
        echo("[New client has connected: " . $ip . "]\r\n");
    }

    foreach($client_list as $client) {
        if($client !== $socket) {   // ignore server socket
            $msg = @socket_read($client, 4096, PHP_NORMAL_READ);

            if($msg === false) { // client disconnected
                socket_getpeername($client, $ip);
                $key = array_search($client, $client_list);
                unset($client_list[$key]);
                echo("[Client " . $ip . " disconnected]\r\n");
                continue; // next client
            }

            $msg = trim($msg);
            if(!empty($msg)) {
                if($msg == "shutdown") {
                    echo("[Shutting down...]\r\n");
                    break 2;
                }
                if($msg == "quit") {
                    echo("[Disconnecting client...]\r\n");
                    socket_close($client);
                    $key = array_search($client, $client_list);
                    unset($client_list[$key]);
                    continue;
                }

                socket_getpeername($new_client, $ip);
                $msg = $ip . ": " . $msg . "\r\n";
                echo($msg);
                foreach($client_list as $send_socket) {
                    if($send_socket === $socket) {
                        continue;
                    }
                    socket_send($send_socket, $msg, strlen($msg), 0);
                }
            }
        }
    }
}

socket_close($socket);

client.php

error_reporting (E_ALL);

$host = '127.0.0.1';
$port = 10000;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_connect($socket, $host, $port);

for($i = 0; $i<10; $i++) {
    $msg = "Test " . $i . "\r\n";
    socket_write($socket, $msg, strlen($msg)); 
}

socket_close($socket);

Желаемый вывод server.php:

[Listening...]
[New client has connected: 127.0.0.1]
127.0.0.1: Test 0
127.0.0.1: Test 1
127.0.0.1: Test 2
127.0.0.1: Test 3
127.0.0.1: Test 4
127.0.0.1: Test 5
127.0.0.1: Test 6
127.0.0.1: Test 7
127.0.0.1: Test 8
127.0.0.1: Test 9
[Client 127.0.0.1 disconnected]

Фактический объем производства:

[Listening...]
[New client has connected: 127.0.0.1]
[Client 127.0.0.1 disconnected]

Я уже понял, что проблема в том, что скрипт client.php заканчивает свое выполнение до того, как сервер прочитает сообщения (используя socket_read). Если я увеличу число итераций цикла for в клиентском скрипте, некоторые сообщения найдут свой путь на сервер, но не все.

Теперь мой главный вопрос: Как я могу убедиться, что клиент не прекращает выполнение до того, как все сообщения были отправлены?
У меня уже есть некоторые идеи, но я не знаю, какое будет лучшее решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...