我正在尝试在 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);
我正在做的事情是否存在本质上的错误,或者我是否需要对图像做一些不同的事情?
编辑:我已经更改它以反射(reflect)当前代码,而且,在对两端的原始字节进行转储之后,看起来由于某种原因,字节在通过网络传输时正在重新排列。有什么方法可以确保字节以原始顺序出现吗?
最佳答案
在 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
关于c# - 通过 ssl 套接字流式传输图像未正确显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8086790/