Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux 下的 Console.Read 将导致管道无法读取到消息 #139

Open
lindexi opened this issue Nov 12, 2023 · 0 comments
Open

Linux 下的 Console.Read 将导致管道无法读取到消息 #139

lindexi opened this issue Nov 12, 2023 · 0 comments

Comments

@lindexi
Copy link
Member

lindexi commented Nov 12, 2023

在 Linux 下的 UOS 系统里面进行测试,如以下代码

                var peer = await ipcProvider.GetAndConnectToPeerAsync(args[0]);
                peer.MessageReceived += (sender, messageArgs) =>
                {
                    Console.WriteLine(
                        $"[{Environment.ProcessId}] 收到 {peer.PeerName} 的回复消息:{Encoding.UTF8.GetString(messageArgs.Message.Body.AsSpan())}");
                };
                await peer.NotifyAsync(new IpcMessage("Hello",
                    Encoding.UTF8.GetBytes($"Hello,进程号是 {Environment.ProcessId} 发送过来消息")));
                Console.WriteLine($"[{Environment.ProcessId}] 完成发送消息");

                 Console.Read();

那么以上的 MessageReceived 事件将不会被触发,且是因为底层的管道读取无法返回。一旦使用 Task.Run 包括起来,如以下代码,即可正常收到消息

                Task.Run(async () =>
                {
                    var peer = await ipcProvider.GetAndConnectToPeerAsync(args[0]);
                    peer.MessageReceived += (sender, messageArgs) =>
                    {
                        Console.WriteLine(
                            $"[{Environment.ProcessId}] 收到 {peer.PeerName} 的回复消息:{Encoding.UTF8.GetString(messageArgs.Message.Body.AsSpan())}");
                    };
                    await peer.NotifyAsync(new IpcMessage("Hello",
                        Encoding.UTF8.GetBytes($"Hello,进程号是 {Environment.ProcessId} 发送过来消息")));
                    Console.WriteLine($"[{Environment.ProcessId}] 完成发送消息");
                });

                 Console.Read();

如果给 Task.Run 加上 await 如以下代码,那将无法收到回复,依然是管道读取没有返回,可参考 91043ee 的更改

                await Task.Run(async () =>
                {
                    var peer = await ipcProvider.GetAndConnectToPeerAsync(args[0]);
                    peer.MessageReceived += (sender, messageArgs) =>
                    {
                        Console.WriteLine(
                            $"[{Environment.ProcessId}] 收到 {peer.PeerName} 的回复消息:{Encoding.UTF8.GetString(messageArgs.Message.Body.AsSpan())}");
                    };
                    await peer.NotifyAsync(new IpcMessage("Hello",
                        Encoding.UTF8.GetBytes($"Hello,进程号是 {Environment.ProcessId} 发送过来消息")));
                    Console.WriteLine($"[{Environment.ProcessId}] 完成发送消息");
                });

                 Console.Read();

以上代码情况可以排除 Task Main 导致的问题,因为一旦将 Console.Read 换掉,那就可以正常读取到管道里面的消息,管道可以返回,如 8d27486 代码更改

                await Task.Run(async () =>
                {
                    var peer = await ipcProvider.GetAndConnectToPeerAsync(args[0]);
                    peer.MessageReceived += (sender, messageArgs) =>
                    {
                        Console.WriteLine(
                            $"[{Environment.ProcessId}] 收到 {peer.PeerName} 的回复消息:{Encoding.UTF8.GetString(messageArgs.Message.Body.AsSpan())}");
                    };
                    await peer.NotifyAsync(new IpcMessage("Hello",
                        Encoding.UTF8.GetBytes($"Hello,进程号是 {Environment.ProcessId} 发送过来消息")));
                    Console.WriteLine($"[{Environment.ProcessId}] 完成发送消息");
                });

            for (int i = 0; i < int.MaxValue; i++)
            {
                await Task.Delay(TimeSpan.FromSeconds(1));
            }

以上问题的简单复现代码:

    internal class Program
    {
        private static async Task Main(string[] args)
        {
            var ipcProvider = new IpcProvider();
            ipcProvider.StartServer();

            if (args.Length == 0)
            {
                var currentName = ipcProvider.IpcContext.PipeName;
                // 将当前的进程的 Name 传递给另一个进程,用来达成通讯
                var mainModuleFileName = Process.GetCurrentProcess().MainModule.FileName;
                Console.WriteLine($"[{Environment.ProcessId}] 准备启动 {mainModuleFileName} 参数:{currentName}");
                Process.Start(mainModuleFileName, currentName);
            }
            else
            {
                // 这是被启动的进程,主动连接发送消息
                Console.WriteLine($"[{Environment.ProcessId}] 开始连接对方进程");

                var peer = await ipcProvider.GetAndConnectToPeerAsync(args[0]);
                peer.MessageReceived += (sender, messageArgs) =>
                {
                    Console.WriteLine(
                        $"[{Environment.ProcessId}] 收到 {peer.PeerName} 的回复消息:{Encoding.UTF8.GetString(messageArgs.Message.Body.AsSpan())}");
                };
                await peer.NotifyAsync(new IpcMessage("Hello",
                    Encoding.UTF8.GetBytes($"Hello,进程号是 {Environment.ProcessId} 发送过来消息")));
                Console.WriteLine($"[{Environment.ProcessId}] 完成发送消息");
            }

            ipcProvider.PeerConnected += (sender, connectedArgs) =>
            {
                Console.WriteLine($"[{Environment.ProcessId}] 收到 {connectedArgs.Peer.PeerName} 的连接");

                connectedArgs.Peer.MessageReceived += async (o, messageArgs) =>
                {
                    Console.WriteLine($"[{Environment.ProcessId}] 收到 {messageArgs.PeerName} 的消息:{Encoding.UTF8.GetString(messageArgs.Message.Body.AsSpan())}");

                    await Task.Delay(TimeSpan.FromSeconds(1));

                    // 反向发送消息给对方
                    Console.WriteLine($"[{Environment.ProcessId}] 向 {connectedArgs.Peer.PeerName} 回复消息");
                    await connectedArgs.Peer.NotifyAsync(new IpcMessage("回复", Encoding.UTF8.GetBytes($"收到你的消息")));
                    Console.WriteLine($"[{Environment.ProcessId}] 完成向 {connectedArgs.Peer.PeerName} 回复消息");
                };
            };

            Console.WriteLine($"[{Environment.ProcessId}] 等待退出");
            Console.Read();
            Console.WriteLine($"[{Environment.ProcessId}] 进程准备退出");
        }
    }

以上代码在 Windows 上正常,在 Linux 的 UOS 系统无法收到回复消息,也就是 peer.MessageReceived 对应的事件没有触发,调试可以看到管道没有读取返回

详细的各个测试步骤请看 #140

可能是 Linux 的 Console.Read 投毒

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant