C#UDP数据包中继器:重新启动将不起作用

C#UDP数据包中继器:重新启动将不起作用,c#,multithreading,visual-studio,error-handling,C#,Multithreading,Visual Studio,Error Handling,长话短说:我需要一个UDP数据包转发器/重发器。 它应该做什么? 嗯,它应该在特定的端口上侦听输入的数据包,然后在指定的端口上将它们发回。 该程序有一个GUI,其中一个按钮用于运行和关闭程序 这个程序运行得很好,直到我开始。。。好吧,去他妈的 慢慢地,我设法把大部分虫子都弄出来了。除了一个。。。或更多: 问题是,如果我想重新启动程序,通过单击按钮,我在上面的链接中得到了相同的错误 我曾尝试实现Shutdown()、Dispose()、Disconnect()、UDP_Client=null以及

长话短说:我需要一个UDP数据包转发器/重发器。 它应该做什么? 嗯,它应该在特定的端口上侦听输入的数据包,然后在指定的端口上将它们发回。 该程序有一个GUI,其中一个按钮用于运行和关闭程序

这个程序运行得很好,直到我开始。。。好吧,去他妈的

慢慢地,我设法把大部分虫子都弄出来了。除了一个。。。或更多:

问题是,如果我想重新启动程序,通过单击按钮,我在上面的链接中得到了相同的错误

我曾尝试实现Shutdown()、Dispose()、Disconnect()、UDP_Client=null以及我用谷歌搜索过的更多功能,但它要么生成了新错误,要么没有效果

using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Packet_Repeater
{
    public partial class Form1 : Form
    {
        public bool connection_status = false;
        UdpClient[]     UDP_Client;
        IPEndPoint[]    IP_End_Point;
        IPAddress[][]   IP_Address;
        Thread[]        Task;
        public int[] upd_client_src_port, udp_client_dst_port;
        public bool[] packet_rxd;
        public bool[] task_running;
        public byte[][] BUFFER;
        public int[,] UDP_Client_num;

    public Form1()
    {
        InitializeComponent();
    }

    public void Init_Size(int num)
    {
        UDP_Client              = new UdpClient[num];
        IP_End_Point            = new IPEndPoint[num];
        IP_Address              = new IPAddress[num][];
        Task                    = new Thread[num];
        upd_client_src_port     = new int[num];
        udp_client_dst_port     = new int[num];
        packet_rxd              = new bool[num];
        BUFFER                  = new byte[num][];
        UDP_Client_num          = new int[num,2];
        task_running            = new bool[num];
    }

    public void UDP_Init(int client_num, string target_ip, int src_port, int dst_port)
    {
        upd_client_src_port[client_num] = src_port;
        udp_client_dst_port[client_num] = dst_port;

        BUFFER[client_num] = new byte[1536];

        if(target_ip == "Any")
        {
            IP_End_Point[client_num] = new IPEndPoint(IPAddress.Any, udp_client_dst_port[client_num]);
        }
        else
        {
            IP_Address[client_num] = Dns.GetHostAddresses(target_ip);
            IP_End_Point[client_num] = new IPEndPoint(IP_Address[client_num][0], udp_client_dst_port[client_num]);
        }
        UDP_Client[client_num] = new UdpClient(upd_client_src_port[client_num]);
        UDP_Client[client_num].Client.SendTimeout       =   500;
        UDP_Client[client_num].Client.ReceiveTimeout    =   500;
    }

    public void Run_Client(int listner_client_num, int destination_client_num)
    {
        task_running[listner_client_num] = true;
        while (connection_status)
        {
            try
            {
                BUFFER[listner_client_num] = UDP_Client[listner_client_num].Receive(ref IP_End_Point[listner_client_num]);
                UDP_Client[destination_client_num].Send(BUFFER[listner_client_num], BUFFER[listner_client_num].Length, IP_End_Point[destination_client_num]);
            }
            catch (Exception) { }
        }
        Array.Clear(BUFFER[listner_client_num], 0, BUFFER[listner_client_num].Length);
// Thread.Sleep(10000);
        UDP_Client[listner_client_num].Close();
        task_running[listner_client_num] = false;
    }

    public void button_Click(object sender, EventArgs e)
    {
        int number_of_connections = 2;

        if(!connection_status)
        {
            button.Enabled = false;
            connection_status = true;

            Init_Size(number_of_connections);

            UDP_Client_num[0, 0] = 0;
            UDP_Client_num[0, 1] = 1;
            UDP_Client_num[1, 0] = 1;
            UDP_Client_num[1, 1] = 0;

            UDP_Init(0, "Any", 9700, 9701);
            UDP_Init(1, "Any", 9600, 9601);
// the Problem is in this for() cycle
            for (UInt32 i = 0; i < (number_of_connections-1); i++)
            {
                Task[i] = new Thread(ThreadStart => Run_Client(UDP_Client_num[i, 0], UDP_Client_num[i, 1]));
                Task[i].Start();
            }
/*   This works OK:
myTask[0] = new Thread(ThreadStart => Run_Client(UDP_Client_num[0, 0], UDP_Client_num[0, 1]));
                myTask[0].Start();

                myTask[1] = new Thread(ThreadStart => Run_Client(UDP_Client_num[1, 0], UDP_Client_num[1, 1]));
                myTask[1].Start();
*/



      button.Text = "Close";
            button.Enabled = true;
        }
        else
        {
            connection_status = false;
            button.Enabled = false;
            for (int i = 0; i < (number_of_connections-1);)
            {
                if(!task_running[i])
                {
                    i++;
                }
            }
            button.Text = "Run";
            button.Enabled = true;
        }
        }
    }
}
这帮助我发现,恩德的一个克林特根本没有关闭。 因此,我在beggining和Run_Client()的末尾添加了一个write to textbox函数。
由于某些原因,一个任务[]无法启动。因此,这是一个线程问题,而不是NetSocket。

问题和解决方案非常简单。由于某种原因,这一行出现了线程问题:

for (int i = 0; i < (number_of_connections); i++)
{
  Task[i] = new Thread(ThreadStart => Run_Client(UDP_Client_num[i, 0], UDP_Client_num[i, 1]));
  Task[i].Start();
  while(!task_running[i])// <<-- This is probably a better Solution
  {
    Thread.Sleep(1);
  }
  // Thread.Sleep(100);   // <<-- This Solved the Problem
}
这向我显示了所有正在使用的udp端口


解决方案是在for()循环中将主线程设置为睡眠一段时间。我已将其设置为100ms,但maybee less也可以。(尚未尝试过。)

请参阅网页:。连接有3项。1) 来源IP。2) 目标IP。3) 端口号。不能有多个连接同时连接所有三个项目。这就是造成错误的原因。使用多播侦听器,查看您的链接,您可以与PC建立一个虚拟连接,并在PC上创建一个端点,该端点称为IPAddressAny。PC上只有一个应用程序可以使用相同的端口号连接到IPAnyAddress。使用多播,您不需要完全连接,因为它是广播类型的消息。相反,你加入了一个团体。所以你说我在正确的轨道上?问题是,我的程序尝试重新创建具有相同IP/端口配置的UDP客户端,与以前一样。这不是我的本意。我想通过第二次单击按钮关闭所有UDP客户端,并在关闭应用程序时释放所有端口。通过第三次单击该按钮,它应该可以使用以前发布的IP/端口重新创建所有UDP客户端,而不会出现问题。这就是我想要做的。在代码中的某个地方,您试图打开一个已经打开的连接。可能是在打开新连接时打开了同一个客户端两次,或者是没有正确关闭连接。如果您有两个udp客户端侦听相同的端口号(广播),则必须使用加入组。问题肯定是未关闭的客户端。我使用了这个cmd netstat-a-b-n-pdp-o,并看到端口9700保持打开状态。所以一个Close()被跳过或失败。我找不到它,你必须这样做。向代码中添加一些调试语句以找出根本原因。Thread.Sleep不应用于修复线程问题,因为无法保证所需的睡眠时间。与其使用线程,不如考虑使用与AcYNC/AWED关键字相结合的任务,并研究为什么延迟会解决问题,而不是修补问题。我已经把线程放在一个WHEELY()循环中,检查任务[I]是否已经运行。如果它没有运行,main()代码将一次又一次地等待(进入睡眠状态1毫秒),直到任务[i]运行。这是一种更好的方法吗?您可以在这里使用互斥体/信号量/信令机制来通信任务是否已启动。
for (int i = 0; i < (number_of_connections); i++)
{
  Task[i] = new Thread(ThreadStart => Run_Client(UDP_Client_num[i, 0], UDP_Client_num[i, 1]));
  Task[i].Start();
  while(!task_running[i])// <<-- This is probably a better Solution
  {
    Thread.Sleep(1);
  }
  // Thread.Sleep(100);   // <<-- This Solved the Problem
}
netstat -a -n -p udp -o