Search code examples
ubuntunetwork-programming.net-coretcpclient

Why isn't my .NET Core server app accepting connections in Ubuntu, but works fine in Windows?


So, I basically have a server and a client.

The server is a .NET Core 2.2 console applications that listens for incoming connections, once a connection is opened, reads the request, pulls some data from a MySQL DB, and sends it back to the client.

The client is a Xamarin Forms application, which sends these requests to the server. Nothing much complicated.

Now, if I run the server in my local Windows machine, it will start listening to the assigned port and correctly accept requests and send responses. However, when I deploy it to the Ubuntu 19.04 machine which was intended to run this server app, it simply doesn't see the incoming connections.

Of course, I made sure that this isn't a networking problem, I tried to netcat ( nc -l PORT ) the relevant port, and it is receiving the correct data.

Here is my server code:

    public static class Server
    {
        public static Dictionary<string, Session> Sessions { get; private set; } = new Dictionary<string, Session>();

        public static int Main(string[] args)
        {
            return RunServer();
        }

        private static int RunServer()
        {
            var listener = new TcpListener(IPAddress.Loopback, ServerConfig.Port);
            int errorCode = 0;

            try
            {
                listener.Start();
                Console.WriteLine("Server running - listening to " + ServerConfig.Port + " ..."); // this is printed in Ubuntu

                while (true)
                {
                    var clientTask = listener.AcceptTcpClientAsync();

                    if (clientTask.Result != null)
                    {
                        using (TcpClient tcpClient = clientTask.Result)
                        {
                            // This line is printed in Windows/localhost, but not on the Ubuntu production machine
                            Console.WriteLine("Connected to {0}", (tcpClient.Client.RemoteEndPoint as IPEndPoint).Address);

                            string data;
                            string cmd;
                            string[] parameters;
                            string response = null;
                            NetworkStream stream = tcpClient.GetStream();

                            data = ReceiveRemoteMessage(stream); // See below

                            if (string.IsNullOrWhiteSpace(data))
                                continue;

                            parameters = data.Split(' ');
                            cmd = parameters[0];

                            try
                            {
                                // Note: the CommunicationManager class that actually processes the requests is not relevant to this question, so it's not included
                                string methodName = "Manage" + cmd + "Request";
                                var argList = new List<object>();
                                var i = 0;
                                foreach(object par in parameters)
                                {
                                    i++;
                                    if (i == 1)
                                        continue;

                                    argList.Add(par);
                                }
                                object[] args = argList.ToArray();
                                response = (string) typeof(CommunicationManager).GetMethod(methodName).Invoke(null, args);
                            }

                            catch (Exception e)
                            {
                                if (e is AmbiguousMatchException ||
                                    e is ArgumentNullException ||
                                    e is TargetException ||
                                    e is ArgumentException ||
                                    e is TargetInvocationException ||
                                    e is TargetParameterCountException ||
                                    e is MethodAccessException ||
                                    e is InvalidOperationException ||
                                    e is NotSupportedException)
                                {
                                    response = ServerResponse.InvalidRequest; // ServerResponse is a static class with read-only static string fields
                                }
                                else
                                {
                                    response = ServerResponse.GenericException;
                                }
                            }

                            if (!string.IsNullOrWhiteSpace(response))
                            {
                                SendSocketMessage(stream, response);
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                errorCode = 1;
            }
            finally
            {
                listener.Stop();
            }

            Console.WriteLine($"\nExit code: {errorCode}\nPress any key to terminate.");
            Console.ReadKey();
            return errorCode;
        }

        private static void SendSocketMessage(NetworkStream stream, string message)
        {
            var encryptedMsg = Encrypt.EncryptString(message);
            stream.Write(Encoding.UTF8.GetBytes(encryptedMsg));
        }

        private static string ReceiveRemoteMessage(NetworkStream stream)
        {
            const int bufferSize = 1024;
            byte[] bytes;
            string data = string.Empty;

            while (true)
            {
                bytes = new byte[bufferSize];
                int bytesReceived = stream.Read(bytes);

                string utfString = Encoding.UTF8.GetString(bytes, 0, bytesReceived);

                if (string.IsNullOrEmpty(utfString))
                    break;

                data += utfString;

                if (bytesReceived < bufferSize)
                    break;
            }
            var decryptedMsg = Encrypt.DecryptString(data);
            return decryptedMsg;
        }
    }

And this is my client code, used in Xamarin (Mono)

public static string SendServerRequest(string request)
        {
            //
            try
            {
                TcpClient client = new TcpClient();
                client.ConnectAsync(ServerConfig.Hostname, ServerConfig.Port).Wait();

                NetworkStream stream = client.GetStream();

                var encryptedRequest = Encrypt.EncryptString(request);
                var sentBytes = Encoding.UTF8.GetBytes(encryptedRequest);
                stream.Write(sentBytes, 0, sentBytes.Length);

                const int bufferSize = 1024;
                byte[] bytes;
                string data = string.Empty;
                int totalBytesReceived = 0;

                while (true)
                {
                    bytes = new byte[bufferSize];
                    int bytesReceived = stream.Read(bytes, totalBytesReceived, bufferSize);
                    totalBytesReceived += bytesReceived;

                    string utfString = Encoding.UTF8.GetString(bytes, 0, bytesReceived);

                    if (string.IsNullOrEmpty(utfString))
                        break;

                    data += utfString;

                    if (bytesReceived < bufferSize)
                        break;
                }

                return Encrypt.DecryptString(data);
            }
            catch
            {
                return null;
            }
        }

Thanks.


Solution

  • var listener = new TcpListener(IPAddress.Loopback, ServerConfig.Port);
    

    This is saying that the TcpListener should listen on the loopback address (only). That means that the server should listen to incoming connections that only originate from the local machine, not any other machine on the network.

    I think you want IPAddress.Any:

    var listener = new TcpListener(IPAddress.Any, ServerConfig.Port);