views:

46

answers:

1

I'm starting to dip my toes in the world of network programming and I've recently come across a fairly old sample from a lecturers tutorial (Or so I'm told).

We tried it on the university computers but it wouldn't work so the lecturer assumed it was down to a security setting either by Windows 7 or by the university computer systems.

Eager to find the cause I decided to run the same code on my own computer at home and to no surprise it didn't work.

There are two projects in a solution, one acts as the client and another the server. Once the server and client are both connected to each other the client sends a simple string to the server which is printed to the console. After this the appropriate connections are closed and the application gracefully exits.

The applications work as far as the server confirming that it has connected to the client yet it throws an exception (That is caught and handled) with the text:

Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. - (System.IO.IOException)

Now as I'm just starting out with network programming with C# I'm not exactly sure where to look, my lecturer said that he would find out for next week's lecture with the cause and solution to the problem but I wanted to take some initiative and find out myself.

I've added the Client.cs and the Server.cs classes just in case they are helpful, the debugger suggests the cause lies at line 27 in Server.cs, the call to streamReader.Readline();

Note: This isn't in any way homework, I'm simply curious as to why it doesn't work. Call it a learning experience =]

Client.cs

using System;
using System.Net.Sockets;
using System.IO;

namespace NetworkProgrammingTutorial1Client
{
    class Client
    {
        static void Main(string[] args)
        {
            TcpClient myclient;

            try
            {
                // Create a TcpClient to talk to the local host.
                myclient = new TcpClient("localhost", 1234);
            }
            catch
            {
                Console.WriteLine("Failed to connect to the server.");
                return;
            }

            // get a Network stream from the server
            NetworkStream networkStream = myclient.GetStream();
            StreamWriter streamWriter = new StreamWriter(networkStream);

            streamWriter.WriteLine("Have a message.");
            streamWriter.Flush();
        }
    }
}

Server.cs

using System;
using System.Net.Sockets;
using System.Net;
using System.IO;

namespace NetworkProgrammingTutorial1Server
{
    class Server
    {
        static void Main(string[] args)
        {
            // TcpListener is listening on the given port...                                                 {
            TcpListener tcpListener = new TcpListener(1234);
            tcpListener.Start();     
            Console.WriteLine("Server Started") ;                  
            // Accepts a new connection...
            Socket socketForClient = tcpListener.AcceptSocket();                   
            try
            {
                if (socketForClient.Connected)
                {
                    while (true)
                    {
                        Console.WriteLine("Client connected");
                        NetworkStream networkStream = new NetworkStream(socketForClient);
                        StreamReader streamReader = new StreamReader(networkStream);
                        string line = streamReader.ReadLine();
                        if (line == null)
                            break;
                        Console.WriteLine(line);
                    }
                }

                socketForClient.Close();               
                Console.WriteLine("Exiting...");
            }
            catch(Exception e)
            {
                Console.WriteLine(e.ToString()) ;
            }
        }
    }
}
A: 

Try this server code:

TcpListener listener = new TcpListener(IPAddress.Any, 1234);
listener.Start();     

using (TcpClient client = listener.AcceptTcpClient())
using (StreamReader reader = new StreamReader(client.GetStream()))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}

listener.Stop();

This listens on port 1234, accepts one client, creates a StreamReader and outputs all lines sent by the client until the client closes the connection. Then it stops listening and exits.

As you can see, only one StreamReader is created (not repeatedly for every line), and both the TcpClient and the StreamReader are disposed by the using statement when you're done.


Your client code should work. It's a good idea to dispose the objects here as well, though:

using (TcpClient client = new TcpClient("localhost", 1234))
using (StreamWriter writer = new StreamWriter(client.GetStream()))
{
    writer.WriteLine("Have a message.");
    writer.Flush();

    writer.WriteLine("Have another message.");
    writer.Flush();
}
dtb
This may seem a bit of a novice question but how come AcceptTcpCLient is being used not not AcceptSocket? Is there a benefit to using one over the other?
Jamie Keeling
The .NET Framework provides two ways of network programming: TcpClient/TcpListener and Sockets. TcpClient/TcpListener offer a high-level interface and are much more simple and easier to use than the low-level Sockets. So it's a good idea for a novice to use TcpClient/TcpListener and to avoid Sockets.
dtb
Ezxcellent, thanks for the advice. After changing the Server.cs to your solution the message is sent across but after that it throws an IOException at the line where it attempts to read the message from the client.
Jamie Keeling
I've just tested my code and it works flawlessly on my machine. What IOException do you get? The same (connection was forcibly closed by the remote host) or another one?
dtb
The exception text is "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host." - Does it matter if the project is built in release mode?
Jamie Keeling
Debug or release mode should be no difference. Check if your firewall prevents communication. Try a different port. Make sure not more than 1 server is running at the same time.
dtb
I typed "netstat -an" into the command line and it didn't list the port I specified as being in use still. I've tried disabling my firewall and this made no effect =/
Jamie Keeling
Bit of a late reply but it seems to work now, I tried it on my netbook and it works flawlessly. Seems I might need to reformat my desktop because it failed to run a network Java app too. Thank you for the help!
Jamie Keeling