服务器获胜';t在第一个客户端登录后正确地向新客户端发送数据

本文关键字:客户端 正确地 数据 登录 服务器 第一个 获胜 | 更新日期: 2023-09-27 18:27:10

我正在为我的2D游戏开发一台服务器,该服务器是在MonoGame的帮助下编程的,目前第一次登录没有问题,但当客户端在接受第一次连接后尝试连接时,它就会停止工作。如果这是我犯的一个简单的错误,我很抱歉,但我似乎找不到它

我试过在ServerSocket.BeginAccept上设置一个断点,它的连接似乎没有问题(即使对于第二个客户端,客户端的套接字的Connected状态也会变为"true"),我猜问题是从它试图向第二个客户发送数据时开始的(至少看起来很像),这就是我目前所拥有的

PS:在长度包之后发送的数据是一个包含长度为2082个字符的字符串的登录包,正如我首先所说,连接的第一个客户端接收或解析该登录包没有问题

我明天会继续调查,但在找到答案之前,我们将不胜感激!

使用的全局变量:

    private static byte[] buffer = new byte[1024];
    static BlockingCollection<byte[]> sendBuffer = new BlockingCollection<byte[]>();
    public static List<SuperSocket> Clients = new List<SuperSocket>();
    public static Socket ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

我如何设置服务器:

ServerSocket.Bind(new IPEndPoint(IPAddress.Any, 7171));
ServerSocket.Listen(50);
ServerSocket.BeginAccept(new AsyncCallback(acceptCallback), null)

acceptCallback的作用:

private static void acceptCallback(IAsyncResult ar)
{
  SuperSocket socket = new SuperSocket();
  socket.PlayerID = 15000; // use a generic ID before assigning the real ID
  socket.PlayerSocket = (Socket)ServerSocket.EndAccept(ar);
  Clients.Add(socket);
  socket.PlayerSocket.BeginReceive(buffer, 0, buffer.Length, 
  SocketFlags.None, new AsyncCallback(receiveCallback), socket);
  ServerSocket.BeginAccept(new AsyncCallback(acceptCallback), null);
}

receiveCallback:

private static async void receiveCallback(IAsyncResult ar)
    {
        SuperSocket socket = (SuperSocket)ar.AsyncState;
        try
        {
            SocketError errorCode;
            int received = socket.PlayerSocket.EndReceive(ar, out errorCode);
            if(errorCode != SocketError.Success)
            {
                socket.PlayerSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
                return;
            }
            byte[] dataBuffer = new byte[received];
            Array.Copy(buffer, dataBuffer, received);
            string text = Encoding.ASCII.GetString(dataBuffer);
            string text_to_send;
            int playerID = map.GetPlayerByName(text).ID;
            socket.PlayerID = playerID;
            string login_data = map.GetPlayerLoginData(playerID);
            Console.WriteLine("Player " + text + " (ID: " + playerID + ") logged in");
            /* Send length */
            text_to_send = login_data;
            byte[] msg = Encoding.ASCII.GetBytes(text_to_send);
            byte[] length = BitConverter.GetBytes(msg.Length);
            sendBuffer.Add(length);
            /* Send message */
            sendBuffer.Add(msg);
            int count;
            while (!sendBuffer.IsCompleted)
            {
                var sendData = sendBuffer.Take();
                count = 0;
                while (count < sendData.Length)
                {
                    count = await SendAsync(socket, sendData, count, sendData.Length - count, 0);
                }
                Console.WriteLine("Sent " + count.ToString() + " bytes of data");
            }
            socket.PlayerSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
        }
        catch(SocketException e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine(socket.PlayerID + " disconnected");
            socket.PlayerSocket.Dispose();
            Clients.Remove(socket);
        }
    }

SendAsync:

    private static Task<int> SendAsync(SuperSocket socket, byte[] buffer, int offset, int size, SocketFlags flags)
    {
        var result = socket.PlayerSocket.BeginSend(buffer, offset, size, flags, _ => { }, socket);
        return Task.Factory.FromAsync(result, (r) => socket.PlayerSocket.EndSend(r));
    }

SuperSocket:

class SuperSocket
{
    public int PlayerID;
    public Socket PlayerSocket;
    public SuperSocket()
    {
    }
    public SuperSocket(int _playerID)
    {
        PlayerID = _playerID;
    }
}

服务器获胜';t在第一个客户端登录后正确地向新客户端发送数据

我在代码中看到的唯一问题是buffersendBuffer是客户端之间共享的全局变量。你不能那样做。

如果多个客户端尝试向您发送数据,它们将覆盖彼此的buffer。您可以将buffer变量放入SuperSocket中,但无论将其放在哪里,都要确保每个客户端都有一个单独的字节数组实例。

至于sendBuffer,我真的不明白你为什么需要它;你就不能这么做吗?

await SendAsync(socket, length, 0, length.Length, 0);
await SendAsync(socket, msg, 0, msg.Length, 0);