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.
Related
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.
In C# you have 3 ways to try and receive TCP data on a Socket:
Socket.Receive is a synchronous, blocking method. It doesn't return until it succeeds, barring failure or [optionally] timeout.
Socket.BeginReceive is asynchronous, a supplied callback/delegate is called when there is data to receive, using the now-antiquated Begin/End pattern
Socket.ReceiveAsync begins an asynchronous request to receive data
However my understanding is none of these actually let you cancel the receive operation? The docs suggest EndReceive is used for completing a read, not something one could call to terminate the request?
You often see code like
while(socket.Available==0 && !cancel)Sleep(50); if(!cancel)socket.Receive(...);
But that's pretty terrible.
If I want to sit waiting for data but at some point cancel the receive, say the user hits "stop" button how can this neatly be done so I don't get a callback triggered later on when unexpected?
I had wondered about closing the socket, which would cause the Receive operation to fail, but it seems somewhat ugly. Am I thinking along the right lines or do the various API methods listed above allow a direct cancellation so I don't risk dangling async operations?
There is no known way to cancel it (AFAIK)
One thing you can do it set the Socket.Blocking = false. The receive will return immediately when there is no data. This way it will not hang.
You should check the Socket.Blocking property.
I advise you to use the BeginReceive(IList<ArraySegment<Byte>>, SocketFlags, SocketError, AsyncCallback, Object) overload to prevent it throwing exceptions.
Check the SocketError on "Would Block", meaning "there is not data". So you can try again.
Didn't tested it but ->
A nice idea is using the non-async version Receive to receive 0 bytes (use a static byte[] emptyBuffer = new byte[0]) , and if the sockerError returns with a 'would block', you can have a short delay and retry it. When it doesn't return a socketError there is probably data. So you can start an async version.
What you could do is get a NetworkStream from the socket being read and use it's ReadTimeout property, for example:
// Get stream from socket:
using NetworkStream ns = new NetworkStream(socket);
// Set timeout:
stream.ReadTimeout = 10 * 1000; // 10 sec
var buffer = new List<byte>();
try
{
do
{
buffer.Add((byte) stream.ReadByte());
}
while (stream.DataAvailable);
}
catch (IOException)
{
// Timeout
}
return buffer.ToArray();
I have a web-service using HttpListener.
I have noticed this thing:
HttpListenerContext context = listener.GetContext();
...
context.Response.StatusCode = 200;
context.Response.OutputStream.Write(buffer, 0, bufferSize);
context.Response.StatusCode = 500;
context.Response.OutputStream.Close();
A client in this case receives a status code 200, so if i have wrote some data to the output network stream i can't change the status code, as, i suppose, it is already written to the response stream.
What i want: after i have started writing a response to the output stream, in some case i want to "abort and reset" the response, clear the output stream (so the client won't receive any data in HTTP response body), and change the status code.
I have no idea how to clear the output stream and change the status code. These two lines below won't help, they throw exceptions.
context.Response.OutputStream.SetLength(0);
context.Response.OutputStream.Position = 0;
I suppose, what the program writes buffer data into network device after i call context.Response.OutputStream.Close(), until this the data is stored in RAM and we can reset it, can't we?
EDIT: It seems what writing into the context.Response.OutputStream takes too much of time sometimes, in some case. From 100 to 1000 ms... That's why i would just interrupt writing, if it's possible.
You either could use a MemoryStream to cache the answer, and if you are sure it is complete, set the status to 200 and return it (e.g. with Stream.CopyTo).
You can't "clear" the OutputStream, since it isn't stored (for long), instead it is sent right away to the client, so you can't edit it anymore.
Apart from that, HTTP does not offer a way to gracefully say "DATADATADATA... oh forget that, this was wrong, use the Status Code 500 instead.". You only can try to kill the TCP connection (TCP RST instead of TCP FIN) and hope that the client will handle failing to continue reading on the connection in a suitable way, after it probably already started to process the data you've already sent.
Try context.Response.Abort() before closing, this won't allow you to set a status code, but will at least communicate that something went wrong.
Im trying to do automation over SSH but the server is faulty and does not implement exec channel properly so I ended up doing a workaround using CreateShellStream(). I can expect that upon running the program a connection wouldnt be available and disconnections are a thing. My solution:
while(!_cancellationToken.IsCancellationRequested))
{
ShellStream stream = null;
while(stream == null)
{
stream = await GetSshStream();
}
while(stream.CanWrite && stream.CanRead)
{
stream.WriteLine(command);
//this breaks everything if stream is not valid
var rep = stream.Expect(new Regex(#"[$>]"));
var delimiters = new[] { " ", "\r\n", "\t" };
var values = rep.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
DealWithValues(values);
}
}
This works and waits for connection and once connected starts coms. The problem arises with that stream.CanWrite && stream.CanRead is not enough to detect that stream is healthy and once connection is lost and stream becomes invalid and used with Expect(); everything breaks. Jumps out of all loops, goes through try {} catch{} and even makes Visual Studio debugger steping break down and continue the program in another thread (multi threaded program). Is there a way to stop this from happening and throwing execution back to first while? I could possibly create a new stream every time I need access to the server but since Im polling parameters about once a second I wouldnt want to have the overhead of reconnecting each time.
I misundertood that thread dissapearing ment code execution stopped. Instead thread sleeps waiting for input. Expect has a timeout overload and I should of been using it.
I am batch uploading products to a database.
I am download the image urls to the site to be used for the products.
The code I written works fine for the first 25 iterations (always that number for some reason), but then throws me a System.Net.WebException "The operation has timed out".
if (!File.Exists(localFilename))
{
using (WebClient Client = new WebClient())
{
Client.DownloadFile(remoteFilename, localFilename);
}
}
I checked the remote url it was requesting and it is a valid image url that returns an image.
Also, when I step through it with the debugger, I don't get the timeout error.
HELP! ;)
If I were in your shoes, here's a few possibilities I'd investigate:
if you're running this code from multiple threads, you may be bumping up against the System.Net.ServicePointManager.DefaultConnectionLimit property. Try increasing it to 50-100 when you start up your app. note that I don't think this is your problem, but trying this is easier than the other stuff below. :-)
another possibility is that you're swamping the server. This is usually hard to do with a single-threaded client, but is possible since multiple other clients may be hitting the server also. But because the problem always happens at #25, this seems unlikely since you'd expect to see more variation.
you may be running into a problem with keepalive HTTP connections backing up between your client and the server. this also seems unlikely.
the hard cutoff of 25 makes me think that this may be a proxy or firewall limit, either on your end or the server's, where >25 connections made from one client IP to one server (or proxy) will get throttled.
My money is on the latter one, since the fact that it always breaks at a nice round number of requests, and that stepping in the debugger (aka slower!) doesn't trigger the problem.
To test all this, I'd start with the easy thing: stick in a delay (Thread.Sleep) before each HTTP call, and see if the problem goes away. If it does, reduce the delay until the problem comes back. If it doesn't, increase the delay up to a large number (e.g. 10 seconds) until the problem goes away. If it doesn't go away with a 10 second delay, that's truly a mystery and I'd need more info to diagnose.
If it does go away with a delay, then you need to figure out why-- and whether the limit is permanent (e.g. server's firewall which you can't change) or something you can change. To get more info, you'll want to time the requests (e.g. check DateTime.Now before and after each call) to see if you see a pattern. If the timings are all consistent and suddenly get huge, that suggests a network/firewall/proxy throttling. If the timings gradually increase, that suggests a server you're gradually overloading and lengthening its request queue.
In addition to timing the requests, I'd set the timeout of your webclient calls to be longer, so you can figure out if the timeout is infinite or just a bit longer than the default. To do this, you'll need an alternative to the WebClient class, since it doesn't support a timeout. This thread on MSDN Forums has a reasonable alternative code sample.
An alternative to adding timing in your code is to use Fiddler:
download fiddler and start it up.
set your webclient code's Proxy property to point to the fiddler proxy (localhost:8888)
run your app and look at fiddler.
it seems that WebClient is not closing the Response object it uses when done which will cause, in your case, many responses to be opened at the same time and with a limit of 25 connections on the remote server, you got the 'Timeout exception'. When you debug, early opened reponses get closed due to their inner timeout, etc...
(I inpected WebClient that with Reflector, I can't find an instruction for closing the response).
I propse that you use HttpWebRequest & HttpWebResponse so that you can clean objects after each download:
HttpWebRequest request;
HttpWebResponse response = null;
try
{
FileStream fs;
Stream s;
byte[] read;
int count;
read = new byte[256];
request = (HttpWebRequest)WebRequest.Create(remoteFilename);
request.Timeout = 30000;
request.AllowWriteStreamBuffering = false;
response = (HttpWebResponse)request.GetResponse();
s = response.GetResponseStream();
fs = new FileStream(localFilename, FileMode.Create);
while((count = s.Read(read, 0, read.Length))> 0)
{
fs.Write(read, 0, count);
count = s.Read(read, 0, read.Length);
}
fs.Close();
s.Close();
}
catch (System.Net.WebException)
{
//....
}finally
{
//Close Response
if (response != null)
response.Close();
}
Here's a slightly simplified version of manji's answer:
private static void DownloadFile(Uri remoteUri, string localPath)
{
var request = (HttpWebRequest)WebRequest.Create(remoteUri);
request.Timeout = 30000;
request.AllowWriteStreamBuffering = false;
using (var response = (HttpWebResponse)request.GetResponse())
using (var s = response.GetResponseStream())
using (var fs = new FileStream(localPath, FileMode.Create))
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = s.Read(buffer, 0, buffer.Length)) > 0)
{
fs.Write(buffer, 0, bytesRead);
bytesRead = s.Read(buffer, 0, buffer.Length);
}
}
}
I have the same problem and I solve it adding this lines to the configuration file app.config:
<system.net>
<connectionManagement>
<add address="*" maxconnection="100" />
</connectionManagement>
</system.net>