ssl套接字上的流图像无法正确传输

本文关键字:传输 图像 套接字 ssl | 更新日期: 2023-09-27 18:14:13

我试图在2个设备之间安全地传输文件,所以我使用附加到TcpClient的SslStream。文档和文本文件可以正常显示,但图像文件不能正确显示。以下是服务器代码:

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);

我正在做的事情是否有任何内在的错误,或者我是否需要为图像做一些不同的事情?

编辑:我已经改变了它,以反映当前的代码,而且,在两端做原始字节的转储后,看起来像由于某种原因,当它们通过电线时,字节正在重新排列。是否有任何方法可以确保字节以原始顺序传递?

ssl套接字上的流图像无法正确传输

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

这可能是端序冲突吗?如果来自服务器的字节是ABCDEF,而客户端看到的图像字节是BADCFE,那么这就是问题所在。

我还没有处理过图像文件,但是当我从传入的字节中读取一个短或整型而不是字符串时,我会这样做:

int intFromStream = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(byteArrayWithLength4, 0));