gpt4 book ai didi

c# - 当 TCPClient 断开连接时显示消息

转载 作者:行者123 更新时间:2023-11-30 21:52:46 37 4
gpt4 key购买 nike

我一直在尝试让我的服务器应用程序在我的客户端断开连接时在标签中显示一条消息。

此时标签在客户端启动时会显示已连接客户端的IP地址,但当客户端关闭时,IP地址仍会显示在标签中。

到目前为止,我已经尝试过这些方法但没有任何运气:

            // DETECT IF CLIENT DISCONNECTED

//METHOD 1
if (bytesRead == 0)
{
ClientIPLabel.Text = "(No Clients Connected)";
break;
}

//METHOD 2
if (!tcpListener.Pending())
{
ClientIPLabel.Text = "(No Clients Connected)";
}

//METHOD 3
if (tcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
ClientIPLabel.Text = "(No Clients Connected)";
}

我确定这可能是我遗漏的一些简单的东西,我只是不知道它可能是什么。


编辑:我发现了一些解决方法,当我单击关闭客户端应用程序的按钮时,客户端会在关闭前向服务器发送一条消息。服务器知道,如果它收到此特定消息(在本例中为“SHUTDOWN CLIENT”),则将“ClientIPLabel.text”中的文本更改为“(未连接客户端)”

这在大多数情况下确实有效,但它有点像 hack,如果客户端由于错误或崩溃等原因关闭。服务器不知道它已断开连接,因此它仍会显示最后已知的已发送 IP。

第二次编辑: 所以看来解决方法对我不起作用。将其添加到我的项目后,出于某种原因,无论我的客户端向服务器发送什么消息都会导致显示“(未连接客户端)”消息。

我的客户端实际上仍处于连接状态并接收消息,但“ClientIPLabel”标记不正确



第三次编辑:这是一个片段,显示了我如何设置我的客户端以按照我在下面的一条评论中详细说明的方式将消息发送到服务器:

private void SendMessage(string msg)
{
NetworkStream clientStream = ConsoleClient.GetStream();

ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);

clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}

第四次编辑:我的服务器代码,以及我直接从客户端关闭按钮获取客户端断开连接消息的临时解决方法:

public partial class Server : Form
{
private TcpListener tcpListener;
private Thread listenThread;
private delegate void WriteMessageDelegate(string msg);

public Server()
{
InitializeComponent();
Server();
}


// WAIT FOR CLIENT

private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}

private void ListenForClients()
{
this.tcpListener.Start();


// GET CLIENT IP ADDRESS

while (true)
{
TcpClient client = this.tcpListener.AcceptTcpClient();
string clientIPAddress = "" + IPAddress.Parse(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
ClientIPLabel.Text = clientIPAddress;
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}


// COMMUNICATE WITH CLIENT

private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();

byte[] message = new byte[4096];
int bytesRead;

while (true)
{
bytesRead = 0;

try
{
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
break;
}


ASCIIEncoding encoder = new ASCIIEncoding();


// CHECK FOR CLIENT DISCONNECT

string msg = encoder.GetString(message, 0, bytesRead);
WriteMessage(msg);

if (msg.Equals("Client Disconnected (" + DateTime.Now + ")"))
{
ClientIPLabel.Text = ("(No Client Connected)");
}
}

tcpClient.Close();
}


第 5 次编辑: 我已经更新了我的代码,并且(几乎)实现了心跳定时器,但它仍然没有完全正确地设置......这是我的代码:

// CHECK FOR CLIENT DISCONNECT

// SHUTDOWN BUTTON PRESSED
string msg = encoder.GetString(message, 0, bytesRead);
WriteMessage(msg);

if (msg.Equals("Client Disconnected (" + DateTime.Now + ")"))
{
ClientIPLabel.Text = ("(No Client Connected)");
}
}
tcpClient.Close();
}

// CHECK FOR CONNECTION FAILED
void heartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
HandleClientComm("Check for connection");
}
catch (Exception)
{
Invoke((MethodInvoker)delegate
{
ClientIPLabel.Text = "(No Clients Connected)";
});
}
}

“(无客户端连接)”消息在计时器后自动弹出到我的服务器上,无论我的客户端是否已断开连接,因此它没有正确捕获异常。

我已经尝试实现 interceptwind 的建议,因为他写了它,但出于某种原因,我应该有 catch (Exception e) 我只有在摆脱 e 写成catch (Exception)。如果我将 e 留在那里,我会收到一条警告,提示 “变量 'e' 已声明但从未使用过”

此外,我知道 interceptwind 编写他的示例是为了使用我的 SendMessage() 方法,但该方法只在我的客户端中使用,所以我更改了代码以尝试使用我的 HandleClientComm() 方法,所以我想知道是否这就是无法正常工作的原因。我试过改变一些东西,但似乎仍然无法正常工作。 5 秒后我仍然收到消息“(没有客户端连接)”,即使我的客户端仍然连接并正常运行。


第 6 次编辑: 我试图调整我的 HandleClientComm() 方法来发送消息,但我显然错过了一些东西,因为我的“心跳计时器“仍在将我的 ClientIPLabel.text 切换为“(未连接客户端)”,即使我的客户端仍处于连接状态。

这是我的代码:

    // COMMUNICATE WITH CLIENT

private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] message = new byte[4096];
byte[] buffer = encoder.GetBytes("Send Message");
int bytesRead;
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
while (true)
{
bytesRead = 0;

try
{
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
break;
}


// START HEARTBEAT TIMER

System.Timers.Timer heartbeatTimer = new System.Timers.Timer();
heartbeatTimer.Interval = 5000;
heartbeatTimer.Elapsed += heartbeatTimer_Elapsed;
heartbeatTimer.Start();

// CHECK FOR CLIENT DISCONNECT

// SHUTDOWN BUTTON PRESSED
string msg = encoder.GetString(message, 0, bytesRead);
WriteMessage(msg);

if (msg.Equals("Client Disconnected (" + DateTime.Now + ")"))
{
ClientIPLabel.Text = ("(No Client Connected)");
}
}
tcpClient.Close();
}

// CHECK FOR CONNECTION FAILED
void heartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
HandleClientComm("Check for connection");
}
catch (Exception)
{
Invoke((MethodInvoker)delegate
{
ClientIPLabel.Text = "(No Clients Connected)";
});
}
}

最佳答案

鉴于OP限制Server不能向Client发送消息,另一种方式是Client每X秒(例如5秒)向Server发送一次心跳消息。

然后服务器将检查它是否在过去的 Y 秒(例如 30 秒)内收到了来自客户端的任何消息。如果没有,则意味着客户端已断开连接。

客户代码

    public Client()
{
...

//After connection, CALL ONCE ONLY
Timer heartbeatTimer = new System.Timers.Timer();
heartbeatTimer.Interval = 5000; //5 seconds
heartbeatTimer.Elapsed += heartbeatTimer_Elapsed;
heartbeatTimer.Start();
}

void heartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
{
SendMessage("Heartbeat");
}

服务器代码

    bool receiveHeartBeat = false;

public Server()
{
...

//After connection, CALL ONCE ONLY
Timer checkHeartbeatTimer = new System.Timers.Timer();
checkHeartbeatTimer.Interval = 30000; //30 seconds
checkHeartbeatTimer.Elapsed += checkHeartbeatTimer_Elapsed;
checkHeartbeatTimer.Start();
}

void checkHeartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if(receiveHeartBeat)
{
Invoke((MethodInvoker)delegate //prevent cross-thread exception
{
ClientIPLabel.Text = "Connected";
});
}
else
{
Invoke((MethodInvoker)delegate //prevent cross-thread exception
{
ClientIPLabel.Text = "(No Clients Connected)";
});
}
}

void WriteMessage(string msg)
{
receiveHeartBeat = true;
// rest of your code

}

关于c# - 当 TCPClient 断开连接时显示消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34456104/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com