Клиент C # TCP переподключается после закрытия и повторного открытия формы клиента - PullRequest
0 голосов
/ 28 ноября 2018

Я написал чат-приложение на C # WinForms.Но если я закрою клиентскую форму (пока эта форма связана с серверной формой) и снова открою клиентскую форму и попытаюсь переподключиться, клиент не подключится к серверу.

Как я могу переподключитьклиент на сервер, если приложение закрыто и вновь открыто?

(извините за плохой английский)

Сервер:

    public frmServer()
    {
        InitializeComponent();
        textBox_Hostname.Text = GetLocalIPAddress();
        Configuration Programmkonfiguration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        Port = Programmkonfiguration.AppSettings.Settings["Port"].Value;
        textBox_Port.Text = Port;
        toolStripStatusLabel_Serverstatus.Text = "deaktiviert";
        toolStripStatusLabel_Serverstatus.ForeColor = Color.Red;
        textBox_Output.Focus();
    }

    private string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        throw new Exception("No network adapters with an IPv4 address in the system!");
    }

    private void button_Send_Click(object sender, EventArgs e)
    {
        if (!(string.IsNullOrWhiteSpace(textBox_Output.Text)))
        {
            String s = "Server: " + textBox_Output.Text + Environment.NewLine;
            textBox_Input.Text += s;
            byte[] byteTime = Encoding.ASCII.GetBytes(s);
            ns.Write(byteTime, 0, byteTime.Length);
            textBox_Output.Clear();
        }
    }

    public void DoWork()
    {
        byte[] bytes = new byte[1024];
        while (true)
        {
            int bytesRead = ns.Read(bytes, 0, bytes.Length);
            this.SetText(Encoding.ASCII.GetString(bytes, 0, bytesRead));
        }
    }

    private void SetText(string text)
    {
        if (this.textBox_Input.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox_Input.Text = this.textBox_Input.Text + text;
        }
    }

    private void button_Starten_Click(object sender, EventArgs e)
    {
        IPAddress hostname = IPAddress.Parse(textBox_Hostname.Text);
        int portNum = Convert.ToInt32(textBox_Port.Text);
        listener = new TcpListener(hostname, portNum);
        listener.Start();
        Task TCPListener = new Task(() => AcceptTCP());
        TCPListener.Start();
        textBox_Input.Text += "Server gestartet." + Environment.NewLine;
        button_Starten.Enabled = false;
        toolStripStatusLabel_Serverstatus.Text = "aktiviert";
        toolStripStatusLabel_Serverstatus.ForeColor = Color.Green;
    }

    private void AcceptTCP()
    {
        client = listener.AcceptTcpClient();
        ns = client.GetStream();
        Task Work = new Task(() => DoWork());
        Work.Start();
    }

    private void textBox_Output_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter)
        {
            button_Send_Click(sender, e);
            e.Handled = true;
            textBox_Output.Focus();
        }
    }
}

Клиент:

    public frmClient()
    {
        InitializeComponent();
        Configuration Programmkonfiguration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        HostnameServer = Programmkonfiguration.AppSettings.Settings["HostnameServer"].Value;
        Port = Programmkonfiguration.AppSettings.Settings["Port"].Value;
        textBox_Hostname.Text = GetLocalIPAddress();
        textBox_Port.Text = Port;
        toolStripStatusLabel_Status.Text = " nicht verbunden";
        toolStripStatusLabel_Status.ForeColor = Color.Red;
        textBox_Output.Focus();
    }

    private string GetLocalIPAddress()
    {
        var host = Dns.GetHostEntry(HostnameServer);
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        throw new Exception("No network adapters with an IPv4 address in the system!");
    }


    private void button_Senden_Click(object sender, EventArgs e)
    {
        if (!(string.IsNullOrWhiteSpace(textBox_Output.Text)))
        {
            String s = "Client: " + textBox_Output.Text + Environment.NewLine;
            textBox_Input.Text += s;
            byte[] byteTime = Encoding.ASCII.GetBytes(s);
            ns.Write(byteTime, 0, byteTime.Length);
            textBox_Output.Clear();
        }
    }

    public void DoWork()
    {
        byte[] bytes = new byte[1024];
        while (true)
        {
            if (ns.DataAvailable)
            {
                int bytesRead = ns.Read(bytes, 0, bytes.Length);
                this.SetText(Encoding.ASCII.GetString(bytes, 0, bytesRead));
            }
        }
    }

    private void SetText(string text)
    {
        if (this.textBox_Input.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox_Input.Text = this.textBox_Input.Text + text;
        }
    }

    private void button_Connect_Click(object sender, EventArgs e)
    {
        string hostName = textBox_Hostname.Text;
        int portNum = Convert.ToInt32(textBox_Port.Text);
        client = new TcpClient(hostName, portNum);
        ns = client.GetStream();
        Work = new Task(() => DoWork());
        Work.Start();
        textBox_Input.Text += "Verbindung hergestellt." + Environment.NewLine;
        button_Connect.Enabled = false;
        toolStripStatusLabel_Status.Text = "verbunden";
        toolStripStatusLabel_Status.ForeColor = Color.Green;
    }

    private void textBox_Output_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter)
        {
            button_Senden_Click(sender, e);
            e.Handled = true;
            textBox_Output.Focus();
        }
    }
}

1 Ответ

0 голосов
/ 28 ноября 2018

Каждый вызов Accept на сокете слушателя принимает одно соединение.В данный момент ваш сервер принимает один запрос на подключение и затем игнорирует сокет слушателя с этой точки и далее.

Как правило, вы бы хотели какую-то форму "Accept loop", которая постоянно вызывает Accept,настраивает ресурсы на стороне сервера для этого соединения, а затем снова возвращается к вызову Accept.

Например, тривиальное изменение заключается в следующем:

private void AcceptTCP()
{
    while(true)
    {
      client = listener.AcceptTcpClient();
      ns = client.GetStream();
      Task Work = new Task(() => DoWork());
      Work.Start();
    }
}

Но теперь вам действительно нужноподумайте о том, что происходит с ns - что произойдет, если / когда вы захотите подключить второй клиент одновременно?Наличие NetworkStream в качестве единой переменной общего экземпляра на сервере не будет хорошо масштабироваться.

Обычно вам нужно создать некую форму простого класса, который представляет каждое соединение + информацию, относящуюся к вашему серверук этой связи.Например, он будет содержать NetworkStream, текущее «состояние» этого соединения (если у вас есть режимы или состояния), возможно, буферы, которые в последний раз были переданы на вызов Read как / когда вы начнете идти async с этимработа и т. д.

...