TCP / TCP client image transmission
I am trying to send an image using a TCP socket. The client connects to the server without any problems and starts receiving data. The problem is that when I try to convert a stream to an image using the FromStream () method, I get an OutOfMemory exception. Can anyone help me? Very important! Here is the code:
client snippet
private void btnConnect_Click(object sender, EventArgs e)
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
TcpClient client = new TcpClient();
client.Connect(ipAddress, 9500);
NetworkStream nNetStream = client.GetStream();
while (client.Connected)
{
lblStatus.Text = "Connected...";
byte[] bytes = new byte[client.ReceiveBufferSize];
int i;
if (nNetStream.CanRead)
{
nNetStream.Read(bytes, 0, bytes.Length);
Image returnImage = Image.FromStream(nNetStream); //exception occurs here
pictureBox1.Image = returnImage;
}
else
{
client.Close();
nNetStream.Close();
}
}
client.Close();
}
>
server fragment
try
{
IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddress, 9500);
server.Start();
Console.WriteLine("Waiting for client to connect...");
while (true)
{
if (server.Pending())
{
Bitmap tImage = new Bitmap(Image URL goes here);
byte[] bStream = ImageToByte(tImage);
while (true)
{
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected");
while (client.Connected)
{
NetworkStream nStream = client.GetStream();
nStream.Write(bStream, 0, bStream.Length);
}
}
}
}
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
static byte[] ImageToByte(System.Drawing.Image iImage)
{
MemoryStream mMemoryStream = new MemoryStream();
iImage.Save(mMemoryStream, System.Drawing.Imaging.ImageFormat.Gif);
return mMemoryStream.ToArray();
}
Thanks a lot in advanced,
a source to share
There are a couple of bugs, including perhaps the protocol you are using. First, the client:
- If you are expecting a single image, there is no need for a loop
while
- First, the client executes
Read
, which reads some information from the server into a buffer, and then callsImage.FromStream(nNetStream)
, which will read the incomplete data. - Whenever you read a stream, keep in mind that a single call
Read
does not guarantee that your buffer is full. It can return any number of bytes between 0 and your buffer size. If it returns 0, then there is nothing more to read. In your case, this also means that your client does not currently know how much to read from the server. The solution here is for the server to send the length of the image as the first piece of information. Another solution would be to shutdown the server after sending this information. This may be acceptable in your case, but it won't work if you need persistent connections (for example, client-side pooled connections).
The client should look something like this (assuming the server will shut it down after sending the data):
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
using (TcpClient client = new TcpClient())
{
client.Connect(ipAddress, 9500);
lblStatus.Text = "Connected...";
NetworkStream nNetStream = client.GetStream();
Image returnImage = Image.FromStream(nNetStream);
pictureBox1.Image = returnImage;
}
Then the server:
- Instead,
Pending
you can just accept the client - The server sends the stream over and over to the same client until it disconnects. Instead, send it only once.
The server loop should look something like this:
Bitmap tImage = new Bitmap(Image URL goes here);
byte[] bStream = ImageToByte(tImage);
while (true)
{
// The 'using' here will call Dispose on the client after data is sent.
// This will disconnect the client
using (TcpClient client = server.AcceptTcpClient())
{
Console.WriteLine("Connected");
NetworkStream nStream = client.GetStream();
try
{
nStream.Write(bStream, 0, bStream.Length);
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
}
a source to share
This part looks scared to me:
byte[] bytes = new byte[client.ReceiveBufferSize];
int i;
if (nNetStream.CanRead)
{
nNetStream.Read(bytes, 0, bytes.Length);
Image returnImage = Image.FromStream(nNetStream); //exception occurs here
First, you read the client.ReceiveBufferSize bytes into the "bytes" array, and then move on to building an image from what's left in the stream. How about the bytes you just read in "bytes"?
a source to share
I recommend you use this code (I created it myself and tested it and it works great.):
public void Bitmap ConvertByteArrayToBitmap(byte[] receivedBytes)
{
MemoryStream ms = new MemoryStream(receivedBytes);
return new Bitmap(ms, System.Drawing.Imaging.ImageFormat.Png); // I recomend you to use png format
}
Use this to convert the resulting byteArray to an image.
a source to share
Here's the solution:
Server side:
tImage.Save(new NetworkStream(client), System.Drawing.Imaging.ImageFormat.Png);
Cleand's side:
byte[] b = new byte[data.ReceiveBufferSize];
client.Receive(b);
MemoryStream ms = new MemoryStream(b);
Image receivedImag = Image.FromStream(ms);
or:
Image receivedImag = Image.FromStream(new NetworkStream(client));
a source to share