1

I am trying to make 2 programs (in console application) in .NET that communicate together through the web (the code is from a video that you can find below, I am just trying to make the code work before adapting it). Forgive me, I'm not an experienced programmer.

I have a server and a client, they work perfectly when I run both of them on my computer (locally). I can connect multiple clients to the server, send requests and get a response. I am facing the problem when i run the server on a computer and the client on an other one and I try to connect through the internet.

I can connect to the server but communication does not work, there is no data exchange when try to request time as an example. I think that the problem is mostly coming from the network itself than the code.

Here's the code for the server:

class Program
{
    private static Socket _serverSocket;
    private static readonly List<Socket> _clientSockets = new List<Socket>();
    private const int _BUFFER_SIZE = 2048;
    private const int _PORT = 50114;
    private static readonly byte[] _buffer = new byte[_BUFFER_SIZE];

    static void Main()
    {
        Console.Title = "Server";
        SetupServer();
        Console.ReadLine(); // When we press enter close everything
        CloseAllSockets();
    }



    private static void SetupServer()
    {
      //  IPAddress addip = GetBroadcastAddress();
        Console.WriteLine("Setting up server...");
        _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _serverSocket.Bind(new IPEndPoint(IPAddress.Any , _PORT));
        _serverSocket.Listen(5);
        _serverSocket.BeginAccept(AcceptCallback, null);
        Console.WriteLine("Server setup complete");
    }

    /// <summary>
    /// Close all connected client (we do not need to shutdown the server socket as its connections
    /// are already closed with the clients)
    /// </summary>
    private static void CloseAllSockets()
    {
        foreach (Socket socket in _clientSockets)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }

        _serverSocket.Close();
    }

    private static void AcceptCallback(IAsyncResult AR)
    {
        Socket socket;

        try
        {
            socket = _serverSocket.EndAccept(AR);
        }
        catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
        {
            return;
        }

       _clientSockets.Add(socket);
       socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
       Console.WriteLine("Client connected, waiting for request...");
       _serverSocket.BeginAccept(AcceptCallback, null);
    }

    private static void ReceiveCallback(IAsyncResult AR)
    {
        Socket current = (Socket)AR.AsyncState;
        int received;

        try
        {
            received = current.EndReceive(AR);
        }
        catch (SocketException)
        {
            Console.WriteLine("Client forcefully disconnected");
            current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
            _clientSockets.Remove(current);
            return;
        }

        byte[] recBuf = new byte[received];
        Array.Copy(_buffer, recBuf, received);
        string text = Encoding.ASCII.GetString(recBuf);
        Console.WriteLine("Received Text: " + text);

        if (text.ToLower() == "get time") // Client requested time
        {
            Console.WriteLine("Text is a get time request");
            byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
            current.Send(data);
            Console.WriteLine("Time sent to client");
        }
        else if (text.ToLower() == "exit") // Client wants to exit gracefully
        {
            // Always Shutdown before closing
            current.Shutdown(SocketShutdown.Both);
            current.Close();
            _clientSockets.Remove(current);
            Console.WriteLine("Client disconnected");
            return;
        }
        else
        {
            Console.WriteLine("Text is an invalid request");
            byte[] data = Encoding.ASCII.GetBytes("Invalid request");
            current.Send(data);
            Console.WriteLine("Warning Sent");
        }

        current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
    }
}

And here the client code:

class Program
{
    private static readonly Socket _clientSocket = new Socket
        (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    private const int _PORT = 50114;

    static void Main()
    {
        Console.Title = "Client";
        ConnectToServer();
        RequestLoop();
        Exit();
    }

    private static void ConnectToServer()
    {
        int attempts = 0;

        while (!_clientSocket.Connected)
        {
            try
            {
                attempts++;
                Console.WriteLine("Connection attempt " + attempts);
                _clientSocket.Connect("IpAddr", _PORT);
            }
            catch (SocketException) 
            {
                Console.Clear();
            }
        }

        Console.Clear();
        Console.WriteLine("Connected");
    }

    private static void RequestLoop()
    {
        Console.WriteLine(@"<Type ""exit"" to properly disconnect client>");

        while (true)
        {
            SendRequest();
            ReceiveResponse();
        }
    }

    /// <summary>
    /// Close socket and exit app
    /// </summary>
    private static void Exit()
    {
        SendString("exit"); // Tell the server we re exiting
        _clientSocket.Shutdown(SocketShutdown.Both);
        _clientSocket.Close();
        Environment.Exit(0);
    }

    private static void SendRequest()
    {
        Console.Write("Send a request: ");
        string request = Console.ReadLine();
        SendString(request);

        if (request.ToLower() == "exit")
        {
            Exit();
        }
    }

    /// <summary>
    /// Sends a string to the server with ASCII encoding
    /// </summary>
    private static void SendString(string text)
    {
        byte[] buffer = Encoding.ASCII.GetBytes(text);
        _clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
    }

    private static void ReceiveResponse()
    {
        var buffer = new byte[2048];
        int received = _clientSocket.Receive(buffer, SocketFlags.None);
        if (received == 0) return;
        var data = new byte[received];
        Array.Copy(buffer, data, received);
        string text = Encoding.ASCII.GetString(data);
        Console.WriteLine(text);
    }
}
 static void Main()
    {
        Console.Title = "Client";
        ConnectToServer();
        RequestLoop();
        Exit();
    }

    private static void ConnectToServer()
    {
        int attempts = 0;

        while (!_clientSocket.Connected)
        {
            try
            {
                attempts++;
                Console.WriteLine("Connection attempt " + attempts);
                _clientSocket.Connect("IpAddr", _PORT);
            }
            catch (SocketException) 
            {
                Console.Clear();
            }
        }

        Console.Clear();
        Console.WriteLine("Connected");
    }

"IpAddr" is a placeholder for the public IP of the router.

This is the video my current code is based on: https://www.youtube.com/watch?v=xgLRe7QV6QI

I took the code directly from it (you can find the 2 code files on the site linked in description).

I run the server, it awaits for a connection. I then run the clients which tries to connect to the server. I connects and on the server it shows the successful connection. The client then sends a request like "get time" and the server is supposed to catch it and respond:

 byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
 current.Send(data);

Back to network side:

Here is a list of all the things I have tried, that were the usual main causes of the problem after looking for a solution for about a full day:

  • I already have a static public IP for the router (so the public IP never changes). Even though, I created a dynamic dns on noip.com.

  • I gave a static lease to the computer the server runs on, so it has always the same local ip.

  • I created rules in the windows firewall to make sure the port I use is opened. I did this on both computers trying to communicate.

  • I forwarded the port on the router so it points to the local ip of the computer the server runs on. (I tried with a lot of different ports, no chance)

  • I tried activating the "DMZ" on the router but it's most likely not a solution

  • I tried to create a ASP.NET website which page returns a string, publish it with IIS 7.5 and set it up. Works on localhost but using the public ip like "xx.xxx.xxx.xx:PORT/default/index" I get an error. Yet it shows the website name in the error. Also, when using the local IP of the computer, it doesn't work either (something like 192.168.1.180).

Thanks for you help.

7
  • Don't learn to code from YouTube, buy a book. This example is broken, it is a waste of time. It does not implement a protocol, so your server does never receive "get time", it receives "get t" in one packet, and "ime" in another. For example. At least, that's what I saw when I quickly skipped the video. If you want help debugging your code, include all relevant code in your question. :) The connection code is irrelevant and working, otherwise you'd get an exception you could not connect. The error is in the code that handles the sending and receiving of data. Commented Nov 26, 2015 at 16:03
  • It works locally, i don't need any debug in particular, i spent a lot of time to find a solution on the web, so i just posted my problem here ^^. Commented Nov 26, 2015 at 16:07
  • 1
    "It works on my machine " is the classic excuse for broken networking code, but that doesn't make it less broken. If you can connect, but the communication doesn't work as expected, the code doesn't work. I'm certainly not trying to annoy you, but these kind of tutorials spawn multiple of such questions a day. Please include the code in your question. Commented Nov 26, 2015 at 16:12
  • Alright, thank you for that edit. What do you see on both consoles, after you type "get time" on the client? Does the server show that it receives anything? Commented Nov 26, 2015 at 16:22
  • I edited my post with the full code for the client and the server.I gave this code as an example but I tried a lot of different things I found over the web (not only on youtube). Everything works perfectly locally but when I change the IP address to the public IP address of the routeur, it doesn't work anymore, except for the "connection" part. Commented Nov 26, 2015 at 16:24

1 Answer 1

1

I learned about message framing, Thank you CodeCaster.

For people who are curious about it, here is an interesting link i found about it: http://blog.stephencleary.com/2009/04/message-framing.html

But before trying to change the code, I ran the server on an AWS vps and it worked instantly, the problem was probably comming from my isp or my router. I am just wondering how can it work without handling message framing.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.