C # клиент / сервер Вопрос - PullRequest
       27

C # клиент / сервер Вопрос

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

Я невероятно смущен тем, что здесь происходит. Я ставил точки разрыва и просто не могу понять. В основном у меня есть клиент и сервер. Я хочу, чтобы клиент отправил две отдельные строки данных. После установки точек останова я заметил, что мой клиент фактически заполняет обе строки соответствующими данными. Однако сервер никогда не видит вторую строку. Почему это происходит и как мне это исправить? Любая помощь будет очень признательна! Ниже мой код:

Сервер:

    private static void HandleClientComm(object client)
    {
        /** creating a list which contains DatabaseFile objects **/
        List<DatabaseFile> theDatabase = new List<DatabaseFile>();

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

        StringBuilder response = new StringBuilder();
        byte[] message = new byte[4096];
        int bytesRead;

        do
        {
            bytesRead = 0;

            try
            {
                /*do
                {
                    bytesRead = clientStream.Read(message, 0, message.Length);
                    response.Append(Encoding.ASCII.GetString(message, 0, bytesRead));
                } while (clientStream.DataAvailable);*/

когда я изменяю этот закомментированный код на bytesRead = clientStream.Read (message, 0, 4096); я получаю ошибку IOException, которая выглядит следующим образом: Невозможно записать данные в транспортное соединение : Существующее соединение было принудительно закрыто удаленным хостом. Следовательно, я изменил его на цикл do while. Как мне обойти это IOException и принять вторую строку?

                ASCIIEncoding encoder = new ASCIIEncoding();
                String file = encoder.GetString(message, 0, bytesRead);
                Menu.Insert(theDatabase, file); 
            }
            catch (Exception)
            {
                // A socket error has occured
                break;
            }

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

        // Release connections
        clientStream.Close();
        tcpClient.Close();
    }

Клиент:

    static void Main(string[] args)
    {
        TcpClient client = new TcpClient();

        IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);

        client.Connect(serverEndPoint);

        NetworkStream clientStream = client.GetStream();
        NetworkStream clientStream2 = client.GetStream();

        ASCIIEncoding encoder = new ASCIIEncoding();
        ASCIIEncoding encoder2 = new ASCIIEncoding();
        String text = System.IO.File.ReadAllText("FirstNames.txt");
        String text2 = System.IO.File.ReadAllText("LastNames.txt");

        byte[] buffer = encoder.GetBytes(text);

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

        byte[] buffer2 = encoder2.GetBytes(text2);

        clientStream2.Write(buffer2, 0, buffer2.Length);
        clientStream2.Flush();
        Console.ReadLine(); 
    }
}

Ответы [ 3 ]

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

потому что while (clientStream.DataAvailable) больше не соответствует действительности после вашего первого клиентского вызова.

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

Связь между клиентом и сервером происходит следующим образом (обратите внимание, что порядок шагов только для иллюстрации, фактический порядок во время выполнения может отличаться):

  1. Клиент: client.Connect(serverEndPoint)
    Сервер: HandleClientComm(newClient)

  2. Клиент: clientStream.Write(buffer, 0, buffer.Length)
    Сервер: bytesRead = clientStream.Read(message, 0, message.Length)
    Обратите внимание, что Read не гарантирует прочтение всего сообщения. Вполне нормально вернуть только часть, которая была получена до сих пор

  3. Клиент: Console.ReadLine()
    Сервер: while (clientStream.DataAvailable)
    В потоке нет данных - клиент не отправил никаких данных. Это может произойти даже без ReadLine - есть время, прежде чем клиент снова отправит данные

  4. Сервер: tcpClient.Close()

  5. Клиент: clientStream2.Write(buffer2, 0, buffer2.Length)
    Вы можете получить исключение здесь или нет - в зависимости от того, сервер уже закрыл соединение, в любом случае сервер больше не читает.

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

Клиент:

using (var client = new TcpClient("localhost", 8888))
using (var clientStream = client.GetStream())
{
    var buffer = Encoding.ASCII.GetBytes( File.ReadAllText("FirstNames.txt") );
    clientStream.Write(buffer, 0, buffer.Length);

    buffer = Encoding.ASCII.GetBytes( File.ReadAllText("LastNames.txt") );
    clientStream.Write(buffer, 0, buffer.Length);
}

Сервер:

using (var tcpClient = (TcpClient)client)
using (var clientStream = tcpClient.GetStream())
{
    // Store everything that the client sends.
    // This will work if the client closes the connection gracefully
    // after sending everything

    var receivedData = new MemoryStream();
    clientStream.CopyTo(receivedData);

    var rawBytes = receivedData.ToArray();
    var file = Encoding.ASCII.GetString(rawBytes, 0, rawBytes.Length);

    Menu.Insert(theDatabase, file);
}

Протокол прост, и может быть достаточно для вашего случая. Однако есть проблемы с ним, которые должны быть устранены в рабочем коде (например, что если клиент отправляет слишком много данных, исчерпывает память сервера, что если клиент прекращает отправку без закрытия соединения и т. Д.)

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

Вы выходите из цикла client-recv на своем сервере только потому, что DatAvailable имеет значение false. Это означает, что если бы клиент отправил кадр данных (который вы потребляете) и сделал паузу, тогда ваш сервер не увидел бы доступных данных в этот момент и отключился бы, даже если через доли секунды другой кадр данных от клиента был готов прийти в. Почти всегда конец диалога основан на содержании передаваемых данных. Вы, конечно, никогда не можете полагаться на тот факт, что DataAvailable однажды оказывается ложным.

В качестве продолжения, если вы предоставите больше информации об используемом протоколе, мы можем оказать вам дополнительную помощь. Например, если протокол является тем, что две строки отправляются с CR / LF в конце, то серверный цикл должен проверять буфер, чтобы узнать, когда следует отключиться.

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