通过TCP

所以我有一个非常真的奇怪的问题。这将需要一小堵墙才能完全说明。.

我正在为Unity游戏SCP:秘密实验室运行一些游戏服务器,并有一个定制的C#Discord Bot,它可以通过控制禁令,记录玩家警告,帮助员工减轻游戏中和Discord的影响,等,等等。

我正在尝试使两个平台通过本地机器地址(127.0.0.1)上的TCP端口相互通信。 我在机器人上设置了侦听器,当服务器准备就绪时,各个服务器(有7个)将连接到该侦听器。

我还进行了设置,以便如果从任一侧断开连接,服务器将关闭TcpClient,启动新的TcpClient,然后尝试连接,而侦听器只是继续在该端口上侦听连接再次关闭客户端之后。

我已经通过关闭客户端,套接字或只是在任一端重新启动程序对它进行了多次测试,并且它们似乎毫无故障地完美连接。

这是我的问题。

虽然游戏服务器保持空白,但一切都很好。玩家开始连接后,会经过5分钟到一个小时的时间,然后突然之间,似乎是随机的,服务器不再通过连接进行对话时会“听到”机器人,但是,机器人本身在遇到错误时不会出错尝试发送数据时,服务器永不接收任何数据。奇怪的是,服务器会继续通过连接发送自己的数据,而机器人接收该数据。

为在发生这种情况时尝试“重置”与新客户端的连接,我让服务器在首次连接时向bot发送初始心跳信号。这告诉机器人,该连接是在服务器端建立的,并启动一个循环线程,该线程将每10秒向服务器发送一次AYT消息,服务器必须对此进行回复。 如果该机器人发送了3条AYT消息而未返回响应,它将关闭TcpClient,并开始侦听新消息。 此时,服务器检测到连接已关闭,处置了它的客户端,实例化了一个新客户端,然后尝试成功连接。然后,机器人会接收到它的初始心跳,并再次为该客户端启动AYT计时器,但是服务器继续不会接收到它们。或从僵尸程序发送的任何数据,即使僵尸程序在这段时间内仍从服务器接收数据。

解决此问题的唯一方法是完全重启游戏服务器,然后它将连接到机器人并运行良好,直到不再运行为止。

作为参考,下面使用的代码的粘贴框。

机器人“监听器”方面

public class ProcessSTT
{
    private static ConcurrentDictionary<int,TcpClient> bag = new ConcurrentDictionary<int,TcpClient>();
    private static ConcurrentDictionary<int,int> heartbeats = new ConcurrentDictionary<int,int>();

    public static void SendData(string data,int port,ulong channel = 0)
    {
        try
        {
            BinaryFormatter formatter = new BinaryFormatter();
            SerializedData.SerializedData serializedData =
                new SerializedData.SerializedData { Data = data,Port = port,Channel = channel };
            //Console.WriteLine($"Sending {serializedData.Data}");
            if (!bag.ContainsKey(port))
            {
                Console.WriteLine($"STT: Bag does not contain {port}");
                return;
            }

            if (bag[port] != null && bag[port].Connected)
                formatter.Serialize(bag[port].GetStream(),serializedData);
            else
            {
                Console.WriteLine($"Error - Bag {port} is null or not connected.");
                if (bag.TryRemove(port,out TcpClient client))
                    client.Dispose();
            }
        }
        catch (IOException s)
        {
            Console.WriteLine($"STT: Socket exception,removing..");
            keyvaluepair<int,TcpClient> thingything = default;
            foreach (var thing in bag)
                if (thing.Key == port)
                    thingything = thing;

            if (bag.TryRemove(thingything.Key,out TcpClient _client))
            {
                _client.Close();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

    private static List<TcpListener> listener = new List<TcpListener>();
    public static void Init()
    {
        for (int i = 1; i < 8; i++)
        {
            TcpListener list = new TcpListener(IPAddress.Loopback,11900 + i);
            Console.WriteLine($"STT: Listener started for port {11900 + i}");
            listener.Add(list);
            list.Start();
            ThreadPool.QueueUserWorkItem(ListenForConn,list);
        }
    }

    public static async Task Heartbeat(int port)
    {
        await Task.Delay(10000);
        for (;;)
        {
            Console.WriteLine("STT: Starting Heartbeat");
            if (heartbeats[port] > 3)
            {
                Console.WriteLine($"STT: Removing {port} due to heartbeat timeout.");
                if (bag.TryRemove(port,out TcpClient client))
                    client.Close();
                heartbeats.TryRemove(port,out int _);
                return;
            }

            heartbeats[port]++;

            Console.WriteLine($"STT: Sending heartbeat to: {port}");
            if (!bag[port].Connected)
            {
                Console.WriteLine($"STT: {port} is null,removing.");
                if (bag.TryRemove(port,out TcpClient client))
                    client.Close();

                return;
            }
            SendData("ping",port,653737934150959115);
            await Task.Delay(10000);
        }
    }

    public static void ListenForConn(object token)
    {
        Console.WriteLine("STT: Listener started.");
        TcpListener listen = token as TcpListener;
            for (;;)
            {
                try
                {
                    TcpClient thing = listen.acceptTcpClient();
                    ThreadPool.QueueUserWorkItem(ListenOn,thing);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
        }
    }

    public static async Task ReceiveData(SerializedData.SerializedData data,TcpClient client)
    {
        try
        {
            if (data == null)
            {
                Console.WriteLine("STT: Received data null");
                return;
            }

            if (data.Data == "ping")
            {
                if (!bag.ContainsKey(data.Port))
                {
                    Console.WriteLine($"STT: Adding {data.Port}");
                    bag.TryAdd(data.Port,client);
                }

                if (!bag[data.Port].Connected || bag[data.Port] == null)
                {
                    Console.WriteLine($"STT: Bag {data.Port} not connected or null,removing.");
                    if (bag.TryRemove(data.Port,out TcpClient cli))
                    {
                        cli?.Close();
                    }
                }
                Console.WriteLine($"STT: Received heartbeat for: {data.Port}");
                if (!heartbeats.ContainsKey(data.Port))
                {
                    Heartbeat(data.Port);
                    heartbeats.TryAdd(data.Port,0);
                }
                else
                    heartbeats[data.Port]--;
                return;
            }

            Console.WriteLine(data.Data);
            data.Data = data.Data.Substring(data.Data.IndexOf('#') + 1);

            //Console.WriteLine("Getting guild.");
            SocketGuild guild = Bot.Discord.GetGuild(478381106798788639);
            //Console.WriteLine("Getting channel");
            SocketTextChannel chan = guild.GetTextChannel(data.Channel);
            //Console.WriteLine("Sending message.");
            await chan.SendMessageAsync($"Server {data.Port -= 7770}: {data.Data}");
            if (data.Port == 7771)
            {
                DiscordWebhookClient webhook = new DiscordWebhookClient(
                    "");
                await webhook.SendMessageAsync($"{data.Data}");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

    }

    public static void ListenOn(object token)
    {
        TcpClient client = token as TcpClient;
        try
        {
            BinaryFormatter formatter = new BinaryFormatter();
            for (;;)
            {
                SerializedData.SerializedData serializedData;
                if (!client.Connected)
                {
                    Console.WriteLine($"Client not connected..");
                    client.Close();
                    continue;
                }

                serializedData = formatter.Deserialize(client.GetStream()) as SerializedData.SerializedData;
                new Thread(() => ReceiveData(serializedData,client)).Start()
            }
        }
        catch (SerializationException s)
        {
            Console.WriteLine($"STT: Serialization exception,TcpClient> thingything = default;
            foreach (var thing in bag)
                if (thing.Value == client)
                    thingything = thing;

            if (bag.TryRemove(thingything.Key,out TcpClient _client))
            {
                _client.Close();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }
}

服务器“扬声器”端

public class ProcessSTT
{
    private static TcpClient tcpClient;
    public static readonly ConcurrentQueue<SerializedData.SerializedData> dataQueue = new ConcurrentQueue<SerializedData.SerializedData>();
    private static Thread _init;
    private static bool _locked;
    public static void Init()
    {
        if (_locked)
            return;
        _locked = true;
        Thread.Sleep(1000);
        try
        {
            Plugin.Log($"STT: Starting INIT.");
            tcpClient?.Close();
            tcpClient = new TcpClient();
            while (!tcpClient.Connected)
            {
                Plugin.Log($"STT: While loop start");
                Thread.Sleep(2000);
                try
                {
                    tcpClient.Connect("127.0.0.1",ServerConsole.Port + 4130);
                }
                catch (SocketException)
                {
                    tcpClient.Client.Disconnect(false);
                }
                catch (Exception e)
                {
                    Plugin.Log($"STT: {e}");
                }
            }

            Thread thread = new Thread(ReceiveData);
            thread.Start();
            SendData("ping",0);
            _locked = false;
        }
        catch (IOException i)
        {
            _init = new Thread(Init);
            _init.Start();
        }
        catch (Exception e)
        {
            ServerConsole.AddLog(e.ToString());
        }
    }

    public static void SendData(string data,ulong channel)
    {
        try
        {
            if (!tcpClient.Connected)
                throw new InvalidOperationException("Tcp Client not connected!");

            SerializedData.SerializedData serializedData = new SerializedData.SerializedData
            {
                Data = data,Port = ServerConsole.Port,Channel = channel
            };
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(tcpClient.GetStream(),serializedData);
            ServerConsole.AddLog($"Sent {data}");
        }
        catch (IOException i)
        {
            _init = new Thread(Init);
            _init.Start();
        }
        catch (Exception e)
        {
            ServerConsole.AddLog(e.ToString());
        }
    }

    public static void ReceiveData()
    {
        try
        {
            if (!tcpClient.Connected)
                throw new InvalidOperationException("Tcp Client not connected!");
            BinaryFormatter formatter = new BinaryFormatter();
            for (;;)
            {
                SerializedData.SerializedData deserialize =
                    formatter.Deserialize(tcpClient.GetStream()) as SerializedData.SerializedData;
                if (deserialize == null)
                    continue;
                dataQueue.Enqueue(deserialize);
            }
        }
        catch (SerializationException s)
        {
            _init = new Thread(Init);
            _init.Start();
        }
        catch (IOException e)
        {
            _init = new Thread(Init);
            _init.Start();
        }
        catch (Exception e)
        {
            ServerConsole.AddLog(e.ToString());
        }
    }
}

public class HandleQueue
{
    public static ulong channelid;
    public static void HandleQueuedItems()
    {
        while (ProcessSTT.dataQueue.TryDequeue(out SerializedData.SerializedData result))
        {
            string command = result.Data;
            Plugin.Log($"STT: Received {result.Data} for {result.Port}");
            if (result.Port != ServerConsole.Port)
                return;

            if (result.Data == "ping")
            {
                Plugin.Log("STT: BLART Heartbeat received.");
                ProcessSTT.SendData("ping",0);
                return;
            }

            channelid = result.Channel;

            try
            {
                GameCore.Console.singleton.TypeCommand($"/{command}",new BlartSender());
            }
            catch (Exception e)
            {
                ServerConsole.AddLog(e.ToString());
            }
        }
    }

    public static IEnumerator<float> Handle()
    {
        for (;;)
        {
            HandleQueuedItems();
            yield return Timing.WaitForSeconds(1f);
        }
    }
}

public class BlartSender : CommandSender
{
    public override void RaReply(string text,bool success,bool logToConsole,string overrideDisplay)
    {
        ProcessSTT.SendData($"{text}",HandleQueue.channelid);
    }

    public override void Print(string text)
    {
        ProcessSTT.SendData($"{text}",HandleQueue.channelid);
    }

    public override string SenderId => "BLART";
    public override string Nickname => "BLART";
    public override ulong Permissions => ServerStatic.GetPermissionsHandler().FullPerm;
    public override byte KickPower => Byte.MaxValue;
    public override bool FullPermissions => true;
}`
wenjin666666 回答:通过TCP

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/2940878.html

大家都在问