Отправить серверу несколько сообщений?C # - PullRequest
0 голосов
/ 23 сентября 2011

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

Ошибка, которую я получаю: IOException был обработан. Невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным хостом.

Вот мой код на стороне сервера:

приватная статическая пустота HandleClientComm (объект-клиент) { / ** создание списка, который содержит объекты DatabaseFile ** / List theDatabase = new List ();

        TcpClient tcpClient = (TcpClient)client;
        NetworkStream clientStream = tcpClient.GetStream();

        byte[] message = new byte[4096];
        int bytesRead;

        do
        {
            bytesRead = 0;

            try
            {
                // Blocks until a client sends a message                    
                bytesRead = clientStream.Read(message, 0, 4096);
            }
            catch (Exception)
            {
                // A socket error has occured
                break;
            }

            if (bytesRead == 0)
            {
                // The client has disconnected from the server
                break;
            }

            // Message has successfully been received
            ASCIIEncoding encoder = new ASCIIEncoding();

            Console.WriteLine("To: " + tcpClient.Client.LocalEndPoint);
            Console.WriteLine("From: " + tcpClient.Client.RemoteEndPoint);
            Console.WriteLine(encoder.GetString(message, 0, bytesRead));


            if (encoder.GetString(message, 0, bytesRead) == "OptionOneInsert")
            {
                byte[] message2 = new byte[4096];
                int bytesRead2 = 0;

                **bytesRead2 = clientStream.Read(message, 0, 4096);** //ERROR occurs here!

                Console.WriteLine("Attempting to go inside insert)");
                Menu.Insert(theDatabase, bytesRead2); 
            }

Вот мой код клиента:

        ASCIIEncoding encoder = new ASCIIEncoding();
        byte[] buffer = encoder.GetBytes("OptionOneInsert");

        Console.ReadLine(); 
        clientStream.Write(buffer, 0, buffer.Length);
        clientStream.Flush();

        NetworkStream clientStream2 = client.GetStream();
        String text = System.IO.File.ReadAllText("FirstNames.txt");
        clientStream2.Write(buffer, 0, buffer.Length);
        clientStream2.Flush();
        ASCIIEncoding encoder2 = new ASCIIEncoding();

        byte[] buffer2 = encoder2.GetBytes(text);
        Console.WriteLine("buffer is filled with content"); 
        Console.ReadLine();

Когда клиент отправляет сообщение «optionOne», оно очень хорошо принимается сервером. Проблемы возникают только тогда, когда я пытаюсь отправить строку с именем «текст»!

Любая помощь будет принята с благодарностью - я не очень знаком с сокетами, поэтому я пытался понять это некоторое время

1 Ответ

3 голосов
/ 23 сентября 2011

У вас есть проблема big - нет ничего, чтобы указать конец одного сообщения и начало другого. Вполне возможно, что сервер получит два сообщения за один раз или половину сообщения, а затем другую половину.

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

  • Кодирование его из строки в байты (в идеале, используя UTF-8 вместо ASCII, если вы не уверены, что никогда не понадобится текст не-ASCII)
  • Запишите длину байтового массива в виде четырехбайтового значения
  • Выпишите содержание

На сервере:

  • Чтение четырех байтов (при необходимости зацикливание - нет гарантии, что вы даже прочитаете эти четыре байта вместе, хотя вы почти наверняка это сделаете)
  • Преобразовать четыре байта в целое число
  • Выделить байтовый массив такого размера
  • Цикл, чтение от "текущей позиции" до конца буфера, пока вы не заполните буфер
  • Преобразовать буфер в строку

Другой альтернативой является простое использование BinaryReader и BinaryWriter - ReadString и WriteString используют префикс длины, по общему признанию в немного другой форме.

Еще одна альтернатива, которую вы могли бы использовать, - это иметь разделитель (например, возврат каретки), но это означает, что вам нужно добавить экранирование, если вам когда-нибудь понадобится включить разделитель в текст для передачи.

...