I have a few problem to send jpg data using a socket.
Sender side:
Socket client_s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
IPEndPoint serverEP = new IPEndPoint(IPAddress.Loopback, 4567);
client_s.Connect(serverEP);
NetworkStream stream = new NetworkStream(client_s);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
Receiver side:
clientSocket = listenSocket.Accept();
NetworkStream s = new NetworkStream(clientSocket);
Bitmap slice_bmp = new Bitmap(s);
Graphics g = this.CreateGraphics();
g.DrawImage(slice_bmp,0,0);
When I execute the above, Bitmap slice_bmp = new Bitmap(s); is blocked until closing sender's socket. After sender's socket is closed, an image is drawn normally. I want to know why that operation is blocked?
Also, is it right using instance of Networkstream as argument of constructor of Bitmap? (My code is based on inheritance)
First of all, I would suggest you to use Flush() method of the NetworkStream to be sure that all the data has been sent.
Socket client_s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint serverEP = new IPEndPoint(IPAddress.Loopback, 4567);
client_s.Connect(serverEP);
NetworkStream stream = new NetworkStream(client_s);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Flush(); //flush everything
On the receiver's side, you should first read all the bytes of the image into a byte array. From that byte array you could construct the MemoryStream and than Bitmap from that stream.
clientSocket = listenSocket.Accept();
NetworkStream s = new NetworkStream(clientSocket);
int bytesRead = 0;
int howMany = 0;
byte [] byteBuffer = new byte[100000];
do
{
howMany = s.Read(byteBuffer, bytesRead, 10000);
bytesRead += howMany;
if(bytesRead>=byteBuffer.Length)
byteBuffer = ResizeByteArray(byteBuffer);
}
while (howMany > 0 && s.DataAvailable);
MemoryStream ms = new MemoryStream(byteBuffer);
Bitmap slice_bmp = new Bitmap(ms);
Graphics g = this.CreateGraphics();
g.DrawImage(slice_bmp, 0, 0);
g.Dispose();
If the image is larger from the capacity of the instantiated byte array, then you need to resize it. You could use this helper method:
private byte[] ResizeByteArray(byte[] arr)
{
byte[] newArr = new byte[arr.Length * 2];
Array.Copy(arr, newArr, arr.Length);
return newArr;
}
And as a side note, always call Dispose on Graphics object that you create manually (like in this case). I checked the code and it works.
It appears you are working on a single threaded-application, or at least on the UI-thread of a multi-threaded-application. The blocking appears because your bitmap object is waiting for its construction to be complete. And as it takes a while to read from a stream over a network, your program will not continue until your bitmap-object is fully created.
If you wanted your program to go on, you would need to create a thread and have it read from the stream and create the bitmap. When the bitmap is ready you could fire an event and act appropriately.
As NetworkStream is a subclass of System.IO.Stream it is perfectly fine! You can use any System.IO.Stream to create an object that requires a stream. The only result is, as you experienced, it might take a little longer than creating the image, e.g. from a System.IO.FileStream.
Have a look at MSDN most of the stuff is well described.
This is because bitmap class waits for transmission to end:
First receive byte data buffer separately,
then create memory stream from it and then create bitmap.
Related
i searched in all similar problem but still couldn't solve the problem
this is a server code it is work successfully and the image File created successfully BUT if i cannot access the image file
image i = Image.FromStream(StreamObject);
NOTES:
1- the image not too large
2- the image have valid image format
I know the problem related to the stream ... how can i control this problem
i want to retrive the saved image in the image object for some reason..
How can i keep the stream open for the lifetime of the image.??
static void Main(string[] args)
{
IPAddress ipAdress = IPAddress.Parse("192.160.1.8");
// Initializes the Listener
TcpListener tcpListener = new TcpListener(ipAdress, 8001);
tcpListener.Start();
int no;
for (;;)
{
Socket socket = tcpListener.AcceptSocket();
if (socket.Connected)
{
Stream os = File.OpenWrite("Target.jpg",);
byte[] buffer = new byte[8000000];
NetworkStream networkStream = new NetworkStream(socket);
no = networkStream.Read(buffer, 0, 8000000);
os.Write(buffer, 0, no);
///here the problem in the following line
///
Image i = Image.FromFile("Target.jpg");
///
networkStream.Close();
socket.Close();
break;
}
}
}
While bytes have been written to the buffer, the bytes may not have been flushed to the disk. Additionally, the code example provided keeps the file open for writing while it is getting read into an image. For things like streams, you should wrap the usage in using statements in order to avoid these types of memory errors.
static void Main(string[] args)
{
IPAddress ipAdress = IPAddress.Parse("192.160.1.8");
// Initializes the Listener
TcpListener tcpListener = new TcpListener(ipAdress, 8001);
tcpListener.Start();
int no;
for (;;)
{
Socket socket = tcpListener.AcceptSocket();
if (socket.Connected)
{
byte[] buffer = new byte[8000000];
using (Stream os = File.OpenWrite("Target.jpg"))
{
using (NetworkStream networkStream = new NetworkStream(socket))
{
no = networkStream.Read(buffer, 0, 8000000);
os.Write(buffer, 0, no);
}
}
///here the problem in the following line
///
Image i = Image.FromFile("Target.jpg");
///
socket.Close();
break;
}
}
}
Alternatively, and probably more appropriately, you should consider creating your GDI+ image directly from the stream using Image.FromStream. The Image.FromStream method is documented here: https://msdn.microsoft.com/en-us/library/system.drawing.image.fromstream%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
I am sending very large file over TCP/IP network which is working as expected.
Just one concern that how to send it efficiently so that memory consumption should be optimized.
Below is the working code
Stream fileStream = File.OpenRead(tbFilename.Text);
byte[] fileBuffer = new byte[fileStream.Length];
fileStream.Read(fileBuffer, 0, (int)fileStream.Length);
// Open a TCP/IP Connection and send the data
TcpClient clientSocket = new TcpClient(tbServer.Text,8080);
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Write(fileBuffer,0,fileBuffer.GetLength(0));
networkStream.Close();
Firstly, Stream.Read will probably not read the whole file just a chunk, but you omit the return value, which is the number of read bytes.
Secondly, you should use a smaller buffer (eg. 4K) and use that to send the file.
const int BUFSIZE = 4096;
long transferred = 0L;
long length = fileStream.Length;
using (BinaryReader br = new BinaryReader(fileStream))
{
while (transferred < length)
{
int chunkSize = Math.Min(length - transferred, BUFSIZE);
byte[] buffer = br.ReadBytes(chunkSize);
networkStream.Write(buffer, 0, chunkSize);
transferred += chunkSize;
// here you can even report some progress to adjust a ProgressBar or something
}
}
You can use Stream.CopyTo() to copy data from a source stream into another.
The CopyTo() method uses a temporary buffer as suggested by taffer.
Do not forget to Flush() the network stream afterwards.
using (Stream fileStream = File.OpenRead(tbFilename.Text))
{
TcpClient clientSocket = new TcpClient(tbServer.Text, 8080);
NetworkStream networkStream = clientSocket.GetStream();
fileStream.CopyTo(networkStream);
networkStream.Flush();
networkStream.Close();
clientSocket.Close();
}
Just trying to use Networkstream, and this is a simple code i wrote:
Client side:
TcpClient c = new TcpClient();
c.Connect("10.0.0.4", 10);
NetworkStream ns = c.GetStream();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("first");
byte[] buffer2 = System.Text.Encoding.UTF8.GetBytes("second");
MemoryStream stream = new MemoryStream();
stream.Write(buffer, 0, buffer.Length);
stream.Write(buffer2, 0, buffer2.Length);
stream.CopyTo(ns);
This is the server side:
TcpListener tl = new TcpListener(IPAddress.Any, 10);
tl.Start();
TcpClient c = tl.AcceptTcpClient();
NetworkStream ns = new NetworkStream(c.Client);
byte[] buff = new byte[5];
ns.Read(buff,0,buff.Length);
string result = System.Text.Encoding.UTF8.GetString(buff);
MessageBox.Show(result);
only when i close the entire application the MessageBox line is executed , and im always getting a blank messagebox! which mean result doesnt contain nothing...
Any help?
On the client stream is positioned at the very end of the stream. Therefore, CopyTo has nothing left to copy.
Use stream.Position = 0; before copying.
Also, you don't seem to be aware of the fact that socket reads (in fact any stream read) can return less bytes than were requested (at least one). Your reading code must account for that. TCP does not preserve message boundaries.
I wanted to create a project for streaming multiple images through net. I just wanted to start with small, functional code but already encountered a funky problem for me. Image is received, but it contains graphical bugs like its only a part of it.
Sadly cant show images cause of low rputation, here is link.
http://img543.imageshack.us/img543/1508/buggedy.jpg
Of course, million dollars for answer. ^^
TcpListener listener;
TcpClient client;
TcpClient datatoclient;
NetworkStream stream;
Host part:
listener = new TcpListener(5000);
listener.Start();
datatoclient = listener.AcceptTcpClient();
NetworkStream nowystream = datatoclient.GetStream();
MemoryStream ms = new MemoryStream();
byte[] image = File.ReadAllBytes("default.jpg");
switch (trackBar1.Value)
{
case 0:
image = File.ReadAllBytes("mirrion.jpg");
break;
case 1:
image = File.ReadAllBytes("tenis.jpg");
break;
case 2:
image = File.ReadAllBytes("marisasold.jpg");
break;
}
// get the image size in bytes
int numberOfBytes = image.Length;
// put the size into an array
byte[] numberOfBytesArray = BitConverter.GetBytes(numberOfBytes);
// send the image size
nowystream.Write(numberOfBytesArray, 0, numberOfBytesArray.Length);
// send the image
nowystream.Write(image, 0, numberOfBytes);
Client part:
client = new TcpClient("127.0.0.1", 5000);
stream = client.GetStream();
byte[] data = new byte[4];
// read the size
stream.Read(data, 0, data.Length);
int size = BitConverter.ToInt32(data, 0);
label1.Text = size.ToString();
// prepare buffer
data = new byte[size];
// load image
stream.Read(data, 0, data.Length);
// save image to file for test
File.WriteAllBytes("received.jpg", data);
MemoryStream MS = new MemoryStream(data);
pictureBox1.Image = Image.FromStream(MS);
stream.Read doesn't guarantee that it will read data.Length bytes. Instead it returns number of bytes read. So you should check its return value and continue reading till you get all the bytes.
See http://msdn.microsoft.com/en-us/library/system.io.stream.read(v=vs.90).aspx (Section Return Value)
Thr read method can be something like this
void Read(Stream stream, byte[] buffer,int offset,int len)
{
int read = 0;
while (read < len)
{
read += stream.Read(buffer, offset + read, len-read);
}
}
So I have found here in stackoverflow One code for sending through sockets a binary file, an image.. So i used it for test to my Project
private void send_ss()
{
byte[] data = new byte[1024];
int sent;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 306);
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:\\Windows\\Web\\Wallpaper\\Theme2\\img7.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.ToArray();
bmp.Dispose();
ms.Close();
sent = SendVarData(server, bmpBytes);
//Console.WriteLine("Disconnecting from server...");
server.Shutdown(SocketShutdown.Both);
server.Close();
}
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;
}
so i tried to send this picture on one of my Listening Sockets in Port 306 (listened with m IRC)
on *:socklisten:ac_img:{
var %p = $ticks $+ $time(hhnnss) $+ $ctime
sockaccept ac_img_ $+ %p
echo -s [] Image Connection Established On -> ac_img_ $+ %p
}
on *:sockread:ac_img_*:{
sockread &picture
bwrite $qt($mIRCdir $+ $sockname $+ .jpg) -1 -1 &picture
}
So i'm getting files like ac_img_2920385501147471360792067.jpg and so on. Same size with the original BUT the images just not appearing , so i opened Both files with word pad and they were a bit different... dunno why...
So any ideas why i'm facing this issue? i mean... I'm taking every single data from my socket and saving them to the file? Maybe a corrupt on file read through c#?
The image is different because you read it, parse it into a Bitmap and reencode it. The wordpad screenshot shows that both are JPEG's but with different metadata (for example "adobe" missing").
Just use File.ReadAllBytes or other lossless methods to read the image.
The sending code looks sound. Not sure why you're looping. Sending never does partial IOs AFAIK on blocking sockets.