c# - 控制台应用程序的一部分在 C# 几分钟后停止工作。请自行复制并粘贴此控制台应用程序代码
问题描述
下面的应用程序在输入 IP 地址后“运行”约 2 分钟(不确定确切时间),然后“停止”运行。“停止”是指当我在调试器运行 10 分钟后暂停调试器时它卡在这条线上:
知道为什么吗?
编辑:
您可以将下面的代码复制并粘贴到控制台应用程序中,它将运行。这需要几分钟,经过几次迭代后,它(通常)会卡在消息 161 上。
编辑: 此应用程序的发送部分停止工作。但对 UDP 的侦听按预期继续。请参阅已接受的答案,了解为什么会发生这种情况。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace UDPTest2
{
class Program
{
static string ip;
static UDPSender sender;
static UDPListener listener;
private static bool _quitFlag = false;
static void Main(string[] args)
{
//Console.WriteLine("Enter '1' to listen for UDP messages or '2' to send UDP messages, or 3 for both sending and receiving");
int choice = 3;
//if (Int32.TryParse(Console.ReadLine(), out choice))
//{
int port = 10001;
Console.WriteLine("Enter YOUR IP address (include periods)");
ip = Console.ReadLine();
switch (choice)
{
case 3: // send and receive from same terminal
Task taskReceive = new Task(() =>
{
listener = new UDPListener(ip, port);
listener.StartListener();
}, TaskCreationOptions.LongRunning);
taskReceive.Start();
sender = new UDPSender(ip, port);
sender.SendUDPContinuously(100);
break;
case 4:
break;
default:
Console.WriteLine("the input entered was not understood" + Environment.NewLine);
break;
}
//}
//else
//{
//Console.WriteLine("Invalid integer input");
//}
//Console.WriteLine("press any key to exit");
}
Console.ReadLine();
}
public class UDPSender
{
private Socket s;
private static byte sequenceNumber = 255;
private IPAddress toIpAddress;
private int portNumber;
private byte lastOctet; // first part of message byte array
public UDPSender(string ipAddress, int portNumber)
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
toIpAddress = IPAddress.Parse(ipAddress);
lastOctet = toIpAddress.GetAddressBytes()[3];
this.portNumber = portNumber;
}
public void SendUDPOnce()
{
byte[] sendbuf = new byte[4];
BuildByteMessage(lastOctet, Encoding.ASCII.GetBytes("PF"), sendbuf); // I can refactor this to just take a CommandParameters.BytesAndCommandEnum
IPEndPoint ep = new IPEndPoint(toIpAddress, portNumber);
s.SendTo(sendbuf, ep);
//Console.WriteLine("Sender: Message sent to the broadcast address: " + toIpAddress + Environment.NewLine + "Sender: contents (first byte is IP_Octet, second is sequenceNumber): " + string.Join(",", sendbuf));
}
public void SendUDPContinuously(int delayMiliseconds)
{
Timer timerstuff = new Timer(sate => SendUDPOnce(), null, 0, delayMiliseconds);
}
private void BuildByteMessage(byte lastOctet, byte[] parameterCommand, byte[] destination)
{
byte sequenceNum = CreateNextSequenceByte();
destination[0] = lastOctet;
destination[1] = sequenceNum;
Buffer.BlockCopy(parameterCommand, 0, destination, 2, parameterCommand.Length);
}
public byte CreateNextSequenceByte()
{
if (sequenceNumber != 255)
{
sequenceNumber++;
}
else
{
sequenceNumber = 0;
}
return sequenceNumber;
}
}
}
namespace UDPTest2
{
public class UDPListener
{
string ipAddress;
int listenPort;
public UDPListener(string ipAddress, int listenPort)
{
this.ipAddress = ipAddress;
this.listenPort = listenPort;
}
public void StartListener()
{
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse(ipAddress), listenPort);
try
{
while (!done)
{
//Console.WriteLine("Receiver: Waiting for broadcast...");
//First byte of the received message is the ASCII Mesage type flag: Q=Data, M=Metric, F=Fault. Second byte is the U8 sequence number. Third byte on is the actual data.
byte[] bytes = listener.Receive(ref groupEP);
byte[] data = new byte[bytes.Length - 2];
Buffer.BlockCopy(bytes, 2, data, 0, bytes.Length - 2);
Console.WriteLine("Receiver: broadcast from {0} :\nReceiver: {1}\nReceiver: contents of each byte: " + string.Join(", ", bytes),
groupEP.ToString(),
Encoding.ASCII.GetString(bytes)); // Or Encoding.ASCII.GetString(bytes, 0, bytes.Length));
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
listener.Close();
}
}
}
}
解决方案
Timer timerstuff
是一个局部变量。它可以在某个时候被 GC 处理掉。让它成为一个领域,使其永久化并保持活力。
public class UDPSender
{
private Timer _timerstuff;
...
public void SendUDPContinuously(int delayMiliseconds)
{
_timerstuff = new Timer(sate => SendUDPOnce(), null, 0, delayMiliseconds);
}
...
}
请参阅:自动内存管理和垃圾回收:释放内存(Microsoft Docs)
推荐阅读
- asynchronous - ClojureScript 的异步库是如何在浏览器中实现的?
- css - 如何将一个 div 居中但将第二个 div 一直保持在左侧?
- redirect - HAProxy 在 302 重定向之前添加一些标头
- typescript - TypeScript 中的 Lodash pickBy 给出错误:索引签名不兼容
- python-3.x - 从具有计算值的 2 个数据帧创建 Pandas 数据帧
- javascript - C# Cefsharp 无法获取ElementsByClassName
- ansible - Ansible 在字符串中查找列表的任何成员
- python - Discord bot 将嵌入消息发送到另一个频道
- java - 错误:无法创建 Java 虚拟机
- c# - 如何在没有继承属性的情况下在设计时填写列表?