Отправка файла изображения с использованием сокета в C # (большие данные) - PullRequest
2 голосов
/ 18 июня 2011

Я хочу отправить большие данные (изображение) ок. 1MB файл через сокетное соединение

Вопрос 1

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

 NetworkStream serverStream = clientSocket.GetStream();
    byte[] outStream = System.Text.Encoding.ASCII.GetBytes(richTextBox1.Text+"$");
    serverStream.Write(outStream, 0, outStream.Length);
    serverStream.Flush();

Вопрос 2 : Какие изменения потребовались как в сокет-клиенте, так и на сервере для отправки и получения больших файлов?

Ответы [ 3 ]

3 голосов
/ 18 июня 2011

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

Отправляющая сторона будет примерно такой:

const int bufsize = 8192;

var buffer = new byte[bufsize];
NetworkStream ns = socket.GetStream();

using (var s = File.OpenRead("path"))
{
    int actuallyRead;
    while ((actuallyRead = s.Read(buffer, 0, bufsize)) > 0)
    {
        ns.Write(buffer, 0, actuallyRead);
    }
}
ns.Flush();

Принимающий сайт просто симметричен.

2 голосов
/ 19 июня 2011

Если все, что вы хотите сделать, это отправить изображение, и вам не нужны метаданные, вы можете использовать такой код:

Сервер:

var listener = new TcpListener(address, port);
listener.Start();

using (var incoming = listener.AcceptTcpClient())
using (var networkStream = incoming.GetStream())
using (var fileStream = File.OpenWrite(imagePath))
{
    networkStream.CopyTo(fileStream);
}

listener.Stop();

Клиент:

var client = new TcpClient();
client.Connect(address, port);

using (var networkStream = client.GetStream())
using (var fileStream = File.OpenRead(imagePath))
{
    fileStream.CopyTo(networkStream);
}

client.Close();

Если вы хотите сжать файл, вы можете использовать GZipStream.

Этот код используетCopyTo() метод, который доступен в .Net 4, но вы можете написать его самостоятельно в более ранних версиях.

2 голосов
/ 18 июня 2011

Сокету не важно, отправляете ли вы текстовые или двоичные данные. Или сколько вы отправляете. Если есть какие-либо проблемы, то это на принимающей стороне, код, который вы не опубликовали. Классическая ошибка - забыть, что NetworkStream - это поток , а не последовательность пакетов. Вызов Read () на принимающей стороне может вернуть любое количество байтов. Это не будет количество байтов, которое вы записали в вызове Write (), в зависимости от того, как маршрутизаторы между двумя машинами разбили IP-пакеты и сколько данных буферизировалось в приемнике. Вы, вероятно, сойдете с вызовом Read only один раз, потому что строка короткая. Это определенно не сработает, когда вы отправляете много данных.

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

Вы можете произвольно расширить этот протокол, скажем, отправив имя файла. Etcetera. Хотя к тому времени, как вы закончите, вы будете близки к переизобретению FTP.

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