Отправка сообщений и файлов через NetworkStream - PullRequest
0 голосов
/ 18 августа 2011

Я новичок в сетевом программировании, и у меня есть несколько вопросов по поводу этого кода:

    if (client.Connected)
            {
                ChangeLabel("Mit dem Server verbunden...");


                NetworkStream stream = client.GetStream();
                FileStream fs = null;
                try
                {
                    fs = new FileStream("Mapeditor2.exe", FileMode.Create);
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                    Environment.Exit(0);
                }

                byte[] bResponse = new byte[16];
                stream.Read(bResponse, 0, 16);
                string sResponse = System.Text.Encoding.UTF8.GetString(bResponse);
                int NoOfPackets = Convert.ToInt32(sResponse);
                float progress = 0;
                float progressPercent = 100.0f / (float)NoOfPackets;

                byte[] buffer = new byte[128];                    
                int bytesRead;

                for (int i = 0; i < NoOfPackets; i++)
                {
                    bytesRead = stream.Read(buffer, 0, 128);
                    fs.Write(buffer, 0, bytesRead);
                    progress += progressPercent;
                    ChangeProgress((int)progress);
                }
                fs.Close();
                stream.Close();
            }

(Клиент - это TcpClient, соединение с сервером)

Теперь я пытаюсь сделать обновление для моего редактора карт, как вы можете видеть. Сначала я отправляю 16-байтовое сообщение, содержащее количество пакетов, которые будут отправлены впоследствии (файл Mapeditor.exe!), Это для индикатора выполнения клиента ...

Есть ли динамический способ сделать это? (не произносить «прочитать 16-байтовый массив» и динамически записывать текст и файлы в поток, когда клиент автоматически знает, когда ему нужно читать текст, а когда файлы)

Надеюсь, так или есть какой-то другой способ написания обновлений / патчеров? Как разработчики игр делают это?

Спасибо!

PS: Есть ли способ убедиться, что клиент получает ВСЕ пакеты, и если некоторые потерялись, только отправьте их и сложите вместе?

1 Ответ

2 голосов
/ 18 августа 2011

Если вы используете TCP, протокол заботится о порядке, ретрансляции и т. Д.

Что касается отправки / получения данных динамически, вы можете использовать префиксный протокол, в котором вы сначала отправляете номер (например,int - 4 байта), который представляет длину сообщения, которое должно прибыть.После этого вы отправляете оставшуюся часть сообщения.

Получатель ожидает 4 байта, затем преобразует их в целое число и ожидает такого количества байтов.Этот процесс повторяется снова и снова.

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

// lengthBytes.Length = 4 bytes, which is sizeof(int)
byte[] lengthBytes = BitConverter.GetBytes(anInt);

конец и затем отправить его по проводам.

Затем, на принимающей стороне, в вашем коде вам нравится:

byte[] msgLengthBytes = new byte[sizeof(int)]; // or hardcode 4 here, I'm a generalization junkie
stream.Read(msgLengthBytes, 0, msgLengthBytes.Length);
int msgLength = BitConverter.GetInt32(msgLengthBytes, 0);

Кроме того, вместо того, для которого предполагается, что каждый раз, когда вы читаете из потока, вы читаете именно то количество байтов, которое вы ожидаете, вы должны использовать что-то вроде этого:

int transfered = 0;
while (transfered < msgLength)
{
    bytesRead = stream.Read(buffer, 0, buffer.Length);
    fs.Write(buffer, 0, bytesRead);

    transfered += bytesRead;

    progress += (bytesRead / msgLength) * 100;
    ChangeProgress(progress); // You can't use int here anymore, use Math to round or something, for your progress bar
}

Кроме того, в моем фрагменте возможно, что при последней операции приема вы прочитаете такую ​​сумму, как: transfered + bytesRead> msgLengh, если вы отправляете данные непрерывно в потоке.Вы также должны позаботиться об этом.

Во всяком случае, если бы я был вами и потому, что вам нужен какой-то уведомитель о прогрессе, я бы использовал поток с асинхронной BeginRead ().

Я только что дал вам идею, вы можете настроить ее по своему желанию.

...