views:

272

answers:

2

I'm using visual studio to program this small TcpServer.

It's really specific. The server listens to port 1234 and is located on IP 127.0.0.1 Our teachers gave us a program that tries to connect to that port on that IP when you click "connect". It's working for everyone else, so it must be a coding error on my part.

When I click connect, the program sends the word "GET" over the stream, to which I have to respons with a list of allready connected IP-adress and then a newline containing only a .

When I disconnect, the program sends the word "REM" and I simply have to remove if from my list(which is a generic list)

I have a class TCPServer(we had to make our own), which has this as main code:

this.tl = new TcpListener(IPAddress.Any, PORT);
tl.Start();
while(true)
{
  TcpClient tcl = tl.AcceptTcpClient();//here the server will wait forever untill someone connects, meaning the "new Thread" statement is never reached untill someone connects.
  TcpHelper th = new TcpHelper(tcl,conf);
  new Thread(new ThreadStart(th.Start)).Start();//should be multi-threaded, not sure if it is.
  //t.Start();
}

TcpHelper looks like this(look for the commented text "here's the problem" within the usings):

public class TcpHelper
{
    private TcpClient tc;
    private IPEndPoint ipe;
    private string get;
    private Configuration conf;

    public TcpHelper(TcpClient tc, Configuration conf)
    {
       this.tc = tc;
       this.conf = conf;
    }

    public void Start()
    {
       using (NetworkStream nws = this.tc.GetStream())
       {
           using (StreamReader sr = new StreamReader(nws))
           {
              using (StreamWriter sw = new StreamWriter(nws))
              {
                  this.ipe = (IPEndPoint)tc.Client.RemoteEndPoint;
                  this.conf.List.Add(this.ipe.Address);
                  bool conn = true;

                  while (conn)
                  {
                      this.get = sr.ReadLine();//here's the problem
                      switch (this.get)
                      {
                          case "GET":
                              foreach (IPAddress address in this.conf.Lijst)
                              {
                                  sw.WriteLine(address.ToString());
                              }
                              sw.WriteLine(".");
                              break;

                          case "REM":
                              this.conf.List.Remove(this.ipe.Address);
                              sw.WriteLine("OK.");
                              conn = false;
                              break;

                          default:
                              break;
                     }
                  }
              }
          }
      }
  }

  #region Properties
  public IPEndPoint Ipe
  {
      get
      {
          return this.ipe;
      }
  }
  #endregion
}
+5  A: 

My guess is that your problem is that you're calling sr.ReadLine(), but the input does not contain a newline, so it's blocked there waiting for a newline that will never come.

you may want to try calling StreamReader.Read 3 times to build up the command string (GET/REM) before you act on it. (Note: 3 times is because all commands are three characters).

Read will return integers, but after checking that they are not -1 (indicating end-of-file), you can cast that integer to a char.

Jonathan
Huh..? Three times? Sounds like a dubious idea to me, care to elaborate? You should continue to read until you've got what you wanted, assuming the protocol dictates a new-line, ReadLine seems like a perfect fit.
roe
ooooh, I see, read one character at a time...
roe
Thing is, Read returns an integer... what good does that do me...
WebDevHobo
Scrap that, I'm getting an IOException when I use Read() to capture.
WebDevHobo
Sorry, I should have been clearer - the 3 times is because of his commands are exactly three characters.
Jonathan
@WebDevHobo: Could you provide the text of the IOException? That will provide some information as to what is going wrong. I'd recommend adding it to the question.
Jonathan
A: 

Sorry, maybe I'm not understanding this... Did you write this code?

this.tl = new TcpListener(IPAddress.Any, PORT);
tl.Start();
while(true)
{
  TcpClient tcl = tl.AcceptTcpClient();
  TcpHelper th = new TcpHelper(tcl,conf);
  new Thread(new ThreadStart(th.Start)).Start();
  //t.Start();
}

This is going to blow the **** out of any computer. You're looping infinitely, creating new threads on each loop. So, if you create one new thread per loop, and each loop takes one millisecond (lets say its very slow!), in five seconds you've got 5,000 threads. Each trying to listen at the same port.

Try using a single thread. If this is a console app, use Console.ReadLine() to block the main thread until somebody presses the enter key.


With the new information... AcceptTcpClient blocks, but instead of creating a new thread the work should be queued on the ThreadPool.

Will
Yes, I wrote this. But consider this. 1) It must loop forever, because it is a server. You don't shut down server. 2) The loop won't continue, since the "tl.AcceptClient();" bit waits for a connection, forcing the program to wait. Meaning no new threads untill someone connects.
WebDevHobo
Okay, so its not too bad. Still, you're creating a new thread every connection. This is not good. Queue these on the ThreadPool, which will manage and reuse threads for you.
Will
ThreadPool you say? I've checked my courses and it's never mentioned. I'm gonna look into it and check with the programming teachers.I wondered how I could keep track of which Thread is doing what. I'm hoping this does that for me.
WebDevHobo
Looks like it did? You should update with the solution, seemed to me like Jonathan was more relevant.
Will