How to maintain connection in Socket after using NetworkStream c# - c#

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;
}
}

Related

How to detect end of file transfer in c# tcplistener

I want to listen for a file send to me. In order to do this I wrote the following code:
private void Listen()
{
IPAddress localip = new IPAddress(new byte[] { 127,0,0,1 });
Console.WriteLine("now listing, IP: " + localip);
var listener = new TcpListener(new IPEndPoint(localip, 5678));
listener.Start();
while (true)
{
using (var client = listener.AcceptTcpClient())
using (var stream = client.GetStream())
using (var output = File.Create("result.data"))
{
Console.WriteLine("Client connected. Starting to receive the file");
var buffer = new byte[1024];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
Console.WriteLine("done receiving message");
}
}
}
}
Now this works fine but once I have received the file the code hangs on the line while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) rather than continue to the line Console.WriteLine("done receiving message");. So rather than detecting that it's reading 0 bytes (and thus no longer satisfying the conditions of the while loop) it instead hangs. When I try to inspect it in a debugger it gives me the error
stream.DataAvailable
Cannot evaluate expression because a native frame is on the top of the call stack.
Anyone know how to fix this?

Sending and receiving images via a socket

I have a C# desktop app. It connects to another PC on my network which is a UWP C# app.
I am trying to send an image or 2 to my listening socket and to test this I get the listening socket to send me the image back.
The trouble is that even though my server recieves all the bytes that were orginally sent the recieved image back to the client is not of the same size.
To make this even more weird is sometimes the returned bytes are correct and I get the whole image and when I attempt to send 2 images the 1st one is OK and the 2nd one is not.
Then it will/can revert back to no images being sent back correctly.
I think is maybe to do with the async/await parts bit I am not sure how.
This is my server code:
using (IInputStream input = args.Socket.InputStream)
{
byte[] data = new byte[BufferSize];
IBuffer buffer = data.AsBuffer();
uint dataRead = BufferSize;
while (dataRead == BufferSize)
{
await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);
requestInBytes.AddRange(data.Take((int) buffer.Length));
dataRead = buffer.Length;
}
}
var ct = requestInBytes.Count;
I then trip out the header info:
int counter = 0;
counter = requestCommand[0].Length;
counter = counter + requestCommand[1].Length;
counter = counter + requestCommand[2].Length;
counter = counter + requestCommand[3].Length;
counter = counter + requestCommand[4].Length;
counter = counter + requestCommand[5].Length;
counter = counter + 6;
Now I extract the image:
var imgBody = new byte[totalBytes.Length- counter];
System.Buffer.BlockCopy(totalBytes, counter, imgBody, 0, imgBody.Length);
byteArray = imgBody;
And send just the image back:
using (IOutputStream output = args.Socket.OutputStream)
{
using (Stream response = output.AsStreamForWrite())
{
MemoryStream stream = new MemoryStream(byteArray);
await response.WriteAsync(byteArray, 0, byteArray.Length);
await response.FlushAsync();
}
}
This is my client code:
StringBuilder sb = new StringBuilder();
foreach (var gallery in Shared.CurrentJobGallery)
{
try
{
sb.Clear();
sb.Append(GeneralTags.ACTION_ADD);
sb.Append(Shared.DLE);
sb.Append("GALLERY");
sb.Append(Shared.DLE);
sb.Append(Shared.CurrentClientId);
sb.Append(Shared.DLE);
sb.Append(gallery.Title);
sb.Append(Shared.DLE);
sb.Append(gallery.Description);
sb.Append(Shared.DLE);
sb.Append(jobRef);
sb.Append(Shared.DLE);
byte[] galleryHdr = Encoding.UTF8.GetBytes(sb.ToString());
byte[] byteArray = new byte[galleryHdr.Length + gallery.ImageData.Length];
Buffer.BlockCopy(galleryHdr, 0, byteArray, 0, galleryHdr.Length);
Buffer.BlockCopy(gallery.ImageData, 0, byteArray, galleryHdr.Length, gallery.ImageData.Length);
List<byte> requestInBytes2 = new List<byte>();
System.Diagnostics.Debug.WriteLine("SENT: " + gallery.ImageData.Length.ToString());
using (TcpClient clientSocket = new TcpClient())
{
await clientSocket.ConnectAsync(GeneralTags.RASPBERRY_PI_IP_ADDRESS, GeneralTags.RASPBERRY_PI_PORT);
using (NetworkStream serverStream = clientSocket.GetStream())
{
List<byte> requestInBytes = new List<byte>();
serverStream.Write(byteArray, 0, byteArray.Length);
serverStream.Flush();
int i;
Byte[] bytes = new Byte[1024];
do
{
i = serverStream.Read(bytes, 0, bytes.Length);
byte[] receivedBuffer = new byte[i];
Array.Copy(bytes, receivedBuffer, i);
requestInBytes2.AddRange(receivedBuffer);
} while (serverStream.DataAvailable);
}
}
using (MemoryStream ms = new MemoryStream())
{
System.Diagnostics.Debug.WriteLine("BACK: " + requestInBytes2.Count.ToString());
ms.Write(requestInBytes2.ToArray(), 0, requestInBytes2.ToArray().Length);
Shared.ViewImage(Image.FromStream(ms, true));
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
Your problem is that TCP sockets are based around streams, not packets. It's true that "on the wire" everything is a packet, but when you're using TCP, you have no control over how the data is split up into packets or is reassembled into a stream.
In particular, this line of code is incorrect:
await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);
According to the docs, you must use the buffer returned from ReadAsync. Also note that this buffer may be a partial image, and it's up to your code to detect that situation, read more if necessary, and append those blocks together. Also, the buffer may contain part of one image and part of the next image; it's also up to your code to detect that and handle it correctly.
For this reason, most TCP applications use some form of message framing (described in more detail on my blog). Note that getting this right is surprisingly hard.
I strongly recommend that you use SignalR instead of raw TCP sockets. SignalR handles message framing for you, and it is capable of self-hosting (i.e., it does not require ASP.NET).

c# Socket Randomly Stops Receiving

This question may be very hard to answer or perhaps somebody knows a common reason.
I have 1 server, 5 clients;
Socket client
Socket listener
Every 5000 MS the client checks for a file on the server (Which is Windows 7)via socket, if found the client received the file via socket.
I understand only Windows Server can process more than two asynch file transfers at a time.
My issue is that, randomly the client begins to receive the file. All clients generally work fine. Once in a while, a client will stop receiving the file partthrough and not complete the file transfer and my client program just hangs and never finishes.
I can NOT reproduce this on development environment. I have tested it with half-gig files, 100's of sends and I never get an error.
My question is , is it possible that there is some protocol on Windows 7 that is stopping my file send from the server.
My Receive call back for the client is quite lengthy, but here it is. I do not believe the problem to be within the code.
Any help would be greatly appreciated. My boss is about to have my neck :(
private static void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
state.totalBytesRead += bytesRead;
if (bytesRead > 0)
{
if (state.flag == 0)
{
if (state.totalBytesRead >= 8)
{
// we know we put the msgLen / prefixLen as the first 8 bytes on the stream
state.msgLen = BitConverter.ToInt32(state.buffer, 0);
state.prefixLen = BitConverter.ToInt32(state.buffer, 4);
state.flag = 1;
// good to process the first 2 integer values on the stream
//state.sb.Append(Encoding.ASCII.GetString(state.buffer, 8, bytesRead));
int prefixRequestBytes = state.prefixLen;
if (prefixRequestBytes > StateObject.BufferSize)
prefixRequestBytes = StateObject.BufferSize;
state.lastSendByteCount = prefixRequestBytes;
state.totalBytesRead = 0;
// start re-writing to the begining of the buffer since we saved
client.BeginReceive(state.buffer, 0, prefixRequestBytes, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
else
{
int bytesToSend = state.lastSendByteCount - bytesRead;
state.lastSendByteCount = bytesToSend;
// need to receive atleast first 8 bytes to continue
// Get the rest of the data.
client.BeginReceive(state.buffer, state.totalBytesRead, bytesToSend, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
}
if (state.flag == 1)
{
// we are expexing to process the prefix
if (state.totalBytesRead >= state.prefixLen)
{
// we are good to process
// Lets always assume that our prefixMsg can fit into our prefixbuffer ( we wont send greater than prefixbuffer)
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.prefixLen));
string prefixMsg = state.sb.ToString();
if (!String.IsNullOrEmpty(prefixMsg))
{
state.cmd = parseXml("CMD", prefixMsg);
state.fName = parseXml("FNAME", prefixMsg);
// File requester should never get a del command
//if (state.cmd == "DEL")
//{
// Console.WriteLine("Processing 'DEL' command..");
// // delete the file
// string filePath = "C:\\" + locationFolder + "\\" + state.fName;
// if (System.IO.File.Exists(filePath))
// {
// System.IO.File.Delete(filePath);
// }
// Console.WriteLine("Deleted file");
// // receiveDone.Set();
// requestTimer.Start();
// return;
//}
//else
if (state.cmd == "SND")
{
Console.WriteLine("Processing 'SND' command..");
// let it rip
if (state.msgLen == 0) // no files
{
Console.WriteLine("No files on server");
requestTimer.Start();
return;
}
}
}
state.receivedPath = importTempFolder + state.fName;
// receive the rest of the file
if (System.IO.File.Exists(state.receivedPath))
{
Console.WriteLine("Deleting temp file: " + state.receivedPath + " for re-write");
System.IO.File.Delete(state.receivedPath);
}
state.flag++;
int msgRequestBytes = state.msgLen;
if (msgRequestBytes > StateObject.BufferSize)
msgRequestBytes = StateObject.BufferSize;
state.lastSendByteCount = msgRequestBytes;
state.totalBytesRead = 0;
// should be good to process the msg now
// start re-writing to the begining of the buffer since we saved
client.BeginReceive(state.buffer, 0, msgRequestBytes, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
else
{
int bytesToSend = state.lastSendByteCount - bytesRead;
state.lastSendByteCount = bytesToSend;
// request the rest of the prefix
// Get the rest of the data.
client.BeginReceive(state.buffer, state.totalBytesRead, bytesToSend, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
}
// we are expecting to process the file
if (state.flag > 1)
{
if (state.totalBytesRead >= state.msgLen)
{
Console.WriteLine("Writing final {0} bytes to server", bytesRead);
using (FileStream fs = new FileStream(state.receivedPath, FileMode.Append, FileAccess.Write))
using (BinaryWriter writer = new BinaryWriter(fs))
{
//BinaryWriter writer = new BinaryWriter(File.Open(state.receivedPath, FileMode.Append, FileAccess.Write, FileShare.None));
writer.Write(state.buffer, 0, bytesRead);
fs.Flush();
// writer.Close();
}
// GC.Collect();
// if temp folder exists, import will exists because its inside it
string destFile = importFolder + state.fName;
if (System.IO.File.Exists(destFile))
{
Console.WriteLine("Deleting file for re-write in importin: \n" + destFile);
System.IO.File.Delete(destFile);
}
Console.WriteLine("Moving file: \n" + state.receivedPath);
System.IO.File.Copy(state.receivedPath, destFile);
Console.WriteLine("Deleting file from temp: \n" + state.receivedPath + importTempFolder + state.fName);
System.IO.File.Delete(state.receivedPath);
if (state.cmd == "SND")
{
Console.WriteLine("Sending 'DEL' command.");
SendDeleteResponse(client, state.fName);
Console.WriteLine("Finished reading to file: " + state.receivedPath);
// receiveDone.Set();
requestTimer.Start();
return;
}
Console.WriteLine("Finished reading file");
client.Shutdown(SocketShutdown.Both);
client.Close();
// receiveDone.Set();
requestTimer.Start();
}
else
{
//Console.WriteLine("Reading {0} bytes from server...", bytesRead);
// Padd these bytes
using (FileStream fs = new FileStream(state.receivedPath, FileMode.Append, FileAccess.Write))
using (BinaryWriter writer = new BinaryWriter(fs))
{
//BinaryWriter writer = new BinaryWriter(File.Open(state.receivedPath, FileMode.Append, FileAccess.Write, FileShare.None));
writer.Write(state.buffer, 0, bytesRead);
fs.Flush();
// writer.Close();
}
// GC.Collect();
// get how many more bytes are left to read
int bytesToSend = state.msgLen - bytesRead;
if (bytesToSend > StateObject.BufferSize)
bytesToSend = StateObject.BufferSize;
client.BeginReceive(state.buffer, 0, bytesToSend, 0, new AsyncCallback(ReceiveCallback), state);
return;
}
}
}
else
{
// All the data has arrived;
}
}
catch (Exception e)
{
Console.WriteLine("HERE5 " + e.Message);
client.Close();
// receiveDone.Set();
requestTimer.Start();
return;
}
}

Reading a C# byte array in Java

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>

setting NetworkStream.ReceiveTimeout not triggering exception

This is a continuation of the this question. I am new to network programming, so I am just writing small sample stuff to gain understanding, but somewhat struggling with explaining results.
It seems setting NetworkStream.ReceiveTimeout is not working correctly when client that was supposed to be sending data simply closes before sending all the expected data.
Here is the sample code:
public static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 10001);
listener.Start();
ThreadPool.QueueUserWorkItem(WriterThread);
using (TcpClient client = listener.AcceptTcpClient())
using (NetworkStream stream = client.GetStream())
{
client.ReceiveTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
stream.ReadTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
ReceiveMessage(stream, 1024);
}
listener.Stop();
Console.WriteLine("Done.");
Console.ReadKey(true);
}
private static void WriterThread(object state)
{
using (TcpClient client = new TcpClient())
{
client.Connect(new IPEndPoint(IPAddress.Loopback, 10001));
using (NetworkStream stream = client.GetStream())
{
byte[] bytes = Encoding.ASCII.GetBytes("obviously less than 1024 bytes");
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(10000); // comment out
}
}
}
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
bufferFill += stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
This version works correctly triggering exception on the stream.Read() call. However If I comment out Thread.Sleep(10000), the client closes connection, but listener fails to recognize it. Main thread gets stuck inside the while(true) loop. The stream.Read() keeps returning zero, but no exception thrown.
Is this normal? If so how am I expected to handle abnormal client disconnections?
Yes, this sounds normal. There is no receive- or read timeout because the client has disconnected. This means that no more data is available for reading and the stream will return 0 immediately just as documented.
I would modify your ReceiveMessage method to something like the following:
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
int bytesRead = stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (bytesRead == 0)
throw new Exception("No more data available.");
bufferFill += bytesRead;
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
Clearly if the stream.Read() call returns 0 before we have received all the expected bytes there must have been some form of disconnection or similar. Either way we will never get any more data from the stream.
Edit: The Stream class has no notion of a "message". The Read method blocks until more data becomes available if none is already in the buffer. It will however return 0 when no more data can be received, which in this case means the connection is closed.

Categories

Resources