Представление отправленных и полученных сообщений чата в «порядке» как для клиента, так и для сервера - PullRequest
2 голосов
/ 28 ноября 2010

У меня есть простой (очень простой :)) клиент и сервер, который может отправлять текстовые сообщения через TCP. Это некорректно, потому что я не знаю, как слушать сообщения и печатать их на экране, а также отправлять сообщения на одновременно (как для клиента, так и для сервера).

Также мне сложно представить все отправленные и полученные сообщения между клиентом и сервером в порядке отправки сообщений .

Например, на стороне server чат может выглядеть следующим образом

Server:Hi there
Client:Hi

А на стороне клиента тот же чат выглядит так

Client:Hi
Server:Hi there

Сообщения расположены в другом порядке, и оба пользователя видят их по-разному. Мой главный вопрос , как мне синхронизировать вывод, чтобы они оба видели одно и то же?

Помня о том, что я упоминал ранее о том, что не знаю, как слушать и отправлять одновременно, это цикл сообщений для сервера и клиента.

Цикл сообщений сервера

    while(true){
        cout<<"-[SERVER]: ";
        getline(cin,send_text);
        if (sizeof(send_text) > 0 ){
            bytes_out = send(client,send_text.c_str(),send_text.length()+1,0);
            cout<< endl;
            if (bytes_out == SOCKET_ERROR){
                cout<<"-[SERVER error in sending.]" << endl;
                break;
            }
        }

        bytes_in = recv(client,recvd_text,sizeof(recvd_text),0);
        if (bytes_in > 0 ){
            cout<<"-[CLIENT]: " << recvd_text << endl;  //output on screen
        }
        if (bytes_in == 0){
            cout<<"-[CLIENT has disconnected.]" << endl;
            break;
        }
        if (bytes_in == SOCKET_ERROR){
            cout<<"-[CLIENT closed unexpectedly.]" << endl;
            break;
        }
    }

Цикл сообщений клиента

    while (true){
        cout<<"-[CLIENT]: ";
        getline(cin,send_text);
        if(sizeof(send_text) > 0){
            bytes_out = send(con_sock,send_text.c_str(),send_text.length()+1,0);
            if (bytes_out == SOCKET_ERROR){
                cout<<"-[CLIENT error in sending.]" << endl;
                break;
            }
        }

        bytes_in = recv(con_sock,recvd_text,sizeof(recvd_text),0);
        if (bytes_in > 0){
            cout<<"-[SERVER]: " << recvd_text << endl;
        }
        if (bytes_in == 0){
            cout<<"-[Server has disconnected." << endl;
            break;
        }
        if (bytes_in == SOCKET_ERROR){
            cout<<"-[Server closed unexpectedly." << endl;
            break;
        }
    }
    return true;

Ответы [ 2 ]

1 голос
/ 28 ноября 2010

Основная проблема заключается в том, как ждать входящие сообщения и одновременно вводить данные пользователем. (Как только вы сможете это сделать, «синхронизация» будет происходить естественным образом, поскольку сообщения будут отображаться по мере их отправки или получения).

Решением этой проблемы является использование select. select может ожидать ввода на нескольких файловых дескрипторах (например, стандартный ввод и сокет) и возвращаться при наличии данных. Затем вы можете обработать данные: если они из сокета, отобразите их. Если это от пользователя, отправьте его на удаленный хост.

Вот пример программы клиент / сервер чата с использованием select. (Пример на Python, а не на C ++, но принцип тот же).


Windows-конкретные

В Windows select() предоставляется библиотекой Winsock и работает только с сокетами. Чтобы ожидать ввода от консоли и от сетевого сокета, похоже, вам нужно будет использовать комбинацию WaitForMultipleObjects, GetStdHandle и WSAEventSelect. В Unix-подобных средах это намного проще, потому что стандартный ввод и сокеты являются дескрипторами файлов.

Более простым решением в Windows будет решение, основанное на передаче сообщений. Используйте окно для ввода текста и используйте WSAAsyncSelect, чтобы получить сообщение, когда сетевой ввод будет готов.

0 голосов
/ 28 ноября 2010

В некотором смысле, это вопрос об интернет-протоколах. Большинство прикладных протоколов решают эту проблему, включая своего рода ответ подтверждения, когда сообщение успешно достигает своего определения. Такое сообщение может выглядеть примерно так:

  1. Сервер отправляет какой-то заголовок, идентифицирующий сообщение чата, с содержанием «Привет!».
  2. Клиент получает сообщение чата и отвечает с другим заголовком, указывающим подтверждение.
  3. Сервер получает подтверждение клиента, а затем выводит сообщение на экран.

Технически операционная система уже делает это как часть TCP, но это, вероятно, самый простой способ добиться чего-то подобного на уровне приложений.

...