views:

829

answers:

3

Using a StreamWriter to write to a NetworkStream, and a StreamReader to read the response. The app is sending commands and reading responses to a news server.

Simplified code (sans error handling, etc.):

tcpClient = new TcpClient();
tcpClient.Connect(Name, Port);

networkStream = tcpClient.GetStream();
serverReader = new StreamReader(networkStream, Encoding.Default);
serverWriter = new StreamWriter(networkStream, Encoding.ASCII) {
                     AutoFlush = true
                   };

// reads the server's response to the connect:  "200 news.newsserver.com"
// commenting out these lines doesn't solve the problem
while (serverReader.Peek() > -1) {
    serverReader.ReadLine();
}

serverWriter.WriteLine("authinfo user username");

// expect response "381 more authentication required", but code just blocks
string response = serverReader.ReadLine();

The code blocks at that last line, presumably waiting for the network stream to send a response.

I can avoid hanging the app by setting a timeout loop using serverReader.Peek(), but I will always timeout; I never get a response.

If I telnet to the server and port directly and enter the commands, I get an immediate response.

If I call serverWriter.Flush() explicitly, instead of using the AutoFlush property, I still block and never get a response.

Any ideas why I'm not getting a response to the server using this approach?

Thanks!

Resolved:

The above code does work for me, so I went back and built upon that code to the code that wouldn't work.

In the code that hangs, I was still using the timeout loop with serverReader.Peek(). Peek() always returns -1, even though there is data in the buffer to read!! Replacing the Peek() loop with a blocking call to ReadLine() solves my problem.

I put the timeout loop in originally because the app is multi-threaded, and I didn't want to block. I will have to revisit this issue and see how I can resolve the thread timing without using Peek().

Thanks all, good answers!

+4  A: 

I doubt that it's the StreamWriter that's the problem... but there's a simple way to find out. Download WireShark and see what's actually coming and going on the network. That's by far the simplest way of finding out what's going on.

Jon Skeet
+1 for Wireshark :D
Ben S
That's a good idea, WireShark is an excellent program, though I never thought to use it in a case like this. I will file that away for future use.
James B
+2  A: 

Try "authinfo user username\r\n". The RFC says NNTP command lines must be terminated by a CR-LF.

R Ubben
He's calling WriteLine() - which will use \r\n on Windows. If this is under Mono it's a different matter though...
Jon Skeet
Yeah, not under Mono, but I tried it anyway, same result. Tried the equivalent (sending a blank command) under the telnet prompt... the news reader ignored the blank command. Good to know, if I wanted to port to Mono I could add the extra lines in without an issue.
James B
True, but TCPClient.GetStream() returns a NetworkStream, and I didn't think NetworkStream had a WriteLine method. (not sure it makes sense except for SMTP, NNTP, etc.) So, even if it lets you call the method, I'm not sure I trust it. I did an NNTP client years ago, and I remember explicitly adding the cr/lf. I do not remember whether I used NetworkStream, though.
R Ubben
@R Ubben: He's not calling it on the stream - he's calling it on the StreamWriter.
Jon Skeet
+1  A: 

The above code does work for me, so I went back and built upon that code to the code that wouldn't work.

In the code that hangs, I was still using the timeout loop with serverReader.Peek(). Peek() always returns -1, even though there is data in the buffer to read!! Replacing the Peek() loop with a blocking call to ReadLine() solves my problem.

I put the timeout loop in originally because the app is multi-threaded, and I didn't want to block. I will have to revisit this issue and see how I can resolve the thread timing without using Peek().

Thanks all, good answers!

James B