0

I'm writing a Connect-Four game in C#, and now want to include the possibility to play games online using TCP. Each instance of the game exe should work as both a server, in order to listen to incoming game invitations, and a client, to send said invitations. Of course, only one at a time is important.

I have read and watched a few C# tutorials on this (namely Jeff Chastine's tutorial 22) and I understand the basics of network communication. After getting past a few permission-errors, fixed by executing as administrator, I am now running into two issues.

1) When I try connecting from a machine on the same network, I always get an error saying the desired server did not respond to the request. When I enter the debugger, the program is stuck at the .AcceptTcpClient call (as if no connection has been attempted). I understand that this is a blocking call, but the code should continue when a connection is attempted. I have not tried connecting two machines in different networks, as I have only one network available.

2) This one is a rather minor issue regarding threading: even though I call listenerThread.Abort() when I close the application, the thread does not stop. I do not have too tight a grip on threads in C#, so I assume this problem is a rather easy fix.

Initialisation of listener and listenerThread

listenerThread = new Thread(ListenForInvites);
listener = new TcpListener(Dns.Resolve("localhost").AddressList[0], setting.port);
client = new TcpClient();

The method for listening to incoming connections

private void ListenForInvites()
{
    try
    {
        listener.Start();
        TcpClient enemyClient = listener.AcceptTcpClient(); // the call where it gets stuck even if someone connects
        onlineSr = new StreamReader(enemyClient.GetStream());
        onlineSw = new StreamWriter(enemyClient.GetStream());

        onlineSw.WriteLine($"ACCEPT {player.name} {player.color.R} {player.color.G} {player.color.B}"); // I am using my own protocol, not HTTP (no clue if this is a horrible idea)
        HandleConnection().Wait();
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message, "Error");
    }
}

The method for attempting the connection

public void SendInvite(string ip)
{
    try
    {
        string[] ipSplit = ip.Split(':');
        client.Connect(ipSplit[0], Convert.ToInt16(ipSplit[1]));
        onlineSr = new StreamReader(client.GetStream());
        onlineSw = new StreamWriter(client.GetStream());

        onlineSw.WriteLine($"INVITE {player.name} {player.color.R} {player.color.G} {player.color.B}"); // player is an instance variable
        onlineSw.Flush();

        HandleConnection().Wait();
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message, "Fehler");
    }
}

What am I doing wrong? Any help is appreciated.

KeksamPC
  • 53
  • 1
  • 7
  • Well, your TcpListener on the server just listens on the [loopback address](https://en.wikipedia.org/wiki/Localhost). No wonder it won't listen to any requests incoming from other machines... –  Jun 08 '19 at 13:31
  • @elgonzo What exactly would be the fix for this? I have tried using IPAddress.Any or just using the TcpListener(int port) constructor, neither of which have worked. – KeksamPC Jun 08 '19 at 13:33
  • Just use the "public"-facing IP address of the server (or resolve the "public" DNS name of the server, if there is one); in other words, the IP address of the NIC through which the incoming traffic arrives. (Also, as a side note, the [`Dns.Resolve`](https://learn.microsoft.com/en-us/dotnet/api/system.net.dns.resolve) method is obsolete) –  Jun 08 '19 at 13:37
  • As an additional side note: Make sure that the client machines, the server machine and any other network-related devices between server and clients are properly configured to actually permit a connection with the chosen address and port... –  Jun 08 '19 at 13:41
  • Yet another side note: Make it a habit to use a [`using`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement) statement whenever working with (local) variables containing IDisposable objects such as streams, StreamReader, StreamWriter, etc... –  Jun 08 '19 at 13:46
  • Alright, so I now use [this solution](https://stackoverflow.com/a/21771432/7588524) to get my public-facing IP address, but now I recieve an error on listener.Start(), saying this IP was invalid. How can I fix this? Of course, any solution requiring to manually configure the network router is out of the question, though I don't think that'll be necessary – KeksamPC Jun 08 '19 at 14:02
  • Sorry for being vague. With "public"-facing IP address i meant the IP address of your server which is used by the clients to establish a connection to the server. The public IP address as seen from the internet is not necessarily the actual IP address of your server machine if the router connecting your devices with the internet is using NAT (which is very, very likely to be the case). –  Jun 08 '19 at 16:12
  • You should probably use IPAddress.Any, otherwise you also need to take into account that a computer may have multiple network connections (WiFi, or wired for instance) and don’t forget when you run as a server to configure the firewall to allow the incoming tcp port. Most online games will use some sort of broker service to discover each other perhaps something to consider – Robbert Draaisma Jun 08 '19 at 16:32
  • Using IPAddress.Any, no luck. I have tried connecting to both the IP-Address gotten from ipconfig, as well as the one from icanhazip.com, neither has worked. I have checked thoroughly to enable the ports I use in the Windows Firewall, on both devices. – KeksamPC Jun 08 '19 at 20:23

0 Answers0