服务器获胜';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;
}
}
我在代码中看到的唯一问题是buffer
和sendBuffer
是客户端之间共享的全局变量。你不能那样做。
如果多个客户端尝试向您发送数据,它们将覆盖彼此的buffer
。您可以将buffer
变量放入SuperSocket
中,但无论将其放在哪里,都要确保每个客户端都有一个单独的字节数组实例。
至于sendBuffer
,我真的不明白你为什么需要它;你就不能这么做吗?
await SendAsync(socket, length, 0, length.Length, 0);
await SendAsync(socket, msg, 0, msg.Length, 0);