I am trying to receive the image form Server and want to display it into a Picturebox in WM Application. I am successfully receiving the Image Stream and I don’t find any way to display it into a PictureBox. In windows program we have a method in Image class that is FromStream (Image.FromStream) but this function is not available in Compact Framework 3.5. I also tried the following code to do so:
private void button1_Click(object sender, EventArgs e)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress IP = IPAddress.Parse("192.168.1.2");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
s.Connect(IPE);
byte[] buffer = new byte[55296];
s.Receive(buffer, buffer.Length, SocketFlags.None);
MemoryStream ms = new MemoryStream(buffer);
Image im = new Bitmap(ms); //EXCEPTION
pictureBox1.Image = im;
}
But it gives an Exception. No detail is provided with the exception and VS is only displaying a dialogbox with the text "Exception".
Does your image size is less than the size of the buffer? If not all the excess data is lost and an exception is thrown.
Also could you try without the buffer length specified.
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
IPAddress IP = IPAddress.Parse("192.168.1.2");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
s.Connect(IPE);
byte[] buffer = new byte[55296];
int rec = s.Receive(buffer, SocketFlags.None);
using (MemoryStream ms = new MemoryStream(buffer, 0, rec))
{
Image im = new Bitmap(ms);
pictureBox1.Image = im;
}
}
You do have to check the return value of the socket's Receive method in order to determine
how large your bitmap buffer is:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress IP = IPAddress.Parse("192.168.1.2");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
s.Connect(IPE);
byte[] buffer = new byte[55296];
int rec = s.Receive(buffer, buffer.Length, SocketFlags.None);
MemoryStream ms = new MemoryStream(buffer, 0, rec);
Image im = new Bitmap(ms);
pictureBox1.Image = im;
Hope, this helps.
Related
I'm programing an application where I need to make file transfers.
Most of the communication in my application is TCP and works just fine. But when I try to do a file transfer, I seem to lose some bytes at the start and/or end of the file.
Here is the piece of code that is supposed to do the file transfer:
Thread sendFile = new Thread(new ThreadStart(() =>
{
TcpClient tcpClient = new TcpClient(ip, 3);
tcpClient.Client.DontFragment = true;
FileStream fileStream = new FileInfo(FilePath).OpenRead();
Thread.Sleep(1000);
fileStream.CopyTo(tcpClient.GetStream());
fileStream.Close();
tcpClient.Close();
}));
sendFile.SetApartmentState(ApartmentState.STA);
sendFile.Start();
sendFile.Join();
I have searched and tried a bunch of methodes of sending a filestream through a networkstream (WriteAsync, byte[] buffer, flushing the buffers,...) but all had similar results: some bytes at the start of the file and about every 128kb disappear.
I got the best results when running the transfer in a STA thread with some delay before starting.
Client code:
FileStream fileStream = File.Create(path);
Thread receiveFile = new Thread(new ThreadStart(() =>
{
tcpClient.GetStream().CopyTo(fileStream);
}));
receiveFile.SetApartmentState(ApartmentState.STA);
receiveFile.Start();
receiveFile.Join();
fileStream.Close();
I tried it on different computers and routers connected with LAN cables to make sure those weren't the problems.
I'm using .Net Core 5.0
Update
I've tried a few things and it made it better, but still not perfect.
Server code:
Thread sendFile = new Thread(new ThreadStart(() =>
{
TcpClient tcpClient = new TcpClient(ip, 3);
FileStream fileStream = new FileInfo(FilePath).OpenRead();
NetworkStream networkStream = tcpClient.GetStream();
Thread.Sleep(1000);
byte[] bytes = new byte[1024];
int read = -1;
while (read != 0)
{
read = fileStream.Read(bytes);
networkStream.Write(bytes, 0, read);
}
filestream.Flush();
fileStream.Close();
tcpClient.Close();
}));
sendFile.SetApartmentState(ApartmentState.STA);
sendFile.Start();
sendFile.Join();
Client code:
FileStream fileStream = File.Create(path);
BufferedStream networkStream = new BufferedStream(client.GetStream());
Thread receiveFile = new Thread(new ThreadStart(() =>
{
byte[] bytes = new byte[2048];
int read = -1;
while (read != 0)
{
read = networkStream.Read(bytes, 0, bytes.Length);
using (MemoryStream memoryStream = new MemoryStream(bytes))
{
using (BinaryReader binaryReader = new BinaryReader(memoryStream))
{
fileStream.Write(binaryReader.ReadBytes(read));
}
}
}
fileStream.Flush();
}));
receiveFile.SetApartmentState(ApartmentState.STA);
receiveFile.Start();
receiveFile.Join();
fileStream.Close();
As I had assumed the problem lies on the TcpClient. When using normal sockets everything works as it should: no data loss.
Client code:
Thread receiveFile = new Thread(new ThreadStart(() =>
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
socket.Bind(new IPEndPoint(IPAddress.Any, 33));
socket.Listen();
socket = socket.Accept();
FileStream fileStream = File.Create(path);
NetworkStream networkStream = new NetworkStream(socket);
networkStream.CopyTo(fileStream);
fileStream.Flush();
fileStream.Close();
socket.Close();
socket.Dispose();
}));
receiveFile.SetApartmentState(ApartmentState.STA);
receiveFile.Start();
receiveFile.Join();
GC.Collect();
Server code:
Thread sendFile = new Thread(new ThreadStart(() =>
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
socket.Connect(new IPEndPoint(IPAddress.Parse(client.Host), 33));
FileStream fileStream = new FileInfo(FilePath).OpenRead();
NetworkStream networkStream = new NetworkStream(socket);
Thread.Sleep(1000);
fileStream.CopyTo(networkStream);
fileStream.Flush();
fileStream.Close();
socket.Close();
socket.Dispose();
}));
sendFile.SetApartmentState(ApartmentState.STA);
sendFile.Start();
sendFile.Join();
GC.Collect();
I forced the collector to make sure the sockets are disposed, so they can be used again.
Here is my server code for reading a mp4 file and sending to the client
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 3400);
sock.Bind(ep);
sock.Listen(10);
sock = sock.Accept();
FileStream fs = new FileStream(#"E:\Entertainment\Songs\Video song\song.mp4",FileMode.Open);
BinaryReader br = new BinaryReader(fs);
byte[] data = new byte[fs.Length];
br.Read(data, 0, data.Length);
sock.Send(data);
fs.Close();
sock.Close();
Here is the client code
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3400);
sock.Connect(ep);
MemoryStream ms = new MemoryStream();
int size = 3190551; // I know the file size is about 30 mb
int rec;
while (size > 0)
{
byte[] buffer;
if (size < sock.ReceiveBufferSize)
{
buffer = new byte[size];
}
else
{
buffer = new byte[sock.ReceiveBufferSize];
}
rec = sock.Receive(buffer, 0, buffer.Length, 0);
size = size - rec;
ms.Write(buffer, 0, buffer.Length);
}
byte[] data = ms.ToArray();
FileStream fs = new FileStream("E:/song.mp4",FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs)
bw.Write(data);
fs.Close();
sock.Close();
**At the end i just get the data in between 3 to 4 mb.... im new to socket programming and I don't know where the problem is... whether its sending side or receiving !!!! it looks like I just receive a single chunk of data from the server side **
I think the problem is here
int size = 3190551; // I know the file size is about 30 mb
you are reading just 3190551 byte which is 3.04mb not 30mb.
try to send length of your file at the beginning of your message so client will know how many bytes it should get from server.
I'm trying to send a file from a client to a server, so I load the file in a byte array in the client side, and send it to the server through the send() method, but the received array is different and bigger than the array sent, I wonder if it's a protocol problem (but I'm using tcp protocol wich assure error detection ):
Client code:
IPAddress ipAddress = new IPAddress(ip);
IPEndPoint ipEnd = new IPEndPoint(ipAddress, 5656);
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
FileStream fl = File.Open("pos.xls",FileMode.Open);
byte[] fileData = ReadFully(fl);
fl.Close();
byte[] clientData = new byte[ fileData.Length];
fileData.CopyTo(clientData,0);
curMsg = "Connection to server ...";
clientSock.Connect(ipEnd);
curMsg = "File sending...";
clientSock.Send(clientData);
curMsg = "Disconnecting...";
clientSock.Close();
curMsg = "File transferred.";
Server code:
curMsg = "Starting...";
sock.Listen(100);
curMsg = "Running and waiting to receive file.";
byte[] clientData = new byte[1024 * 5000];
while (true)
{
Socket clientSock = sock.Accept();
clientData = new byte[1024 * 5000];
int receivedBytesLen = clientSock.Receive(clientData);
curMsg = "Receiving data...";
FileStream fz = writeFully(clientData);
fz.Close();
curMsg = "Saving file...";
You have defined clientData = new byte[1024 * 5000]; - and you then don't use receivedBytesLen. I can't remember whether that Receive overload will read as much as it can until EOF, or simply "some or EOF" (the latter being the Stream.Read behavior), but you must verify and use receivedBytesLen.
IMO, the approach of a fixed buffer is inherently flawed, as it doesn't cope well with oversized inputs either. Personally I would use a NetworkStream here; then your entire code becomes:
using(var fz = File.Create(path)) {
networkStream.CopyTo(fz);
}
Another common approach here is to send the expected size as a prefix to the data; that way you can verify that you have the data you need. I personally wouldn't use this information to create a correct-sized buffer in memory though, as that still doesn't allow for epic-sized files (a Stream, however, does).
I'm trying to send an image using a TCP socket. The client connects to the server without any problems and start to receive the data. The problem is when I try to convert the stream to an image using FromStream() method, I get an OutOfMemory Exception. Can anyone help me out? Really 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 snippet
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,
There are a couple of things wrong, including, possibly the protocol you are using. First, the client:
If you expect a single image, there is no need for the while loop
Your client first does a Read which reads some information from the server into the buffer, and then it calls Image.FromStream(nNetStream) which will read incomplete data.
Whenever you read from a stream, keep in mind that a single Read call is not guaranteed to fill your buffer. It can return any number of bytes between 0 and your buffer size. If it returns 0, it means there is no more to read. In your case this also means that your client currently has no way of knowing how much to read from the server. A solution here is to have the server send the length of the image as the first piece of information. Another solution would be to have the server disconnect the client after it has sent the information. This may be acceptable in your case, but it will not work if you need persistent connections (e.g. pooled connections on client side).
The client should look something like this (assuming the server will disconnect it after it sends 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;
}
Next, the server:
Instead of Pending, you can simply accept the client
The server sends the stream over and over again to the same client, until they disconnect. 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);
}
}
}
This part looks funky 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 client.ReceiveBufferSize bytes into the "bytes" array, and then you proceed to construct the image from what's left on the stream. What about the bytes you just read into "bytes"?
I recomend you to use this code(I've created it by myself and tested it and it works perfect.):
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 received byteArray to an image.
It seems like your server is sending the image over and over again:
while (client.Connected)
{
NetworkStream nStream = client.GetStream();
nStream.Write(bStream, 0, bStream.Length);
}
If the server can send data fast enough, the client will probably keep receiving it.
Here's a solution :
Server side :
tImage.Save(new NetworkStream(client), System.Drawing.Imaging.ImageFormat.Png);
Cliend 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));
I am trying to set up two programs in C#. Basically, a simple client server set up where I want the server to listen for an image from the client. Then, upon receiving the image, will display it in a PictureBox.
I keep running into the following error:
A first chance exception of type
'System.ArgumentException' occurred in
System.Drawing.dll
The error is happening on the server code that is listening at this line:
Image bmp = Image.FromStream(ms);
Any ideas?
The Server code that listens:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace NetView
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
startListening();
}
private void startListening()
{
////////////////////////////////////////////
Console.WriteLine("Server is starting...");
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket newsock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(ipep);
newsock.Listen(10);
Console.WriteLine("Waiting for a client...");
Socket client = newsock.Accept();
IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}",
newclient.Address, newclient.Port);
while (true)
{
data = ReceiveVarData(client);
MemoryStream ms = new MemoryStream(data);
try
{
Image bmp = Image.FromStream(ms);
pictureBox1.Image = bmp;
}
catch (ArgumentException e)
{
Console.WriteLine("something broke");
}
if (data.Length == 0)
newsock.Listen(10);
}
//Console.WriteLine("Disconnected from {0}", newclient.Address);
client.Close();
newsock.Close();
/////////////////////////////////////////////
}
private static byte[] ReceiveVarData(Socket s)
{
int total = 0;
int recv;
byte[] datasize = new byte[4];
recv = s.Receive(datasize, 0, 4, 0);
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;
byte[] data = new byte[size];
while (total < size)
{
recv = s.Receive(data, total, dataleft, 0);
if (recv == 0)
{
break;
}
total += recv;
dataleft -= recv;
}
return data;
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
The Client Code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Drawing;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
byte[] data = new byte[1024];
int sent;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
Socket server = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
server.Connect(ipep);
}
catch (SocketException e)
{
Console.WriteLine("Unable to connect to server.");
Console.WriteLine(e.ToString());
Console.ReadLine();
}
Bitmap bmp = new Bitmap("c:\\eek256.jpg");
MemoryStream ms = new MemoryStream();
// Save to memory using the Jpeg format
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
// read to end
byte[] bmpBytes = ms.GetBuffer();
bmp.Dispose();
ms.Close();
sent = SendVarData(server, bmpBytes);
Console.WriteLine("Disconnecting from server...");
server.Shutdown(SocketShutdown.Both);
server.Close();
Console.ReadLine();
}
private static int SendVarData(Socket s, byte[] data)
{
int total = 0;
int size = data.Length;
int dataleft = size;
int sent;
byte[] datasize = new byte[4];
datasize = BitConverter.GetBytes(size);
sent = s.Send(datasize);
while (total < size)
{
sent = s.Send(data, total, dataleft, SocketFlags.None);
total += sent;
dataleft -= sent;
}
return total;
}
}
}
ArgumentException tells you that the image format in the stream is invalid. Which is probably caused by the client application closing the memory stream before the data were sent.
Try replacing byte[] bmpBytes = ms.GetBuffer(); with
byte[] bmpBytes = ms.ToArray();
Or close the stream after the data were sent.
Remember that the byte-array returned by the .GetBuffer() returns the underlying array, not a copy of it (.ToArray() returns a copy), that is valid as long as the parent stream.
If you have access to the JPG file itself (as in the example), you should send the file bytes and not use the Image/Bitmap classes. By reading a JPG file and re-encoding into JPG you are decreasing the image quality and incurring unnecessary overhead. You can use File.ReadAllBytes() to quickly get the complete byte[] or read/send it in pieces if your memory space is limited.
A better way to send the image would be to use BinaryFormatter.
eg, some snippets from my own code to send an image every second...
sending:
TcpClient client = new TcpClient();
try
{
client.Connect(address, port);
// Retrieve the network stream.
NetworkStream stream = client.GetStream();
MessageData data = new MessageData(imageToSend);
IFormatter formatter = new BinaryFormatter();
while(true)
{
formatter.Serialize(stream, data);
Thread.Sleep(1000);
data.GetNewImage();
}
}
receiving:
TcpListener listener = new TcpListener(address, port);
listener.Start();
try
{
using (TcpClient client = listener.AcceptTcpClient())
{
stream = client.GetStream();
IFormatter formatter = new BinaryFormatter();
while (true)
{
MessageData data = (MessageData)formatter.Deserialize(stream);
if (ImageReceivedEvent != null) ImageReceivedEvent(data.Picture);
}
}
}
and the MessageData class simply holds the image and has the [Serializable] attribute.
Use Arul's code to get the data to send correctly -- you want .ToArray(), not .GetBuffer(). Then, you'll want to run the server's 'startListening' method on a background thread or you won't actually see anything (as the form thread will be busy running the server code. Try:
var t = new Thread(startListening);
t.IsBackground = true;
t.start();
In your Form_Load method instead of directly calling startListening in your constructor.
Here is a code that works for me. User starts server with a button and client selects photo by opening the file dialog of computer. At last sends the image but be careful about the photo size because UDP cannot transmit much large data.
Server:
delegate void showMessageInThread(string message);
UdpClient listener = null;
IPEndPoint endpoint = null;
Thread listenThread = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
startServer();
}
private void startServer()
{
endpoint = new IPEndPoint(IPAddress.Any, 1234);
listener = new UdpClient(endpoint);
ShowMsg("Waiting for a client!");
listenThread = new Thread(new ThreadStart(Listening));
listenThread.Start();
}
private void Listening()
{
while (true)
{
//take the coming data
byte[] comingDataFromClient = listener.Receive(ref endpoint);
ImageConverter convertData = new ImageConverter();
Image image = (Image)convertData.ConvertFrom(comingDataFromClient);
pictureBox1.Image = image;
}
private void ShowMsg(string msg)
{
this.richTextBox1.Text += msg + "\r\n";
}
Client:
Socket server = null;
MemoryStream ms;
IPEndPoint endpoint = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
server = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234);
}
private void btn_browse_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
string path = openFileDialog1.FileName;
pictureBox1.Image = Image.FromFile(path);
textPath.Text = path;
}
private void btn_send_Click(object sender, EventArgs e)
{
try
{
ms = new MemoryStream();
Bitmap bmp = new Bitmap(this.openFileDialog1.FileName);
bmp.Save(ms, ImageFormat.Jpeg);
byte[] byteArray = ms.ToArray();
server.Connect(endpoint);
server.SendTo(byteArray, endpoint);
}
}
catch (Exception ex)
{
}
data = ReceiveVarData(client);
MemoryStream ms = new MemoryStream(data);
Image bmp = Image.FromStream(ms);
pictureBox1.Image = bmp;
The error may due to corrupted or incomplete bmp image received in the MemoryStream
it worked fine for me after increasing the socket send/receive buffers values
adjust the sender "Socket.SendBufferSize" and the receiver "Socket.ReceiveBufferSize" to large values for example = 1024 * 2048 *10
this will help sending the entire image at once.
or another solution is to check whether the received data size (data.length) is the same as the sent image data size, before the code line of forming the received image stream