线程将数据发送到错误的客户端。这是线程安全问题吗?

Thread sending data to wrong client. Is this a thread safety issue?

我目前正在开发一个服务器,该服务器使用 consumer/producer 方法处理线程和阻塞集合,如下所示:

public class NetworkClient
{
    private bool _started = false;
    private int _clientId;
    private readonly Socket _socket;

    private static AutoResetEvent _lastMessageWasAckd = new AutoResetEvent(true);
    private static BlockingCollection<byte[]> _messageQueue = new BlockingCollection<byte[]>(); 
        

    public NetworkClient(Socket socket, int clientId)
    {
        this._socket = socket;
        this._clientId = clientId;
    }

    public int getClientID() {
        return _clientId;
    }

    public void SendMessage(string message)
    {
        Console.WriteLine("Adding to player's sending queue " + _clientId);
        _messageQueue.Add(Encoding.ASCII.GetBytes(message));
    }


    public void Start()
    {
        Thread receiver = new Thread(new ThreadStart(ReceivingThreadProc));
        Thread sender = new Thread(new ThreadStart(SendingThreadProc));
        receiver.Start();
        sender.Start();
        this._started = true;
    }
        
    public void Stop()
    {
        this._started = false;
    }

    private void ReceivingThreadProc()
    {
        byte[] bytes = new byte[1024];
        string data;
        try
        {
            while (_started && _socket.Connected)
            {
                int numByte = this._socket.Receive(bytes);
                data = Encoding.ASCII.GetString(bytes, 0, numByte);
                if (numByte == 0)
                {
                    break;
                }

                if (data == "ACK")
                {
                    _lastMessageWasAckd.Set();
                    continue;
                }

                // Acknowledge the message
                _socket.Send(Encoding.ASCII.GetBytes("ACK"));

                ServerReceiver.onEvent(this._clientId, data);
            }
        }
        catch (Exception e)
        {
            this._socket.Close();
        }
    }

    private void SendingThreadProc()
    {
        while (_started && _socket.Connected)
        {
            _lastMessageWasAckd.WaitOne();

            byte[] message = _messageQueue.Take();
                
            Console.WriteLine("Sending the following message to client number: " + _clientId);
            Console.WriteLine(System.Text.Encoding.ASCII.GetString(message));
                
            _socket.Send(message);

            _lastMessageWasAckd.Reset();
        }
    }
}

将为连接服务器的每个客户端创建一个 NetworkClient 实例。问题是有时一条消息排队等待发送到客户端 1(这由 SendMessage 方法中的 Console.Writeline 确认)但是该消息被发送到客户端 0(由控制台写入行显示SendingThreadProc 方法)代替。这是由于线程安全问题,还是我完全遗漏了什么?这通常发生在两条消息接连发送时。

如有任何帮助,我们将不胜感激。

编辑:

正如许多人正确指出的那样,我没有在我调用的地方添加 SendMessage 我将把这个 class 放在下面:

class NetworkServer
{
    private int latestClient = 0;
    private ServerReceiver _serverReceiver;
    private static readonly Dictionary<int, NetworkClient> clients = new Dictionary<int, NetworkClient>();
        
    public NetworkServer()
    {
        IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 5656);
        Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        this._serverReceiver = new ServerReceiver();
        this._serverReceiver.start();

        try
        {
            listener.Bind(endpoint);
            listener.Listen(10);

            while (true)
            {
                Socket clientSocket = listener.Accept();
                this.OnClientJoin(clientSocket);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
public static void SendClientMessage(int clientId, string package, CommandType commandType,
    Dictionary<string, object> data = null)
{
    if (data == null)
    {
        data = new Dictionary<string, object>();
    }
        
    SendClientMessageRaw(clientId, new NetworkCommand(clientId, package, commandType, data).ToJson());
}

public static void SendClientMessageRaw(int id, string message)
{
    Console.WriteLine("Supposed to send to client number " + clients[id].getClientID());
    clients[id].SendMessage(message);
}

private void OnClientJoin(Socket socket)
{
    // Add client to array, perform handshake?
    NetworkClient networkClient = new NetworkClient(socket, latestClient);
    clients.Add(latestClient, networkClient);
    Console.WriteLine("player added :" + latestClient);
    networkClient.Start();
    latestClient++;
        
    if (latestClient == 2)
    {
        SendClientMessage(1, "Test", CommandType.Ping, null);
    }
}

会不会是因为您的消息队列是静态的,因此在所有 NetworkClient 之间共享?意味着客户端 A 可以为客户端 B 提取消息?

可能就像从属性中删除静态一样简单。