streamreader readline blocking tcp many clients c# - c#

I have written a TCP chat in C# WPF for one client and server (it works). Now I would like to extend this program to have many clients in chat.
client code: http://pastebin.com/Zv1Me6P4
server code: http://pastebin.com/VYBJCA9f
I was checking everything and I guess that streamreader readline fails.
In my program, client sends message to server, which sends to everybody and appears message in their TextBoxs.
How my program works:
Start server
Connect Client1, Client2
Client1 sends message "a" ... nothing happens
Client1 sends message "b" ... nothing happens
Client2 sends message "c" ... both clients got "ac"
Streamreader blocks and I dont know how to unblock it. Okay, I can use new thread; +1 client = +1 thread, but it sounds so strange. I was really reading stackOverFlow and I found sth like: while((line = reader.ReadLine()) != null) or !reader.EndOfStream or reader.pike > 0.. all that doesn't work... or I do it incorrenctly.
Reading my code you can be confused:
in client program there is some server ( it's old overwritten project )
I create for every clients new Reader and Writer Stream; I got to know that I can use one R/W Stream but I couldn't use it however.. Because I use List list so: reader(list.getByte()) does't work.
I beg you please help me. It's small unsolved piece of my work, which makes me upset. I love programming when problems are resonable and possible to solve.
Thanks for all comment under my post.

I had a similar problem not being able to ReadLine and ReadToEnd would exceed my timeouts. This worked for me
string line = "";
while (reader.Peek() > -1) {
line += (char)reader.Read();
}

Related

Client stops working after sending message and server doesn't wait for mutliple data to come

I've recently started learning about computer networks and decieded to try TCP/IP server and client. They both work, but I'm having issues with sending mutliple data to the server. I've made it to look like a chat service between clients but the server accepts only one client and closes the connection after the data is sent and the client for some reason stops responding after sending data to server (I think the problem comes from the server and not the client itself), no error message, only on the server side when I force close the client.
This is how my server looks like...
static void Main(string[] args)
{
//User can define port
Console.WriteLine("open a port:");
string userInputPort = Console.ReadLine();
//listening for connections
TcpListener listener = new TcpListener(System.Net.IPAddress.Any, Convert.ToInt32(userInputPort));
listener.Start();
Console.WriteLine("listening...");
while (true)
{
//waiting for client to connect to server
Console.WriteLine("Waiting for connection...");
//when user connects to server, server will accept any request
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client Accepted");
NetworkStream stream = client.GetStream();
StreamReader streamR = new StreamReader(client.GetStream());
StreamWriter streamW = new StreamWriter(client.GetStream());
while (true)
{
if(client.Connected)
{
if (stream.CanRead)
{
//buffer
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
int recv = 0;
foreach (byte b in buffer)
{
if(b != 0)
{
recv++;
}
}
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine("request recived: " + request);
streamW.Flush();
}
}
}
}
}
}
}
and this is how the client looks like...
...
try
{
//try to connect
client = new TcpClient(textBoxIP.Text, Convert.ToInt32(textBoxPort.Text));
}
...
static void sendMessage(string message, TcpClient client)
{
int byteCount = Encoding.ASCII.GetByteCount(message);
byte[] sendData = new byte[byteCount];
sendData = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
stream.Write(sendData, 0, sendData.Length);
StreamReader streamReader = new StreamReader(stream);
string respone = streamReader.ReadLine();
stream.Close();
client.Close();
}
Like I said, I'm still learning about computer networking and any comment to this code will help!
Thank you
It helps if you give yourself some idea of what you're actually expecting from the code you're writing. It seems to me that you make a lot of automatic assumptions without actually making sure to put them in your code.
Your server can only ever at best accept a single client. Not one client at a time, but one ever. You never exit from your reading loop, so after the client disconnects, you end up in a wonderful infinite busy loop. Your intent was probably to serve another client when one disconnects, but that's not what you're doing.
You assume the server will send a response to the client. But you never actually send any response! For a client to read something, the server first must send something for the client to read.
You assume the string sent by the client will be zero-terminated, or that the target buffer for Read will be zeroed. If you want zero-termination, you have to send it yourself from the client - the StreamWriter certainly doesn't do that. Strings aren't zero-terminated as a rule - it's just one C-style way of representing strings in memory. You shouldn't assume anything about the contents of the buffer beyond what the return value from Read tells you was returned.
Those are issues with things you forgot to quite put in, presumably. Now to the incorrect assumptions on part of how TCP works. To keep clarity, I will tell the way it is, rather than the incorrect assumption.
A single write can result in multiple reads on the other side, and a single read can read data from multiple writes on the other side. TCP doesn't send (and receive) messages, it deals with streams. You need to add a messaging protocol on top of that if streams aren't good enough for you.
Read returns how many bytes were read. Use that to process the response, instead of looking for a zero. When Read returns a zero, it means the connection has been closed, and you should close your side as well. This is all that you need, instead of all the while (true), if (Connected) and if (CanRead) - loop until Read returns zero. Process data you get as it gets to you.
The TCP stream is a bit trickier to work with than most streams; it behaves differently enough that using helpers like StreamReader is dangerous. You have to do the work yourself, or get a higher-abstraction library to work with networking. TCP is very low level.
You cannot rely on getting a response to a Read. TCP uses connections, but it doesn't do anything to keep the connection alive on its own, or notice when it is down - it was designed for a very different internet than today's, and it can happily survive interruptions of service for hours - as long as you don't try to send anything. If the client disconnects abruptly, the server might never know.
You should also make sure to clean up all the native resources properly - it really helps to use using whenever possible. .NET will clean up eventually, but for things like I/O, that's often dangerously late.
while (true)
{
if(client.Connected)
{
if (stream.CanRead)
{
I don't see any code, that exits the outer while the loop if either client.Connected or stream.CanRead become false. So, when the client disconnects and they become false, it seems to me that the server just loops forever.
You should at least do all error handling (close all necessary streams) and break out of the loop.
As the next problem, you code can only have one client at a time. If the client is not actually closing the connection. I do not know for sure what the correct C# solution is, but i think it is spawning a separate thread for each connected client.

C# streamreader readtoend freeze up

I have the following code to read the time from time.nist.gov:
TcpClient client = new TcpClient();
var result = client.BeginConnect("129.6.15.28", 13, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success || !client.Connected)
// Timeout
else{
streamReader = new StreamReader(client.GetStream());
var response = streamReader.ReadToEnd();
//code
}
The problem is that sometimes ReadToEnd get frozen indefinitely, I assume because it does not reach and end.
Is it possible to set a timeout for this operation?
Or maybe a better option to read the server response?
Thanks.
According to MSDN:
ReadToEnd assumes that the stream knows when it has reached an end. For interactive protocols in which the server sends data only when you ask for it and does not close the connection, ReadToEnd might block indefinitely because it does not reach an end, and should be avoided.
Do you know how much you're reading? If so, you can use Read().
EDIT:
I tested this code (well, something very similar) and found that ReadToEnd works fine, unless port 13 is blocked, in which case it also runs without returning for me as well. So, check your firewall before doing this.
Better is Hans's suggestion of using an existing, well-tested NTP lib.

issue with getting TcpClient server response as string

so long story short, i am trying to develop an application which requires having Tcp Connection to a server. having no previous experiance in this field i ended up with having none of my functions working. so i decided to make a simple console app just to check my commands and their responses. the part about setting up the connections went well, so does the part about wrting into network stream(i think) but i hit a wall when trying to display server respons:
each time my porgram reaches the line where it has to Encode server respons and WriteLine, my console application goes all black and all texts goes away. can you tell what's wrong with the code i am using?everything up until the part where console trys to display response goes well, i checked. i want to have server's respones as normal strings(if possible i guess...)
static void ServerTalk(TcpClient tcpClient,NetworkStream networkStream, StreamWriter streamWriter, StreamReader streamReader)
{
//Messaging methods:
Console.WriteLine("Client: ");
string message = Console.ReadLine();
streamWriter.WriteLine(message);
streamWriter.Flush();
//Response methode:
byte[] data = new byte[tcpClient.ReceiveBufferSize];
int ret = networkStream.Read(data, 0, data.Length);
string respond = Encoding.ASCII.GetString(data).TrimEnd();
Console.WriteLine("Server: ");
Console.WriteLine(respond);
ServerTalk(tcpClient, networkStream, streamWriter, streamReader);
}
you need to process only ret bytes, you are translating all bytes in the array.
copy to a new array that is 'ret' long and then decode.
var retarr = new byte[ret];
Array.Copy(data,retarr,ret);
string respond = Encoding.ASCII.GetString(retarr);
More importantly note that this method of tcp communication is not going to work. You are assuming that when you send x bytes in one block you will receive x bytes in one block, this is not so, you can send 1 100 byte message and receive 100 1 byte messages
This means that you task is much more complex. YOu need to devise a way of sending self describing data - so that you know its completely received. classically you send a length followed by the data. You then keep looping in the receive code till you have received that many bytes

AS3 sockets and policy file request to a C# server

This problem is driving me crazy! I've read all the questions on Stack Overflow but I'm still stuck.
My as3 program works very well, but when I have finished it and put it on a server, it starts to request this famous policy file.
AS3 script:
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecError);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
socket.connect( MYHOST, 4242 );
C# server code:
TcpListener serverSocket = new TcpListener(4242);
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
clientSocket = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
StreamReader read = new StreamReader(networkStream, Encoding.UTF8);
StreamWriter write = new StreamWriter(networkStream, Encoding.UTF8);
response = read.ReadLine();
if (response.Contains("policy"))
{
write.Write("<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\0");
write.Flush();
clientSocket.Close();
return;
}
So, when the AS3 doesn't find the policy on the default port 843 (or something similar), it asks directly on the same socket as the connection.
My C# code sees the request and replies, after which the AS3 script closes the connection (which is OK), but it never reconnects.
I have tried to put this in the AS3 before the connect():
Security.loadPolicyFile( "xmlsocket://myhost.com:4242");
But when I do the connect() it simply gets stuck and never requests the policy file. After I close the AS3 application, my server sees the request, but the connection is closed. It's like the client forget to do a flush.
Can someone tell me how I can solve this problem correctly?
After 3 days i have finally discovered what is the bug in the code.
A bounty of 50 points and no one have noticed it :-(
Is very stupid, a novice error:
When the flash application ask for the policy file dont send the newline char, but the terminating char '\0'.
and im reading with the read.ReadLine(); that read until the '\n', so it stuck.
Thank you all for your replies.
I've faced a problem similar to your's. The fact is, that while running a Flash app into a C#, it lose lot's of requests which port differs from standart. The solution is not to use such requests in Flash. So you have to put them into C#, and call this functions with Flash's ExternalInterface.call. When the request is completed, your C# must call a Flash function, passing req's answer as a parameter.

Sockets on Windows - did I miss something in my program?

Thanks for reading and answering in advance!
I wrote a simple C# program that connects via sockets with a third-party tool. Whenever I send a string longer than 1024 characters, the third-party software throws an error. Now I am trying to find out if this is a problem of my socket code or one of the other software (EnergyPlus).
It is only a few lines of code, and if anyone has suggestions, they would be highly appreciated!
using System.IO;
using System.Net;
using System.Net.Sockets;
...
private int port = 1410;
private TcpListener listener;
private Stream s;
private StreamReader sr;
private StreamWriter sw;
private Socket soc;
...
Here it really starts:
listener = new TcpListener(port);
listener.Start();
soc = listener.AcceptSocket();
// now, the other program connects
soc.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, 10000);
s = new NetworkStream(soc);
sr = new StreamReader(s);
sw = new StreamWriter(s);
sw.AutoFlush = true; // enable automatic flushing
sw.WriteLine("more or less than 1024 characters");
...
This is the code I use. Anything I forgot? Anything I should take care of?
I am glad about any suggestions.
The error I get from E+ is the following:
ExternalInterface: Socket communication received error value " 1" at time = 0.00 hours.
ExternalInterface: Flag from server " 0".
Yu need to look at the specification defined by EnergyPlus; any socket communication needs rules. There are two obvious options here:
you aren't following the rules (maybe it is limited length, or maybe you need to write special marker bytes for this scenario)
their server code doesn't implement the specification correctly (biggest causes are: buffer issues, or: assuming a logical frame arrives in a single network packet)
Actually, I find it interesting that it is doing anything yet, as there is no obvious "frame" there; TCP is a stream, so you ususally need frames to divide logical messages. This usually means one of:
a length prefix, with or without other header data
a cr/lf/crlf terminator (or other terminator), usually for text-based protocols
closing the socket (the ultimate terminator)
You do none of those, so in any server I write, that would be an incomplete message until something else happens. It sounds text-based; I'd try adding a cr/lf/crlf

Categories