Байты, которые получает моя серверная программа, являются неполными. Зачем? Я использую сокеты C # .net - PullRequest
1 голос
/ 16 февраля 2012

Это не всегда происходит. Но это случается чаще, чем получение байтов полностью.

Вот как моя клиентская прога отправляет байты на мою серверную прогу:

public void sendBytes()
{
    FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    TcpClient cli = tcpServer; //tcpServer is a global TcpClient variable I use to connect to the server. 
    NetworkStream ns = cli.GetStream();

    CopyStreamToStream(fs, ns, null);
    ns.Flush();
}

public static void CopyStreamToStream(Stream source, Stream destination, Action<Stream, Stream, Exception> completed)
{
    byte[] buffer = new byte[0x1000];
    int read;

    while ((read = source.Read(buffer, 0, buffer.Length)) > 0) // <- client loop
        destination.Write(buffer, 0, read);
}

Вот как моя серверная программа получает байты от моей клиентской программы:

FileStream ms = new FileStream(tmpFile, FileMode.Create, FileAccess.Write);
do
{
    int szToRead = s.Available; //s is a socket
    byte[] buffer = new byte[szToRead];

    int szRead = s.Receive(buffer, szToRead, SocketFlags.None);
    if (szRead > 0)
        ms.Write(buffer, 0, szRead);            
}
while(s.Available != 0); //i also tried ms.length < size_of_file_to_be_received_in_bytes

Я вошел в программу и посмотрел значения, и я не знаю, что вызывает нехватку полученных байтов. Я не знаю, связана ли проблема с прогой клиента или прогой сервера.

Я не знаю, относится ли это к делу, но когда я попытался войти в цикл клиента (чтобы посмотреть значение fs.length и проверить, будет ли оно получено на сервере), все 4 попытки отправить файл с клиента на сервер успешно. но когда я не наблюдал за циклом клиента, а только смотрел приложение сервера (чтобы увидеть значение ms.length), только 1 из 4 попыток отправить файл на сервер увенчался успехом. при 3 неудачных попытках ms.length меньше байтов исходного файла (я проверил это в свойстве файла).

Это , где я основал это из

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

В исходном коде (с веб-сайта, на котором я основывал свою программу) цикл имеет другое условие:

FileStream ms = new FileStream(tmpFile, FileMode.Create, FileAccess.Write);
do
{
    int szToRead = s.Available; //s is a socket
    byte[] buffer = new byte[szToRead];

    int szRead = s.Receive(buffer, szToRead, SocketFlags.None);
    if (szRead > 0)
        ms.Write(buffer, 0, szRead);            
}
while(SocketConnected(s)); // <--- i changed this in my program

private static bool SocketConnected(Socket s)
{
    return !(s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0));
}

Я думаю, что SocketConnected проверяет, подключен ли сокет, потому что оригинальный код для клиентской программы был таким:

CopyStreamToStream(fs, ns, null);
ns.Flush();
ns.Close();

Я удалил ns.Close () из программы, потому что я хочу поддерживать соединение клиентского приложения с сервером. Поэтому я хочу иметь возможность проверить, закончил ли я чтение всех байтов, поступающих из клиентского приложения, не закрывая сокетное соединение со стороны клиента.

1 Ответ

4 голосов
/ 16 февраля 2012

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

В хорошем приближении каждое отдельное использование Доступного является ошибкой!

Удалить все использования Доступного.Вместо этого всегда пытайтесь прочитать полный буфер.Если вы получаете 0, это означает, что сокет был закрыт и все готово.

Редактировать: Вот некоторый канонический код чтения:

var buffer = new byte[8192];
while(true) {
 var readCount = stream.Read(buffer, 0, buffer.Length);
 if (readCount == 0) break;
 outputStream.Write(buffer, 0, readCount);
}
...