0

I'm trying to implement my own NNTP client (a console program at the moment). My Connection class inherits from TcpClient, and has the following code:

Connect(hostname, port);
NetworkStream stream = GetStream();
StreamReader reader = new StreamReader(stream);
try
{
    while (!reader.EndOfStream)
    {
        r = reader.ReadLine();
        Console.WriteLine(r);
    }
}
catch (IOException ioe)
{
    Console.WriteLine(ioe.Message);
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}              

When I run this piece of code or debug it, it outputs the welcome message from the NNTP server, but appears to hang as soon as the ReadLine is executed again. There should be no more data from the server, but EndOfStream is false.

I decided to ditch the StreamReader, and ended up with the following:

Connect(hostname, port);
NetworkStream stream = GetStream();
try
{
    int ch;
    while ((ch = stream.ReadByte()) != -1)
    {
        Console.WriteLine((char) ch);
    }
}
catch (IOException ioe)
{
    Console.WriteLine(ioe.Message);
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}              

As with the first example, ReadByte never returns -1, and the code appears to hang.

No exceptions are thrown, the program just doesn't exit. Does anybody know why this is happening, or what I am doing wrong?

Thanks!

Marlon
  • 45
  • 7
  • Would be better if you shared source of method `GetStream`. – Farhan Nasim Jun 11 '17 at 21:34
  • @f.nasim - GetStream is not a method written by me, it is part of the C# TcpClient class. – Marlon Jun 11 '17 at 21:37
  • Simple. A stream you will never get to the end of data because the other is open. When you use a file the file contains an end so windows put the end in the steam. When using a stream to get data you must indicate the end of each message with one (or combination) of following methods. 1) ASCII : Add character at end line '\n'. 2) ASCII or BINARY : Add length of message to beginning of each message. 3) ASCII or BINARY : Use fixed length messages. Each message type can have different length. You can also add an application level which sends and receives commands like to close connection. – jdweng Jun 11 '17 at 21:41
  • @jdweng - I see. So basically the stream will remain open, but I can only read from it whenever the server sends something, and I need to process the sent messages to see when I should stop reading between messages. Got it - thank you! – Marlon Jun 11 '17 at 22:34
  • Yes, but you are backwards. A server is a slave device while the client is the master. So the application should be setup that the client sends a command and the server processes the command and sends back a response. Now is some cases a server will automatically keep sending messages. A good example is the GPS device which is technically a server. The GPS device will constantly send location messages without client requesting when in automatic mode. – jdweng Jun 11 '17 at 23:06
  • I assume that you are referencing the [NNTP specification](https://tools.ietf.org/html/rfc3977). If you read it, you'll notice that NNTP is a responsive protocol; that is, the server is a command-based server, responding to commands issued by the client connecting to it until the connection is closed. `NetworkStream` is an abstraction around the socket, the end of which isn't reached until the TCP connection is actually closed. – Peter Duniho Jun 12 '17 at 00:25
  • Before you try to implement NNTP, you really need to learn a _lot_ more about how network protocols work, especially TCP. I strongly recommend the [Winsock Programmer's FAQ](http://tangentsoft.net/wskfaq/). While not written from a .NET perspective per se, the .NET API is just a thin layer over the Winsock API, and in any case much of the details are specific to the network protocol itself (e.g. TCP), rather than the API. You'll want to learn all that first, before diving into NNTP. – Peter Duniho Jun 12 '17 at 00:26
  • I also advise taking the comments from jdweng with a large grain of salt. They don't seem to be paying attention to the fact that you're dealing with NNTP and thus already have a specific protocol you have to comply with (i.e. you can't just choose your own message-delimiting structure), and that person has only just enough knowledge to make it sound like they know what they are talking about, when in fact they will often post misleading or outright incorrect information (e.g. you do not need to use ASCII to use newline-terminated messaging, as their comment above claims). – Peter Duniho Jun 12 '17 at 00:31
  • Bottom line here: it is normal for the read operation to block. There is no data available, but the connection hasn't been closed. So the read operation will wait until one or the other happens. This means it's important to not issue a read operation in a thread you want to be able to do something else, unless you are 100% sure there's something to read. It is generally much better to handle reading and writing separately, using async mechanisms for the reading (at a minimum...you can also use async for writing if you want), so that you don't block a thread that should be doing other things. – Peter Duniho Jun 12 '17 at 00:40

0 Answers0