I currently need to send big data (such as images) from a client(C#) to a server (C#). There is no problem with sending and receiving the string data via NetworkStream. But when sending large data (images) will get an error result (loss data or image crash). Any idea?
client image output before sending (test_send.jpg) | output after the server received(test_received.jpg) |
---|---|
Server
static void Main(string[] args)
{
int Port = 20000;
TcpListener? server = null;
try
{
server = new TcpListener(IPAddress.Any, Port);
server.Start();
var client = server.AcceptTcpClient();
var stream = client.GetStream();
// get image
var ms = new MemoryStream();
int total = 0;
int read = -1;
do
{
if (!stream.CanRead)
{
continue;
}
Console.WriteLine("get");
byte[] data = new byte[client.ReceiveBufferSize];
read = stream.Read(data, 0, client.ReceiveBufferSize);
ms.Write(data, 0, data.Length);
total = read;
} while (read > 0);
Console.WriteLine("get image finish");
Console.WriteLine($"total is {total}"); // 8590651
byte[] image = ms.ToArray();
// image.Length is different every time, I don't know why
Console.WriteLine($"the byte array size is {image.Length}");
File.WriteAllBytes("/Users/tim/Downloads/test_received.jpg", image);
Console.WriteLine("saved");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
finally
{
server?.Stop();
}
}
Client
private static void SendData(byte[] image)
{
Console.WriteLine($"image byte size is {image.Length}"); // 8590651
File.WriteAllBytes("/Users/tim/Downloads/test_send.jpg", image); // test
// TCP
var tcpClient = new TcpClient();
try
{
tcpClient.Connect("127.0.0.1", 20000);
}
catch (Exception e)
{
Console.Error.WriteLine($"TCP connect error, {e.Message}");
return;
}
try
{
var stream = tcpClient.GetStream();
if (stream.CanWrite)
{
stream.Write(image, 0, image.Length);
}
}
catch (Exception e)
{
Console.Error.WriteLine($"send error, {e.Message}");
}
tcpClient.Close();
}
CodePudding user response:
Your mistake is in this line
ms.Write(data, 0, data.Length);
It should be
ms.Write(data, 0, read);
To be honest, it's far easier to just use CopyTo
.
var ms = new MemoryStream();
stream.CopyTo(ms);
You should also consider transitioning to a fully async
flow, and you are also missing using
everywhere.
static async Task Main(string[] args)
{
int Port = 20000;
TcpListener? server = null;
try
{
server = new TcpListener(IPAddress.Any, Port);
server.Start();
using var client = await server.AcceptTcpClientAsync();
using var stream = client.GetStream();
// get image
var ms = new MemoryStream();
await stream.CopyToAsync(ms);
Console.WriteLine("get image finish");
Console.WriteLine($"total is {total}"); // 8590651
byte[] image = ms.ToArray();
// image.Length is different every time, I don't know why
Console.WriteLine($"the byte array size is {image.Length}");
await File.WriteAllBytesAsync("/Users/tim/Downloads/test_received.jpg", image);
Console.WriteLine("saved");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
finally
{
if(server?.Active)
server?.Stop();
}
}
private static async Task SendData(byte[] image)
{
Console.WriteLine($"image byte size is {image.Length}"); // 8590651
await File.WriteAllBytesAsync("/Users/tim/Downloads/test_send.jpg", image); // test
// TCP
using var tcpClient = new TcpClient();
try
{
await tcpClient.ConnectAsync("127.0.0.1", 20000);
}
catch (Exception e)
{
Console.Error.WriteLine($"TCP connect error, {e.Message}");
return;
}
try
{
using var stream = tcpClient.GetStream();
await stream.WriteAsync(image, 0, image.Length);
}
catch (Exception e)
{
Console.Error.WriteLine($"send error, {e.Message}");
}
}
Consider also passing the NetworkStream
directly to a FileStream
.