Question

I've made a small chat application using asynchronous sockets in C#.

The chat is made for multiple clients.

Here's the problem: When I opened the server on my Loopback IP (127.0.0.1), and opened a few clients on my computer, I successfully sent messages between them.

But when I opened the server on my computer (127.0.0.1), and opened a client on another computer, the communication failed. When I tried to connect to the server from another computer, the client crashed (because it couldn't connect).

The codes:

Server:

namespace ServerForm
{
    public partial class Form1 : Form
    {
        private Socket _serverSocket;
        private readonly List<Socket> _clientSockets = new List<Socket>();
        private const int _BUFFER_SIZE = 2048;
        private const int _PORT = 513;
        private readonly byte[] _buffer = new byte[_BUFFER_SIZE];
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            SetupServer();
        }
        private void SetupServer()
        {
            //Console.WriteLine("Setting up server...");
            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.Bind(new IPEndPoint(0, 1234));
            _serverSocket.Listen(5);
            _serverSocket.BeginAccept(AcceptCallback, null);
            //Console.WriteLine("Server setup complete");
        }
        private void CloseAllSockets()
        {
            foreach (Socket socket in _clientSockets)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }

            _serverSocket.Close();
        }

        private 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 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());
                for (int i = 0; i < _clientSockets.Count; i++) _clientSockets[i].Send(Encoding.ASCII.GetBytes(text));
                //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");
                for (int i = 0; i < _clientSockets.Count; i++) _clientSockets[i].Send(Encoding.ASCII.GetBytes(text));
                //Console.WriteLine("Warning Sent");
            }

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

Client:

namespace ChatForm
{
    public partial class Form1 : Form
    {
        private readonly Socket _clientSocket = new Socket
            (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        private const int _PORT = 1234;
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void connect_Click(object sender, EventArgs e)
        {
            if (name.Text == "" || s_ip.Text == "") MessageBox.Show("Fields cannot be empty.");
            else ConnectToServer();
        }
        private void ConnectToServer()
        {
            IPAddress connection = IPAddress.Parse(s_ip.Text);
            IPAddress server = connection;
            int attempts = 1;

            while (!_clientSocket.Connected)
            {
                try
                {
                    _clientSocket.Connect(connection, _PORT);
                }
                catch (SocketException) // it crashes if it reaches here
                {

                }
            }
            MessageBox.Show("Successfully connected to server");
            RequestLoop();
        }

        private void RequestLoop()
        {
            Thread t1 = new Thread(ReceiveResponse);
            t1.Start();
        }

        /// <summary>
        /// Close socket and exit app
        /// </summary>
        private void Exit()
        {
            SendString("exit");
            _clientSocket.Shutdown(SocketShutdown.Both);
            _clientSocket.Close();
            Environment.Exit(0);
        }

        private void SendRequest()
        {
            string request = "[" + name.Text + "] " + text.Text + "\n";
            SendString(request);

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

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

        private void ReceiveResponse()
        {
            while (true)
            {
                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);
                display.AppendText(text);
                if (text.Contains("MessageBox!"))
                {
                    MessageBox.Show(text.Split('!')[1]);
                }
            } 
        }

        private void button2_Click(object sender, EventArgs e)
        {
            SendRequest();
            text.Text = "";
        }
    }
}

Again, when I opened 2 clients and a server on my computer, the clients successfully communicated through the server.

But when I opened the server on my computer, I couldn't connect to it through another computers with port 1234 (which the server listens to).

I haven't forwarded port 1234, if that matters (I don't think it should matter since the server is listening to that port).

Why is this? And how can I fix it?

Was it helpful?

Solution

I think you can bind to IPAddress.Any,which is 0.0.0.0, means listening all interface activity

_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 1234));
_serverSocket.Listen(5);

OTHER TIPS

You cant listen only on the loopback interface (127.0.0.1) if you expect other computers to be able to connect. There is no routing for that interface. Either make the server listen on all interfaces (0.0.0.0) or one of your real ip-addresses (192.168.1.6 for instance?)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top