如何修复 win socket 中损坏的 byte[]-s
How to fix corrupt byte[]-s in win socket
我有两个 win 套接字应用程序,服务器和客户端。服务器应用程序在我的虚拟机上,客户端在主机上,通信正常。我正在通过该套接字发送一个 ISO 文件 (700MB),我遇到了接收到的字节已损坏的错误。当我的文件来到虚拟机时,它具有原始大小,但内容不正确。在 客户端 端,我正在使用此代码:
public class ProgramClient
{
public static void StartClient()
{
// Data buffer for incoming data.
byte[] msg;
try
{
IPAddress ipAd = IPAddress.Parse("192.168.137.71");
IPEndPoint remoteEP = new IPEndPoint(ipAd, 1234);
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Connect(remoteEP);
Console.WriteLine("Client connected to {0}", sender.RemoteEndPoint.ToString());
Console.WriteLine("Sending file...");
msg = GetBinaryFile(@"C:\TCPIP\test_big.iso");
byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
int msgLength = BitConverter.ToInt32(msgLengthBytes, 0);
Console.WriteLine("int: {0}", msgLength);
Console.WriteLine("msgL size: {0}", msgLengthBytes.Length);
//join arrays, file size info, TCP header
byte[] result = new byte[msgLengthBytes.Length + msgLength];
Buffer.BlockCopy(msgLengthBytes, 0, result, 0, msgLengthBytes.Length);
Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);
//file extension info, TCP Header
byte extension = 2; //file extension code
byte[] newArray = new byte[result.Length + 1];
result.CopyTo(newArray, 1);
newArray[0] = extension;
result = newArray;
int bytesSent = sender.Send(result);
Console.WriteLine("result size: {0}", result.Length);
sender.Shutdown(SocketShutdown.Both);
sender.Close();
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
private static byte[] GetBinaryFile(string filename)
{
byte[] bytes;
using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
return bytes;
}
public static void Main(String[] args)
{
StartClient();
}
}
在服务器端我有以下代码:
class ProgramServer
{
public static void Main(String[] args)
{
try
{
StartListening();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
public static void StartListening()
{
byte[] bytes = new Byte[1024];
while (true)
{
string outputPath = string.Empty;
outputPath = @"C:\output\output";
Console.WriteLine("Waiting for a connection...");
Socket handler = SocketInstance().Accept();
data = null;
//for the TCP header, get file extension
bytes = new byte[1];
int bytesReceivedExtension = handler.Receive(bytes);
string extension = GetExtension(bytes[0]);
outputPath = outputPath + extension;
//for the TCP header, get file size information
bytes = new byte[4];
int bytesReceived = handler.Receive(bytes);
int Lenght = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("msg length: " + Lenght);
int TotalReceivedBytes = 0;
while (TotalReceivedBytes < Lenght)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes);
}
Console.WriteLine("Bytes received total: " + TotalReceivedBytes);
Console.WriteLine(File.Exists(outputPath) ? "File received." : "File not received.");
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
private static Socket SocketInstance()
{
IPAddress ipAd = IPAddress.Parse("192.168.137.71");
IPEndPoint localEndPoint = new IPEndPoint(ipAd, 1234);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(10);
return listener;
}
public static void AppendAllBytes(string path, byte[] bytes)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bytes.Length);
}
}
public static string GetExtension(byte extOfFile)
{
switch (extOfFile)
{
case 0:
return ".txt";
case 1:
return ".png";
case 2:
return ".iso";
default:
return "";
}
}
}
那么,我怎样才能确定我的byte[]没问题呢?因为当我在接收方打开那个ISO文件时,它的内容是不正确的。是否有任何类型的文件到二进制转换的替代方法?
谢谢
你编写的框架协议似乎是这样工作的:
0 1 2 3 4 ... N
[L][L][L][L][D][...][D]
其中 L
表示一个 32 位整数(采用哪种字节顺序?)表示 D
ata 的长度。
首先,您发送的文件长度有误:
byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
为什么减去3?你不应该。这会导致文件的最后 3 个字节被截断。
然后在填充消息缓冲区时,从字节 3 或 L
的最后一个字节开始写入:
Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);
这将导致 reader 解释不正确的数据长度。您应该从字节 4 开始。
第三,写入文件时,不应该追加整个缓冲区,而应该只追加Receive()
实际写入缓冲区的字节:
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes, bytesRec);
然后在那个方法中:
public static void AppendAllBytes(string path, byte[] bytes, int bufferLength)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bufferLength);
}
}
这就是为什么如果您不太清楚自己在做什么,就不应该编写自己的协议和套接字代码。而是利用现有的协议和库。
我有两个 win 套接字应用程序,服务器和客户端。服务器应用程序在我的虚拟机上,客户端在主机上,通信正常。我正在通过该套接字发送一个 ISO 文件 (700MB),我遇到了接收到的字节已损坏的错误。当我的文件来到虚拟机时,它具有原始大小,但内容不正确。在 客户端 端,我正在使用此代码:
public class ProgramClient
{
public static void StartClient()
{
// Data buffer for incoming data.
byte[] msg;
try
{
IPAddress ipAd = IPAddress.Parse("192.168.137.71");
IPEndPoint remoteEP = new IPEndPoint(ipAd, 1234);
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Connect(remoteEP);
Console.WriteLine("Client connected to {0}", sender.RemoteEndPoint.ToString());
Console.WriteLine("Sending file...");
msg = GetBinaryFile(@"C:\TCPIP\test_big.iso");
byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
int msgLength = BitConverter.ToInt32(msgLengthBytes, 0);
Console.WriteLine("int: {0}", msgLength);
Console.WriteLine("msgL size: {0}", msgLengthBytes.Length);
//join arrays, file size info, TCP header
byte[] result = new byte[msgLengthBytes.Length + msgLength];
Buffer.BlockCopy(msgLengthBytes, 0, result, 0, msgLengthBytes.Length);
Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);
//file extension info, TCP Header
byte extension = 2; //file extension code
byte[] newArray = new byte[result.Length + 1];
result.CopyTo(newArray, 1);
newArray[0] = extension;
result = newArray;
int bytesSent = sender.Send(result);
Console.WriteLine("result size: {0}", result.Length);
sender.Shutdown(SocketShutdown.Both);
sender.Close();
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
private static byte[] GetBinaryFile(string filename)
{
byte[] bytes;
using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
return bytes;
}
public static void Main(String[] args)
{
StartClient();
}
}
在服务器端我有以下代码:
class ProgramServer
{
public static void Main(String[] args)
{
try
{
StartListening();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
public static void StartListening()
{
byte[] bytes = new Byte[1024];
while (true)
{
string outputPath = string.Empty;
outputPath = @"C:\output\output";
Console.WriteLine("Waiting for a connection...");
Socket handler = SocketInstance().Accept();
data = null;
//for the TCP header, get file extension
bytes = new byte[1];
int bytesReceivedExtension = handler.Receive(bytes);
string extension = GetExtension(bytes[0]);
outputPath = outputPath + extension;
//for the TCP header, get file size information
bytes = new byte[4];
int bytesReceived = handler.Receive(bytes);
int Lenght = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("msg length: " + Lenght);
int TotalReceivedBytes = 0;
while (TotalReceivedBytes < Lenght)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes);
}
Console.WriteLine("Bytes received total: " + TotalReceivedBytes);
Console.WriteLine(File.Exists(outputPath) ? "File received." : "File not received.");
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
private static Socket SocketInstance()
{
IPAddress ipAd = IPAddress.Parse("192.168.137.71");
IPEndPoint localEndPoint = new IPEndPoint(ipAd, 1234);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(10);
return listener;
}
public static void AppendAllBytes(string path, byte[] bytes)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bytes.Length);
}
}
public static string GetExtension(byte extOfFile)
{
switch (extOfFile)
{
case 0:
return ".txt";
case 1:
return ".png";
case 2:
return ".iso";
default:
return "";
}
}
}
那么,我怎样才能确定我的byte[]没问题呢?因为当我在接收方打开那个ISO文件时,它的内容是不正确的。是否有任何类型的文件到二进制转换的替代方法? 谢谢
你编写的框架协议似乎是这样工作的:
0 1 2 3 4 ... N
[L][L][L][L][D][...][D]
其中 L
表示一个 32 位整数(采用哪种字节顺序?)表示 D
ata 的长度。
首先,您发送的文件长度有误:
byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
为什么减去3?你不应该。这会导致文件的最后 3 个字节被截断。
然后在填充消息缓冲区时,从字节 3 或 L
的最后一个字节开始写入:
Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);
这将导致 reader 解释不正确的数据长度。您应该从字节 4 开始。
第三,写入文件时,不应该追加整个缓冲区,而应该只追加Receive()
实际写入缓冲区的字节:
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes, bytesRec);
然后在那个方法中:
public static void AppendAllBytes(string path, byte[] bytes, int bufferLength)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bufferLength);
}
}
这就是为什么如果您不太清楚自己在做什么,就不应该编写自己的协议和套接字代码。而是利用现有的协议和库。