C# `BinaryReader.ReadBoolean` 卡住了

C# `BinaryReader.ReadBoolean` stuck

客户端:

类似于我的代码:

var socket = Connect();
var reader = new BinaryReader(socket.GetStream());
var writer = new BinaryWriter(socket.GetStream());

// In other thread
writer.Write((byte) 5);
writer.Write("C:\no-file.exe");
var exists = reader.ReadBoolean();

卡在 System.Net.Sockets.Socket.Receive

// Decompiled with JetBrains decompiler
UnsafeNclNativeMethods.OSSOCK.recv(this.m_Handle.DangerousGetHandle(), numPtr + offset, size, socketFlags);

我可以在 WireShark 中看到带有我的布尔值的数据包,但是 ReadBoolean 仍在执行并且 socket.Available 等于零。

服务器原型:

像真实服务器一样运行并导致相同问题的最少代码。

var server = new TcpListener(IPAddress.Any, 2386);
server.Start();

var socket = server.AcceptTcpClient();
socket.NoDelay = true;
Console.WriteLine("Connected: " + socket.Client.RemoteEndPoint);

var stream = socket.GetStream();
var reader = new BinaryReader(stream);
var writer = new BinaryWriter(stream);

while (socket.Connected) {
    while (!stream.DataAvailable);

    if (stream.ReadByte() != 5) {
        break;
    }

    var path = reader.ReadString();
    Console.WriteLine("Requested file " + path);

    var exists = File.Exists(path);
    writer.Write(exists);

    writer.Flush();
    Console.WriteLine(exists ? "File exists" : "Not found");
}

Console.WriteLine("Disconnected: " + socket.Client.RemoteEndPoint);

我发现我的代码中有其他线程窃取了我的布尔值。

// TcpClient thread inside Connect method
while (client.Connected) {
    DispatchPacketType(stream.ReadByte());
}

// Thread that calls Connect
reader.ReadBoolean(); // stuck!

编辑:

So I made WaitPacket method to fix this problem. Not the best solution, but this works.

制作特殊的等待方法是完全错误的,因为它导致了很多问题。唯一的正常决策是项目重构

同样的情况你可以试试:

  1. 拒绝读取数据包的 while 循环 (DispatchPacketType)。现在客户端发送数据包的类型字节及其内容并以相同的方法读取服务器回复(例如 FetchSomeData),因为服务器(在我的情况下)按顺序响应。
  2. 避免与来自多个线程的相同 TCPClient 交互,或使用他的评论中提到的 @500-Internal Server Error 的储物柜。我重写了多行代码,现在它更安全、更高效。