我用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();
}
}
}
答案 0 :(得分:0)
在侦听器套接字上对Accept
的每次调用都接受一个连接。目前,您的服务器接受单个连接请求,然后从该点开始忽略监听器套接字。
通常,您需要某种形式的“ Accept
循环”来连续调用Accept
,为该连接设置服务器端资源,然后循环返回以再次调用Accept
例如简单的更改是这样做:
private void AcceptTCP()
{
while(true)
{
client = listener.AcceptTcpClient();
ns = client.GetStream();
Task Work = new Task(() => DoWork());
Work.Start();
}
}
但是现在您真的必须考虑ns
会发生什么-如果/当您希望同时连接第二个客户端时会发生什么?将NetworkStream
设为服务器内的单个共享实例变量并不能很好地扩展。
通常,您需要创建某种形式的简单类,以表示每个连接以及与该连接有关的服务器特定信息。例如。它会包含NetworkStream
,此连接的当前“状态”(如果您有模式或状态),也可能是在您开始进行{{时,最后一次传递给Read
调用的缓冲区1}},等等。