启用的计时器不滴答
Enabled timer does not tick
我正在用c#写一个简单的tcp通讯程序。我想要的是在客户端收到特定消息时通过启用它来启动计时器。问题是,计时器在启用时不会滴答作响。我正在使用 System.Windows.Forms.Timer.
void ReceiveData()
{
int recv;
string stringData;
while (true)
{
recv = client.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
if (stringData == "/starttimer" & !timer1.Enabled)
{
timer1.Enabled = true;
break;
}
}
}
Stopwatch player1timer = new Stopwatch();
void timer1_Tick(object sender, EventArgs e)
{
if (player1timer.IsRunning)
{
pl1label.Text = Convert.ToDouble(2) - Convert.ToDouble(player1timer.Elapsed.Minutes.ToString("00")) + ":" +
Convert.ToString(Convert.ToDouble(59) - Convert.ToDouble(player1timer.Elapsed.Seconds.ToString("00"))) + "." +
Convert.ToString(Convert.ToDouble(999) - Convert.ToDouble(player1timer.Elapsed.Milliseconds.ToString("00")));
}
}
由于这是一个 UI 程序,您需要小心避免阻塞 UI 线程。
在您的示例中,Receive
可能会阻塞 UI 线程,直到有一些数据。如果计时器已经启用,或者如果它没有收到所需的消息,它将继续这样做。这将阻止 UI 执行其他操作,例如更新图形或处理鼠标和键盘事件。 从不阻塞 UI 线程
为避免这种情况,您需要使用异步编程或后台线程。由于后台线程需要对线程安全有相当好的理解,我会推荐异步方法。
我没有任何完整的例子,如果这是作业,这样的例子可能会适得其反,但总体方法应该是:
- 从 TcpListner
创建一个 TcpClient
- 从
TcpClient.GetStream()
获取 NetworkStream
- 将此流包装在 streamReader 中,并使用
ReadLineAsync()
读取行。在创建 reader. 时使用任何你想要的 text-encoding
- 等待返回的任务以获取实际字符串。
您可以在异步方法内的无限循环中执行此操作。 应该 不会阻塞,因为 await
会让 UI 线程在等待数据时做其他事情。请记住将方法的内容包装在 try/catch 中,否则可能会丢失异常。
这应该适用于演示概念的简单应用程序,但对于实际使用,我强烈建议使用库来处理通信。这很可能会更容易使用。
请注意,有些返回任务的方法是骗人的,实际上是假装异步的同步方法。这显然行不通,但从文档中很难判断,因此通常最简单的方法就是尝试。
我正在用c#写一个简单的tcp通讯程序。我想要的是在客户端收到特定消息时通过启用它来启动计时器。问题是,计时器在启用时不会滴答作响。我正在使用 System.Windows.Forms.Timer.
void ReceiveData()
{
int recv;
string stringData;
while (true)
{
recv = client.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
if (stringData == "/starttimer" & !timer1.Enabled)
{
timer1.Enabled = true;
break;
}
}
}
Stopwatch player1timer = new Stopwatch();
void timer1_Tick(object sender, EventArgs e)
{
if (player1timer.IsRunning)
{
pl1label.Text = Convert.ToDouble(2) - Convert.ToDouble(player1timer.Elapsed.Minutes.ToString("00")) + ":" +
Convert.ToString(Convert.ToDouble(59) - Convert.ToDouble(player1timer.Elapsed.Seconds.ToString("00"))) + "." +
Convert.ToString(Convert.ToDouble(999) - Convert.ToDouble(player1timer.Elapsed.Milliseconds.ToString("00")));
}
}
由于这是一个 UI 程序,您需要小心避免阻塞 UI 线程。
在您的示例中,Receive
可能会阻塞 UI 线程,直到有一些数据。如果计时器已经启用,或者如果它没有收到所需的消息,它将继续这样做。这将阻止 UI 执行其他操作,例如更新图形或处理鼠标和键盘事件。 从不阻塞 UI 线程
为避免这种情况,您需要使用异步编程或后台线程。由于后台线程需要对线程安全有相当好的理解,我会推荐异步方法。
我没有任何完整的例子,如果这是作业,这样的例子可能会适得其反,但总体方法应该是:
- 从 TcpListner 创建一个 TcpClient
- 从
TcpClient.GetStream()
获取 NetworkStream
- 将此流包装在 streamReader 中,并使用
ReadLineAsync()
读取行。在创建 reader. 时使用任何你想要的 text-encoding
- 等待返回的任务以获取实际字符串。
您可以在异步方法内的无限循环中执行此操作。 应该 不会阻塞,因为 await
会让 UI 线程在等待数据时做其他事情。请记住将方法的内容包装在 try/catch 中,否则可能会丢失异常。
这应该适用于演示概念的简单应用程序,但对于实际使用,我强烈建议使用库来处理通信。这很可能会更容易使用。
请注意,有些返回任务的方法是骗人的,实际上是假装异步的同步方法。这显然行不通,但从文档中很难判断,因此通常最简单的方法就是尝试。