服务器无法检测到客户端是否关闭

时间:2019-07-10 09:54:06

标签: c# .net tcp client-server

以下是我的客户代码:

public partial class ClientForm : Form
{
    private string clientID = string.Empty;
    private string otherClientID = string.Empty;
    private ClientClass client ;

    public ClientForm()
    {
        InitializeComponent();

        connectToolStripMenuItem.Enabled = true;
        disconnectToolStripMenuItem.Enabled = false;
        postToolStripMenuItem.Enabled = false;
        viewToolStripMenuItem.Enabled = false;
    }

    private void connectToolStripMenuItem1_Click(object sender, EventArgs e)
    {
        //...
    }

    private void postToolStripMenuItem_Click(object sender, EventArgs e)
    {
        //...
    }

    private void viewToolStripMenuItem_Click(object sender, EventArgs e)
    {
        //...
    }

    private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (client.IsConnected())
        {
            client.Close();
            client = null;
        }

        connectToolStripMenuItem.Enabled = true;
        disconnectToolStripMenuItem.Enabled = false;
        postToolStripMenuItem.Enabled = false;
        viewToolStripMenuItem.Enabled = false;
    }
}

以下是我的服务器:

    public partial class ServerForm : Form
    {
        TcpListener _tcplistener = null;
        bool _keepPolling = true;        
        private static object _lockObj = new object();
        // ...

        public ServerForm()
        {
            InitializeComponent();

            startToolStripMenuItem.Enabled = true;
            stopToolStripMenuItem.Enabled = false;

            //...
        }

        private void startToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string ipAddress = Constants.LOCAL_HOST_IP;
            int portNo = Constants.PORT_NO;

            IPAddress ip = IPAddress.Parse(ipAddress);
            _tcplistener = new TcpListener(ip, portNo);

            // poll for clients in a 2nd thread
            Thread thread = new Thread(delegate()
            {
                PollIncomingClientConns(_tcplistener);
            });
            thread.IsBackground = true;
            thread.Start();

            SetStringToTextBox("Server program started on address [" + ipAddress + ":" + portNo + "]");

            startToolStripMenuItem.Enabled = false;
            stopToolStripMenuItem.Enabled = true;
        }

        #region polling incoming client connections
        void PollIncomingClientConns(TcpListener listener)
        {
            listener.Start();

            _keepPolling = true;

            try
            {
                while (_keepPolling)
                {
                    ClientClass client = new ClientClass(listener);
                    ClientDictionary.Add(client.ID, client);

                    SetStringToTextBox("Client [" + client.ID + "] is now connected.");

                    Thread thread = new Thread(delegate()
                    {
                        ReadFromClient(client);
                    });
                    thread.IsBackground = true;
                    thread.Start();
                }
            }
            catch (Exception ex)
            {
                var inner = ex.InnerException as SocketException;

                if (inner != null && inner.SocketErrorCode == SocketError.ConnectionReset)
                {
                    SetStringToTextBox("Disconnected");
                }
                else
                {
                    SetStringToTextBox(ex.Message);
                }

                listener.Stop();
            }
        }
        #endregion

        void ReadFromClient(ClientClass client)
        {
            try
            {
                while (true)
                {
                    string str = client.Read();
                    SetStringToTextBox("[" + client.ID + "] says: " + str);

                    switch (str)
                    {
                        //...
                    }

                    if (!client.Tcp.Connected)
                    {
                        SetStringToTextBox("[" + client.ID + "] is disconnected.");
                        client.Close();
                        break;
                    }
                }
            }
            catch
            {
                client.Close();
            }
        }

        #region add text to the text box.
        delegate void SetTextCallback(string text);
        private void SetStringToTextBox(string text)
        {
            if (this.outputTextBox.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetStringToTextBox);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.outputTextBox.AppendText(text + Environment.NewLine);
            }
        } 
        #endregion

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _keepPolling = false;
            _tcplistener.Server.Close();
            _tcplistener = null;

            SetStringToTextBox("Server is stopped!");

            startToolStripMenuItem.Enabled = true;
            stopToolStripMenuItem.Enabled = false;
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Environment.Exit(Environment.ExitCode);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            Environment.Exit(Environment.ExitCode);
        }
    }
}

我面临的问题是

  1. 服务器程序未显示有关客户端是否关闭的任何消息。
  2. 如果服务器已停止,则会出现以下错误:
  

通过调用WSACancelBlockingCall中断了阻止操作   服务器程序在地址上启动

以下是我的客户课程:

    public class ClientClass
    {
        public string ID { get; private set; }
        public string Host { get; set; }
        public int Port { get; set; }        

        public TcpClient Tcp { get; private set; }
        private BinaryReader reader;
        private BinaryWriter writer;

        /// <summary>
        /// Creates a client at the Client-end.
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        public ClientClass(string host, int port)
        {
            Random rnd = new Random();
            ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
            Host = host;
            Port = port;
        }

        /// <summary>
        /// creates a proxy-client at the Server-end.
        /// </summary>
        /// <param name="listener"></param>
        public ClientClass(TcpListener listener)
        {
            Tcp  = listener.AcceptTcpClient();

            Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
            Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;

            NetworkStream stream = Tcp.GetStream();
            reader = new BinaryReader(stream);
            writer = new BinaryWriter(stream);

            ID = Read();
        }

        /// <summary>
        /// Connects the client to the server.
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {
            bool is_connected = IsConnected();

            if (!is_connected)
            {
                Tcp = new TcpClient(Host, Port);

                NetworkStream stream = Tcp.GetStream();
                reader = new BinaryReader(stream);
                writer = new BinaryWriter(stream);

                return true;
            }
            else if (is_connected)
            {
                return true;
            }
            else return false;
        }

        public bool IsConnected()
        {
            if (Tcp == null)
            {
                return false;
            }
            else
            {
                Socket s = Tcp.Client;

                bool part1 = s.Poll(1000, SelectMode.SelectRead);
                bool part2 = (s.Available == 0);
                if ((part1 && part2) || !s.Connected)
                    return false;
                else
                    return true;
            }
        }

        public void Write(string str)
        {
            //... ... ...
        }

        public string Read()
        {
            //... ... ...
        }

        public void PrintID()
        {
            Console.WriteLine("Client ID = {0}", ID);
        }

        public void SendIdToServer()
        {
            this.Write(ID);
        }

        public bool Close()
        {
            if (IsConnected())
            {
                if (Tcp != null)
                {                
                    Tcp.Close();
                    Tcp = null;

                    return true;
                }
            }

            return false;
        }
    }

0 个答案:

没有答案