Потоковое изображение через ssl-сокет неправильно отображается - PullRequest
0 голосов
/ 11 ноября 2011

Я пытаюсь безопасно передавать файлы между двумя устройствами, поэтому я использую SslStream, подключенный к TcpClient.Документы и текстовые файлы встречаются очень хорошо, но файлы изображений не отображаются правильно.Ниже приведен код сервера:

listener = new TcpListener(IPAddress.Any, 1337);
listener.Start();

while (true)
{
    TcpClient client = listener.AcceptTcpClient();

    SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidationCallback), new LocalCertificateSelectionCallback(CertificateSelectionCallback));
    var certificate = Connection.GetClientCertificate(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
    try
    {
        sslStream.AuthenticateAsServer(certificate, true, SslProtocols.Default, true);

        sslStream.ReadTimeout = 5000;
        sslStream.WriteTimeout = 5000;

        var messageData = ReadMessage(sslStream);

        var mode = messageData[0];
        var tokenBytes = messageData.Splice(1, 16);
        var fileNameBytes = messageData.Splice(17, 128);
        var fileBytes = messageData.Splice(146);

        var fileName = Encoding.ASCII.GetString(fileNameBytes).TrimEnd('\0');
        using (var tempFile = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write))
        {
            tempFile.Write(fileBytes, 0, fileBytes.Length);
            tempFile.Flush();
        }

        if (mode == 0)
            tempFiles.Add(fileName);

        Process.Start(fileName);
    }
    catch (AuthenticationException e)
    {
        MessageBox.Show("The other side failed to authenticate.");
    }
    finally
    {
        sslStream.Close();
        client.Close();
    }
}

И ReadMessage определяется следующим образом:

private static byte[] ReadMessage(SslStream sslStream)
{
    byte[] buffer = new byte[2048];
    MemoryStream stream = new MemoryStream();
    int bytes = -1;
    while (bytes != 0)
    {
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        stream.Write(buffer, 0, bytes);
    }
    return stream.ToArray();
}

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

TcpClient client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Parse(ip), 1337));

SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidationCallback), new LocalCertificateSelectionCallback(CertificateSelectionCallback));
var certificate = Connection.GetClientCertificate(ip);
try
{
    sslStream.AuthenticateAsClient(ip, new X509CertificateCollection() { certificate }, SslProtocols.Default, false);

    sslStream.ReadTimeout = 5000;
    sslStream.WriteTimeout = 5000;
    sslStream.Write(data);
}
catch (AuthenticationException e)
{
    MessageBox.Show("The other side failed to authenticate.");
}
finally
{
    sslStream.Close();
    client.Close();
}

Икод, который вызывает его, просто делает:

var fileBytes = File.ReadAllBytes(file);
var tokenBytes = Encoding.UTF8.GetBytes(token);
var fileNameBytes = Encoding.UTF8.GetBytes(Path.GetFileName(file));

var buffer = new byte[145 + fileBytes.Length];
buffer[0] = 1;
for (int i = 0; i < 16; i++)
{
    buffer[i + 1] = tokenBytes[i];
}

for (int i = 0; i < fileNameBytes.Length; i++)
{
    buffer[i + 17] = fileNameBytes[i];
}

for (int i = 0; i < fileBytes.Length; i++)
{
    buffer[i + 145] = fileBytes[i];
}

SocketConnection.Send(ip, buffer);

Что-то не так с тем, что я делаю, или мне нужно сделать что-то другое для изображений?

РЕДАКТИРОВАТЬ: я изменил его, чтобы отразить текущий код, а также, после выполнения дампа необработанных байтов на обоих концах, похоже, что по какой-то причине байты переставляются, когда они приходят по проводам,Есть ли способ убедиться, что байты попадают в исходный порядок?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2015

Возможно ли это конфликт между порядком байтов?Если байтами с сервера являются ABCDEF и клиент видит байты изображения как BADCFE, то это проблема.

Я не работал с файлами изображений, но когда я читаю short или int вместо String из байтов, поступающих по проводам, я делаю что-то вроде этого:

int intFromStream = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(byteArrayWithLength4, 0));
0 голосов
/ 11 ноября 2011

В ReadMessage вы записываете bytes.Length байтов в поток независимо от количества фактически прочитанных байтов.Попробуйте:

private static byte[] ReadMessage(SslStream sslStream)
{
    byte[] buffer = new byte[2048];
    MemoryStream stream = new MemoryStream();
    int bytes = -1;
    while (bytes != 0)
    {
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        // Use "bytes" instead of "buffer.Length" here
        stream.Write(buffer, 0, bytes);
    }
    return stream.ToArray();
}

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

Ваш код должен быть:

var fileBytes = messageData.Splice(145); // File data starts at 145, not 146
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...