I'm transferring a file from a C# client to a Java server using TCP Sockets. On the C# client I convert the file to a byte array for transmission and send it using a NetworkStream.
On the Java server I use the following code to convert the received byte array back into a file;
public void run() {
try {
byte[] byteArrayJAR = new byte[filesize];
InputStream input = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(
"Controller " + controllerNumber + ".jar");
BufferedOutputStream output = new BufferedOutputStream(fos);
int bytesRead = input.read(byteArrayJAR, 0, byteArrayJAR.length);
int currentByte = bytesRead;
System.out.println("BytesRead = " + bytesRead);
do {
bytesRead = input.read(
byteArrayJAR,
currentByte,
(byteArrayJAR.length - currentByte));
if (bytesRead >= 0) {
currentByte += bytesRead;
}
}
while (bytesRead > -1);
output.write(byteArrayJAR, 0, currentByte);
output.flush();
output.close();
socket.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
The code above works if the received byte array comes from a client programmed with Java but for C# clients the code hangs in the do-while loop at the bytesRead = input.read(...) method.
Does anybody know why the code is hanging at this point for a C# client but not a Java client? According to the output from the println message data is definately being received by the InputStream and is read once at the bytesRead variable initialization, but not during the do-while loop.
Any solutions or suggestions for overcoming this problem would be welcome.
Regards,
Midavi.
You need to send your bytes as sbyte from c# instead of byte.
In addition you should change your do/while loop to a regular while loop. If you have already read everything from the stream in your first call to input.read then you will block on the second call because read will wait for input.
Based on: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/InputStream.html
int bytesRead = input.read(byteArrayJAR, 0, byteArrayJAR.length);
Reads all available bytes that means your byte-data is alread in byteArrayJAR or am I completly wrong here?
EDIT:
Just checked some of my projects...I send data from Android <=> C# Server Application.
I use String data = input.readLine();(java) and _sw.WriteLine("Testdata");(C#)
Since you cannot know the amount of data being sent in advance in the general case, it would be better to receive the data in chunks and ignore the offset into your bigger array. Your code as-is doesn't handle the case very well if the data is larger than your array, nor if it is smaller than the array.
A much simpler case would be to remove the currentByte offset:
InputStream input = socket.getInputStream();
BufferedOutputStream output = new BufferedOutputStream(
new FileOutputStream("test.exe"));
byte[] bytes = new byte[2048];
int bytesRead;
do {
bytesRead = input.read(bytes, 0, bytes.length);
System.out.println("size: " + bytes.length + " read(): " + bytesRead);
if (bytesRead > 0) {
output.write(bytes, 0, bytesRead);
}
} while (bytesRead > -1);
output.close();
socket.close();
input.close();
And I used the following C# code on the client side:
if (!args.Any())
{
Console.Error.WriteLine("Usage: send.exe <executable>");
Environment.Exit(-1);
}
using (var client = new TcpClient("localhost", 10101))
using (var file = File.Open(args.First(), FileMode.Open, FileAccess.Read))
{
file.CopyTo(client.GetStream());
}
Client side results:
C:\temp>csc send.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.
C:\temp>send send.exe
C:\temp>
Server side results:
C:\temp>javac.exe Server.java
C:\temp>java Server
size: 2048 read(): 2048
size: 2048 read(): 2048
size: 2048 read(): 512
size: 2048 read(): -1
C:\temp>test.exe
Usage: send.exe <executable>
Related
Simple I try to send a file to a server then send a file from server to client using networkstreams (only for files). The code shown is only server side, first one gets a file from client, second sends a file to client
try
{
using (var netStream = new NetworkStream(current, false))
{
netStream.ReadTimeout = 5000;
using (var fileStream = File.OpenWrite(cp.parameters[0] + "\\" + cp.parameters[0] + ".txt"))
{
fileStream.CopyFrom(netStream);
}
}
}
After this i try to execute this piece of code but it says on SocketException that I cannot use it because it's not connected. In debug for the socket "current" i see the .Connected variable is set to false but the IPEndpoints and ports for both sides are still the correct ones only the .Connected status is false.
try
{
Console.WriteLine("Text is a payloadx64file request");
using (var netStream = new NetworkStream(current, false))
{
using (var fileStream = File.OpenRead("Payload_x64.zip"))
{
fileStream.CopyTo(netStream);
Console.WriteLine(fileStream.Name);
}
}
}
How do i use the Socket with a network stream but prevent it to close down after garbage collector or block modification the variable .Connected, also as a side question
I mention that i set the ReadTimeout to 5 seconds because if there is no timeout in the Copy functions the Stream object get's stuck in a while loop because of a stream read that never ends. If someone knows how to end the loop or read please share with me too.
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) //here gets stuck in case someone knows
Here is the Copy code from a stream to another
public static void CopyTo(this Stream input, Stream output)
{
byte[] buffer = new byte[16 * 1024];
int bytesRead;
int total = 0;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
if (total <= totalFileSize)
{
byte[] clear_buffer = CryptosystemChiper.DecryptToByteArray(buffer);
int size = clear_buffer.Length;
output.Write(clear_buffer, 0, size);
total += size;
//Console.WriteLine("Bytes got:" + size); FROM DEBUG
//Console.WriteLine("Total: " + total + " bytesRead is: " + bytesRead); FROM DEBUG
}
else
{
//Console.WriteLine("Total: " + total + " bytesRead is: " + bytesRead); FROM DEBUG
//Console.WriteLine("About to break"); FROM DEBUG
break;
}
}
I recently started to work with TCP in C#. I'm now at the point where I want the client to receive the data sent by the server.
I know that there is no guarantee for the client to receive all data at once. If the size of the data sent is bigger than the buffer's size at the client's side, then the data will be sent in parts. So my question is: how can I store all my received data in a byte array, and then convert it to the actual message when all is received?
I've set the buffer size to 1, so I can see what happens when all sent data doesn't fit in the buffer. Here are my methods in which I call stream.BeginRead() in Client.cs:
// Deliberately setting the buffer size to 1, to simulate what happens when the message doesn't fit in the buffer.
int bufferSize = 1;
byte[] receiveBuffer;
private void ConnectCallback(IAsyncResult result)
{
client.EndConnect(result);
Console.WriteLine("Connected to server.");
stream = client.GetStream();
// At this point, the client is connected, and we're expecting a message: "Welcome!"
receiveBuffer = new byte[bufferSize];
stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, new AsyncCallback(ReadCallback), stream);
}
private void ReadCallback(IAsyncResult result)
{
int bytesLength = stream.EndRead(result);
// Should be "Welcome!". But of course it's "W", because the bufferSize is 1.
string message = Encoding.UTF8.GetString(receiveBuffer, 0, bytesLength);
Console.WriteLine("Received message: {0}", receivedMessage);
// Reset the buffer and begin reading a new message, which will be "e".
// However, I want the whole message ("Welcome!") in one byte array.
receiveBuffer = new byte[bufferSize];
stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReadCallback, null);
}
This is the output when sending the message "Welcome!":
Connected to server.
Received message: W
Received message: e
Received message: l
Received message: c
Received message: o
Received message: m
Received message: e
Received message: !
Should I temporary store the data until the whole message has arrived, and then convert that to a string?
Follow up question: What if 2 messages are sent closely after each other, for example Welcome! and then What's your name? How do I distinguish the two messages then?
Should I temporary store the data until the whole message has arrived, and then convert that to a string?
Yes, exactly.
Follow up question: What if 2 messages are sent closely after each other, for example Welcome! and then What's your name? How do I distinguish the two messages then?
The general approach is to send the length of the message before the message itself. That way the receiving end will know when it has received a complete package.
As 500 - Internal Server Error already pointed out, you use a buffer for it. Here is some Code example:
Receiving:
while (true) //you should use a bool variable here to stop this on disconnect.
{
byte[] bytes;
bytes = ReadNBytes(ns, 4);
//read out the length field we know is there, because the server always sends it.
int msgLenth = BitConverter.ToInt32(bytes, 0);
bytes = ReadNBytes(ns, msgLenth);
//working with the buffer...
if (bytes.Length > 0)
{
try
{
//do stuff here. bytes contains your complete message.
}
catch (Exception e) { Log(e.Message); }
}
}
public static byte[] ReadNBytes(NetworkStream stream, int n)
{
byte[] buffer = new byte[n];
try
{
int bytesRead = 0;
int chunk;
while (bytesRead < n)
{
chunk = stream.Read(buffer, (int)bytesRead, buffer.Length - (int)bytesRead);
if (chunk == 0)
{
// error out
Log("Unexpected disconnect");
stream.Close();
}
bytesRead += chunk;
}
}
catch (Exception e) { Log(e.Message); }
return buffer;
}
To send stuff use something linke this:
public static void SendObject(NetworkStream ns, byte[] data)
{
byte[] lengthBuffer = BitConverter.GetBytes(data.Length);
ns.Write(lengthBuffer, 0, lengthBuffer.Length);
ns.Write(data, 0, data.Length);
}
I hope that helped!
I'm currently working on a project that involves me taking a picture with my laptop camera on a given command. I'm using my webcam as a security camera right now due to the fact that I have not gotten the time to buy a real one yet so my laptop will have to do.
The project is structured like this:
I have my Server (this runs on my laptop) and I have my Client (which runs on my PC which will later be on my phone - but thats not relevant). I send a command to the server using my client (in this case it's "Webcam") and the server receives it, takes a picture using the webcam, gets the bytes and then sends the bytes over a network stream to the client.
However when I download the stream with my client, it downloads 0 bytes. To clarify, it does save the image in my folder but I can't open it because it's 0 bytes.
Server
while (true)
{
if (nwStream.DataAvailable)
{
//Create a byte array (a buffer). This will hold the byte size that we recieve from the client in memory.
byte[] buffer = new byte[client.ReceiveBufferSize];
//Now we need to read the bytes and store the bytes we read in a int, we do this by using our nwStream.Read function and pass it the correct parameters.
//1. [Buffer] - an array of type byte, and we declared that above [buffer] <- This is what we are reading from.
//2. [Offset] - Now we need to set the offset, where we want to start reading in the buffer. so since its an array we start at 0.
//3. [Size] - The number of bytes we want to read from the NetworkStream.
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
//Now we need to decode the message we recieved by using the Encoding.ASCII.GetString to get the string and passing the correct parameters.
//1. [Bytes] - What we want to decode, this is where we give it a byte array
//2. [Index] - We need to give it the first index of the array that we want to decode so it knows where to start, we do this bya dding 0 since its an array.
//3. [Count] - The number of bytes we want to decode and we created an int to hold that number above so let's pass it as a parameter.
string dataRecieved = Encoding.Default.GetString(buffer, 0, bytesRead);
if (dataRecieved == "webcam")
{
Console.WriteLine("Starting the webcam feature..");
CameraFeature();
}
}
}
}
private static void CameraFeature()
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo Device in VideoCaptureDevices)
{
Devices.Add(Device.Name);
Console.WriteLine("Device: " + Device.Name);
}
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[0].MonikerString);
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.Start();
}
private static void exitcamera()
{
FinalVideo.SignalToStop();
// FinalVideo.WaitForStop(); << marking out that one solved it
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame); // as sugested
FinalVideo = null;
}
static void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap video = (Bitmap)eventArgs.Frame.Clone();
//video.Save($"image{imgCount}.png");
Console.WriteLine("Picture taken!");
Connection(video);
exitcamera();
imgCount++;
}
public static void Connection(Bitmap tImage)
{
Console.WriteLine("Starting the transfer..");
byte[] bStream = ImageToByte(tImage);
try
{
nwStream.Write(bStream, 0, bStream.Length);
Console.WriteLine("Done..");
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
static byte[] ImageToByte(Bitmap iImage)
{
MemoryStream mMemoryStream = new MemoryStream();
iImage.Save(mMemoryStream, System.Drawing.Imaging.ImageFormat.Png);
return mMemoryStream.ToArray();
}
}
Client
private static void SendCommand()
{
while (true)
{
Console.WriteLine("Please enter a command: ");
string userInput = Console.ReadLine();
//Convert out string message to a byteArray because we will send it as a buffer later.
byte[] bytesToSend = Encoding.Default.GetBytes(userInput);
//Write out to the console what we are sending.
Console.WriteLine("Sending: " + userInput);
//Use the networkstream to send the byteArray we just declared above, start at the offset of zero, and the size of the packet we are sending is the size of the messages length.
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//RecieveBuffer();
//Recieve the bytes that are coming from the other end (server) through the client and store them in an array.
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
//byte[] bitmap = GetYourImage();
//read the bytes, starting from the offset 0, and the size is what ever the client has recieved.
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
//Decode the bytes we just recieved using the Encoding.ASCII.GetString function and give it the correct parameters
//1. What it should decode
//2. Starting to decode from what offset
//3. How much do we want to decode?
Bitmap bmp;
using (var ms = new MemoryStream(bytesToRead))
{
bmp = new Bitmap(ms);
bmp.Save("Image.png");
}
//Console.WriteLine("Recieved: " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
}
Try MemoryStream.Seek(0, SeekOrigin.Begin) before sending stream to client. You may download 0 bytes, because stream at its end when you receive it.
I am trying to receive data at my server of any length through tcp connection. First my client sends length of data to server through stream.write then it send the actual data.
At Client I receive the length and loop until whole the data is received successfully.
The problem is: "I receive 0 size on the server no matters what the length of data is". I tried to figure out the issue but could not get where the problem is. Any kind of help/hint would be appreciated.
Server Side Code:
byte[] lengthOfData = new byte[2048];
byte[] buffer;
try
{
stream = client.GetStream();
eventLog1.WriteEntry("Size of 1st = "+stream.Read(lengthOfData,0,lengthOfData.Length));
int numBytesToRead = ByteArraySerializer.BytesArrayToInt(lengthOfData);
eventLog1.WriteEntry("number of bytes to read= "+numBytesToRead);
buffer = new byte[numBytesToRead+10];
int numBytesRead = 0;
do
{
int n = stream.Read(buffer, numBytesRead, 10);
numBytesRead += n;
numBytesToRead -= n;
eventLog1.WriteEntry("number of bytes read= " + numBytesRead);
} while (numBytesToRead > 0);
}
catch (Exception e) // Called automatically when Client Diposes or disconnects unexpectedly
{
eventLog1.WriteEntry("Connection Closes: "+e.ToString());
lock (connectedClients)
{
connectedClients.Remove(client);
}
client.Close();
break;
}
Client Side Code
byte[] command = ByteArraySerializer.Serialize<Command>(cmd);
byte[] sizeOfData = ByteArraySerializer.IntToBytesArray(command.Length);
stream.Write(sizeOfData, 0, sizeOfData.Length);
Console.WriteLine("Size of Data = "+command.Length);
stream.Write(command, 0, command.Length);
Change the following line at server
byte[] lengthOfData = new byte[2048];
to
byte[] lengthOfData = new byte[sizeof(int)];
The issue was that the read at server was supposed to read only 4 bytes integer whereas it was reading other data as well which was getting written after writing the length of data. We are supposed to read only 4 bytes if we want to get the length of data(integer).
I'm writting a FTP client in C# with a socket.
Now I have the following problem. When I send a FTP command through my control connection socket to the Server I try to receive the reply. But sometimes the server sends the data with delays.
My result are fragmented.
Now my code:
public byte[] BinaryReceive()
{
byte[] bytes;
using (MemoryStream memoryStream = new MemoryStream())
{
byte[] buffer = new byte[4056];
while (_controlConnectionSocket.Available > 0)
{
int count = _controlConnectionSocket.Receive(buffer, buffer.Length, SocketFlags.None);
memoryStream.Write(buffer, 0, count);
Thread.Sleep(100);
}
bytes = memoryStream.ToArray();
}
return bytes;
}
How can I avoid this situation? Currenty I implemented the Thread.Sleep() a as workaround. But this can not be the solution.
Any suggestion would be appreciated.
Edit:
I solved the problem. The key is, not to use Available > 0 instead I wait for the reply end. Than it works..