我使用线程和套接字编写了服务器和多个客户端的代码。通常客户端通过向服务器发送'exit'关键字退出,但我希望服务器也检测到客户端强行退出而不向服务器发送'exit'关键字的情况,例如当用户向服务器发送消息时按下交叉按钮客户端窗口。我想要的是服务器应该检测到这种情况并显示一些错误代码并继续从连接到它的其他客户端接收消息。
我面临的第二个问题即使多个客户端连接到服务器,我如何断开服务器。在我的代码中我使用tcpListener.Stop(),但是当我使用此方法时,显示错误消息“服务器无法启动ipaddress”,此类窗口打开的数量相当于服务器正在侦听的客户端数量。例如,如果服务器正在侦听1000个客户端,那么将打开1000个这样的窗口,显示前面提到的错误消息,从使用该软件的人的角度来看这看起来并不好。那么我该如何处理这种情况呢?此外,在这种情况下,如果客户端再次开始向服务器发送消息,那么即使我已断开服务器,也会开始接收消息。在用户重新启动服务器之前,服务器应保持断开状态。
以下是我的服务器代码。
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
// Constants IP address of server and maximum number of clients server can connect.
static class Constants
{
public const string IP = "127.0.0.1";
public const int No_Of_Clients = 2;
}
// server port number
int port_number;
static IPAddress ipAddress = IPAddress.Parse(Constants.IP);
TcpListener tcpListener;
public Form1()
{
InitializeComponent();
button1.Click += button1_Click;
button2.Click += button2_Click;
//this.FormClosing += Form1_FormClosing;
}
//Socket socketForClient;
private void button1_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(textBox1.Text.Trim()))
{
System.Windows.Forms.MessageBox.Show("Port Number Empty", "Error");
}
else
{
port_number = int.Parse(textBox1.Text);
createserver(Constants.No_Of_Clients);
serveripaddress();
infoBox1.Text = string.Format("The server is now listening at port {0} at ip address {1}", port_number, Constants.IP);
infoBox1.Text = infoBox1.Text + "\r\n" + string.Format("The server can listen to maximum {0} number of clients", Constants.No_Of_Clients);
}
}
// this code disconnects the server
private void button2_Click(object sender, EventArgs e)
{
try
{
tcpListener.Stop();
}
catch (Exception f)
{
MessageBox.Show(f.Message);
}
}
public void serveripaddress()
{
serverip.Text = "Server IP : " + Constants.IP;
//serverport.Text = "Port Number : " + port.ToString();
}
// Starts server
private void createserver(int no_of_clients)
{
tcpListener = new TcpListener(ipAddress, port_number);
tcpListener.Start();
for (int i = 0; i < no_of_clients; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}
} // end of createserver();
//listen to client receiving messages
public void Listeners()
{
Socket socketForClient;
try
{
socketForClient = tcpListener.AcceptSocket();
}
catch
{
System.Windows.Forms.MessageBox.Show(string.Format("Server failed to start at {0}:{1}", Constants.IP, port_number), "Error");
return;
}
if (socketForClient.Connected)
{
//System.Windows.Forms.MessageBox.Show("hello");
string string1 = string.Format("Client : " + socketForClient.RemoteEndPoint + " is now connected to server.");
infoBox1.Text = infoBox1.Text + "\r\n" + string1;
NetworkStream networkStream = new NetworkStream(socketForClient);
System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
string theString = "";
while (true)
{
try
{
theString = streamReader.ReadLine();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
// if (streamReader.ReadLine() == null )
//{
// System.Windows.Forms.MessageBox.Show(string.Format("Server failed to start at {0}:{1}", Constants.IP, port_number), "Error");
// }
if (theString != "exit")
{
textBox2.Text = textBox2.Text + "\r\n" + "-----------------------------------------------------------------------------------";
string string2 = string.Format("Message recieved from client(" + socketForClient.RemoteEndPoint + ") : " + theString);
textBox2.Text = textBox2.Text + "\r\n" + string2;
// ASCII code for the message from client
string string3 = string.Format("ASCII Code for message is : ");
textBox2.Text = textBox2.Text + "\r\n" + string3;
string string4 = "";
foreach (char c in theString)
{
string4 += string.Format(System.Convert.ToInt32(c) + " ");
}
textBox2.Text = textBox2.Text + string4;
// Hex value of message from client
string hex = "";
foreach (char c in theString)
{
int tmp = c;
hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
}
string string5 = string.Format("Hex Code for the message from client : " + hex);
textBox2.Text = textBox2.Text + "\r\n" + string5;
//sending acknowledgement to client
try
{
socketForClient.Send(new ASCIIEncoding().GetBytes("The string was recieved from Client(" + socketForClient.RemoteEndPoint + ") : " + theString));
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
} // end of if loop
// if exit from client
else
{
string string7 = string.Format("Client " + socketForClient.RemoteEndPoint + " has exited");
infoBox1.Text = infoBox1.Text + "\r\n" + string7;
break;
}
} // end of while loop
streamReader.Close();
networkStream.Close();
streamWriter.Close();
} // end of if loop
socketForClient.Close();
}
}
}
答案 0 :(得分:0)
要了解已关闭的客户端连接,您必须定期向客户端发送“心跳”消息。如果客户端连接中断,tcp / ip机制将在超时后通知您连接已死(无法记住异常的名称)。 如果客户端想知道连接是否已经死亡,他还必须发送心跳消息。 这是必需的,因为只有在通过此连接发送数据时,tcp连接才能识别丢失的连接。
对于第二个问题,您应该保留所有活动客户端的列表(您的变量socketForClient)。如果要结束服务器,请关闭所有客户端连接(列表中的客户端)。