I've read similar questions but I could not get the solutions to work. I have a Server that created a ClientManager that handles sending and writing data.
The critical part that is causing a bug is this are right here:
private void StartReceive(object sender, DoWorkEventArgs e)
{
String data = null;
Byte[] bytes = new Byte[256];
while (this.socket.Connected)
{
int i = stream.Read(bytes, 0, bytes.Length);
if (i != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
stream.Write(bytes, 0, bytes.Length);
Console.WriteLine("Sent: {0}", data);
}
else
{
break;
}
}
this.Disconnect();
}
Specifically this: int i = stream.Read(bytes, 0, bytes.Length);
My client is connected and sends a message, then I close the client application the server hangs on this line. I'm not sure how to handle a sudden disconnect, I assumed that the Read bytes would be 0 and it would disconnect out of the while loop, but I was mistaken.
Related
I have a "messenger" application that works like this:
Client Sends Message to Server -> Server forwards Message to rest of the clients -> Clients read the message.
The server always receives the messages, but the clients do not.
Code that forwards the message to all clients (Server/TcpListener):
public static void SendToAll(TcpClient sender, string message)
{
// Log the recieved message in the console
Console.WriteLine(message);
// Save the recieved message for new clients
messageLog += message + "\n";
byte[] msg = Encoding.ASCII.GetBytes(message);
foreach (TcpClient client in clients.Keys)
{
if (client == sender || clients[client] == "") continue;
if (!client.Connected)
{
clients.Remove(client);
continue;
}
NetworkStream stream = client.GetStream();
stream.Write(msg, 0, msg.Length);
}
}
Code that reads messages from the server (TcpClient):
byte[] buffer = new byte[1024];
while (true)
{
using (MemoryStream memoryStream = new MemoryStream())
{
Int32 bytes = 0;
do
{
bytes = stream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, bytes);
}
while (stream.DataAvailable);
Console.WriteLine(Encoding.ASCII.GetString(memoryStream.ToArray()));
}
Server (image attached)
Client1 (image attached)
Client2 (image attached)
Found the answer.
The problem was probably caused because TCP is slow; not entirely finished with reading all the stream and already tasked with reading new data.
So I Switched
byte[] buffer = new byte[1024];
while (true)
{
using (MemoryStream memoryStream = new MemoryStream())
{
Int32 bytes = 0;
do
{
bytes = stream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, bytes);
}
while (stream.DataAvailable);
Console.WriteLine(Encoding.ASCII.GetString(memoryStream.ToArray()));
}
to
// ... Main() {
while (true) StartRead();
// ... }
public static async void StartRead(NetworkStream stream)
{
byte[] buffer = new byte[1024];
Int32 bytesRead = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length));
string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine(message);
}
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?
I have created a TCP listener to receive data from a port. And I created a NetworkStream to read the coming data.
NetworkStream stream = new NetworkStream(TCPSocket);
Byte[] bytes = new Byte[128];
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
string msg = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("received: {0}", msg);
}
What I want to do is, if there is no data coming for 10 minutes, I want to close the stream. How can I do this? I have tried to use timer with creating a thread to call stream.close() after sometime, but nothing worked before it receive any data. Thanks in advance!
Try using:
stream.ReadTimeOut = 600000;
it is in milliseconds.
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.
I have a simple tcp/ip chat program with a server and client. The first time I send a packet, it makes it to the client but during the NetworkStream.Read it stops execution and doesn't throw an exception. The next packet I send is read and processed perfectly. Another weird thing I noticed is that MyNetworkStream.DataAvailable is always false even if I get information from the server so I have to put a debug symbol and skip over it. I wish I could post all my code but it is long so I will post where I read and write to the network stream.
public void Listen(int byteLength)
{
var buffer = new byte[byteLength];
MySocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Read), buffer);
}
private void Read(IAsyncResult ar)
{
while (MySocket.Connected)
{
MyNetworkStream = new NetworkStream(MySocket);
var buffer = new byte[((byte[])ar.AsyncState).Length];
if (!MyNetworkStream.DataAvailable)
throw new Exception("Data not available");
MyNetworkStream.Read(buffer, 0, buffer.Length); <------Here it stops execution without throwing an exception
string content = Encoding.ASCII.GetString(buffer);
if(OnRead == null)
continue;
var e = new CommandEventArgs( null, content);
Control target = null;
if (OnRead.Target is Control)
target = (Control)OnRead.Target;
if (target != null && target.InvokeRequired)
target.Invoke(OnRead, this, e);
else
OnRead(this,e);
}
}
public void Write(string message)
{
try
{
var buffer = Encoding.ASCII.GetBytes(message);
MySocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, null);
if (OnWrite != null)
{
var target = (Control)OnWrite.Target;
if (target != null && target.InvokeRequired)
{
target.Invoke(OnWrite, this, new EventArgs());
}
else
{
OnWrite(this, new EventArgs());
}
}
}
catch
{
}
}
BeginReceive asynchronously waits for a message and fills your buffer. You then start synchronously reading from the socket, overwriting the first message in the process.
You should call EndReceive which returns the number of bytes read, then process your buffer before trying to read more bytes.
I'm not sure if it's directly related to the problem, but you are using the Read method wrong. You are reading data into the buffer, but you are ignoring how much data was actually read assuming that the Read call always returns as much data as you request, so you are decoding the entire buffer eventhough it might not be completely filled.
Get the return value of the Read call so that you know how much of the buffer is actually filled with data:
int len = MyNetworkStream.Read(buffer, 0, buffer.Length);
string content = Encoding.ASCII.GetString(buffer, 0, len);
You need to implement EndRecieve to get the complete data from the stream. Checkout the following example from MSDN :
public static void Read_Callback(IAsyncResult ar){
StateObject so = (StateObject) ar.AsyncState;
Socket s = so.workSocket;
int read = s.EndReceive(ar);
if (read > 0) {
so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(Async_Send_Receive.Read_Callback), so);
}
else{
if (so.sb.Length > 1) {
//All of the data has been read, so displays it to the console
string strContent;
strContent = so.sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +
"data = {1} ", strContent.Length, strContent));
}
s.Close();
}
}