C#TCP客户端在关闭并重新打开客户端表单后重新连接
C# TCP Client reconnect after closing and reopening client form
我用 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();
}
}
}
在侦听器套接字上对 Accept
的每次调用都接受一个连接。目前,您的服务器接受单个连接请求,然后从那时起忽略侦听器套接字。
通常,您需要某种形式的“Accept
循环”不断调用 Accept
,为该连接设置服务器端资源,然后循环回调用 Accept
再次.
例如微不足道的改变是这样做:
private void AcceptTCP()
{
while(true)
{
client = listener.AcceptTcpClient();
ns = client.GetStream();
Task Work = new Task(() => DoWork());
Work.Start();
}
}
但现在您真的必须考虑 ns
会发生什么 - 会发生什么 if/when 您想要同时连接第二个客户端?让 NetworkStream
成为服务器中的单个共享实例变量不会很好地扩展。
通常,您希望创建某种形式的简单 class 来表示每个连接 + 与该连接相关的服务器特定信息。例如。它将包含 NetworkStream
、此连接的当前 "state"(如果您有模式或状态),可能是最后传递给 Read
调用 as/when 的缓冲区开始 async
这项工作,等等
我用 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();
}
}
}
在侦听器套接字上对 Accept
的每次调用都接受一个连接。目前,您的服务器接受单个连接请求,然后从那时起忽略侦听器套接字。
通常,您需要某种形式的“Accept
循环”不断调用 Accept
,为该连接设置服务器端资源,然后循环回调用 Accept
再次.
例如微不足道的改变是这样做:
private void AcceptTCP()
{
while(true)
{
client = listener.AcceptTcpClient();
ns = client.GetStream();
Task Work = new Task(() => DoWork());
Work.Start();
}
}
但现在您真的必须考虑 ns
会发生什么 - 会发生什么 if/when 您想要同时连接第二个客户端?让 NetworkStream
成为服务器中的单个共享实例变量不会很好地扩展。
通常,您希望创建某种形式的简单 class 来表示每个连接 + 与该连接相关的服务器特定信息。例如。它将包含 NetworkStream
、此连接的当前 "state"(如果您有模式或状态),可能是最后传递给 Read
调用 as/when 的缓冲区开始 async
这项工作,等等