多客户端异步聊天错误

时间:2013-12-27 22:17:40

标签: c# .net networking communication

我在C#中使用异步套接字创建了一个小型聊天应用程序。

为多个客户进行聊天。

问题在于:当我在Loopback IP(127.0.0.1)上打开服务器,并在我的计算机上打开了几个客户端时,我成功地在它们之间发送了消息。

但是当我在计算机上打开服务器(127.0.0.1)并在另一台计算机上打开客户端时,通信失败。当我尝试从另一台计算机连接到服务器时,客户端崩溃了(因为它无法连接)。

代码:

服务器

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);
        }
    }
}

客户端:

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 = "";
        }
    }
}

同样,当我在计算机上打开2个客户端和服务器时,客户端已成功通过服务器进行通信。

但是当我在计算机上打开服务器时,我无法通过另一台端口1234(服务器监听)的计算机连接到它。

我没有转发端口1234,如果这很重要(我认为这不重要,因为服务器正在侦听该端口)。

这是为什么?我该如何解决?

2 个答案:

答案 0 :(得分:1)

我认为你可以绑定到IPAddress.Any,即0.0.0.0,意味着监听所有接口活动

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

答案 1 :(得分:0)

如果您希望其他计算机能够连接,您只能在环回接口(127.0.0.1)上监听。该接口没有路由。 让服务器监听所有接口(0.0.0.0)或一个真正的IP地址(例如192.168.1.6?)