我最近编写了一个套接字管理器,用于接收与我的游戏服务器的连接。每次客户端连接时,都会创建一个新的GameClient实例。问题是,目前正在创建3个GameClient实例,我不知道为什么。有人可以提供帮助,因为我只想要一个连接而且我真的不确定它为什么要创建3?
我的代码如下......
namespace Emulator.Core.Network.GameSockets
{
using System;
using System.Net;
using System.Net.Sockets;
using Base.Game.Habbo.Players.Players;
using NLog;
internal sealed class GameSocketManager : IDisposable
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
private readonly Socket _gameSocket;
public GameSocketManager()
{
_gameSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Start();
}
private void Start()
{
var gameSocketPort = Convert.ToInt32(Config.GetConfigValueByKey("game.socket.port"));
var gameSocketBacklog = Convert.ToInt32(Config.GetConfigValueByKey("game.socket.backlog"));
_gameSocket.Bind(new IPEndPoint(IPAddress.Any, gameSocketPort));
_gameSocket.Listen(gameSocketBacklog);
_gameSocket.BeginAccept(OnAcceptConnection, _gameSocket);
}
private void OnAcceptConnection(IAsyncResult asyncResult)
{
try
{
if (_gameSocket == null)
{
return;
}
var server = (Socket)asyncResult.AsyncState;
var client = server.EndAccept(asyncResult);
var uniqueId = Guid.NewGuid().ToString();
var newPlayer = new GameClient(client, uniqueId);
if (!GameManager.PlayerManager.TryAddPlayer(newPlayer))
{
Logger.Error("Failed to register new player on " + client.RemoteEndPoint);
}
}
catch (SocketException socketException)
{
Logger.Fatal("Failed to accept socket connection: " + socketException.Message);
Logger.Fatal(socketException);
}
finally
{
_gameSocket?.BeginAccept(OnAcceptConnection, _gameSocket);
}
}
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (!disposing)
{
return;
}
if (_gameSocket == null)
{
return;
}
_gameSocket.Shutdown(SocketShutdown.Both);
_gameSocket.Close();
_gameSocket.Dispose();
}
}
}
GameClient:
public sealed class GameClient : GameClientData, IDisposable
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
private readonly Socket _socket;
private readonly byte[] _buffer;
private readonly string _guid;
private ARC4 _rc4Client;
private PlayerTimer _playerTimer;
private bool _disposing;
internal GameClient(Socket socket, string guid)
{
_socket = socket;
_socket.SendBufferSize = Convert.ToInt32(Hariak.HariakServer.Config.GetConfigValueByKey("packet.buffer.size"));
_buffer = new byte[Convert.ToInt32(Hariak.HariakServer.Config.GetConfigValueByKey("packet.buffer.size"))];
_guid = guid;
PingCount = 0;
Utilities = new PlayerUtilities(this);
StartReceive();
}
private void StartReceive()
{
try
{
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, OnDataReceived, _socket);
}
catch (SocketException exception)
{
Logger.Error(exception, "Failed to start receiving data on connection socket.");
Dispose();
}
}
private void ProcessPacketData(byte[] receivedData)
{
_rc4Client?.Decrypt(ref receivedData);
var receivedDataPacketId = receivedData[0];
if (receivedDataPacketId == 67)
{
return;
}
if (receivedDataPacketId == 60)
{
const string crossDomainPolicy = "<?xml version=\"1.0\"?>\r\n"
+ "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\r\n"
+ "<cross-domain-policy>\r\n"
+ "<site-control permitted-cross-domain-policies=\"master-only\"/>\r\n"
+ "<allow-access-from domain=\"*\" to-ports=\"*\" />\r\n"
+ "</cross-domain-policy>\x0";
SendString(crossDomainPolicy);
}
else
{
using (var reader = new BinaryReader(new MemoryStream(receivedData)))
{
if (receivedData.Length < 4)
{
return;
}
var packetLength = PacketUtilities.DecodeInt32(reader.ReadBytes(4));
if (reader.BaseStream.Length - 4 < packetLength)
{
return;
}
if (packetLength < 0 || packetLength > 5120)
{
return;
}
var packetBytes = reader.ReadBytes(packetLength);
using (var binaryReader = new BinaryReader(new MemoryStream(packetBytes)))
{
var packetHeader = PacketUtilities.DecodeInt16(binaryReader.ReadBytes(2));
var packetBodyBytes = new byte[packetBytes.Length - 2];
Buffer.BlockCopy(packetBytes, 2, packetBodyBytes, 0, packetBytes.Length - 2);
var packetEvent = new PacketEvent(packetHeader, packetBodyBytes);
if (!Hariak.HariakServer.GameManager.PacketManager.ProcessPacket(this, packetEvent))
{
Logger.Error("Failed to execute packet " + packetEvent.PacketId);
}
}
if (reader.BaseStream.Length - 4 <= packetLength)
{
return;
}
var extra = new byte[reader.BaseStream.Length - reader.BaseStream.Position];
Buffer.BlockCopy(receivedData, (int)reader.BaseStream.Position, extra, 0, (int)(reader.BaseStream.Length - reader.BaseStream.Position));
ProcessPacketData(extra);
}
}
}
private void OnDataReceived(IAsyncResult iAsyncResult)
{
try
{
var bytesReceived = _socket.EndReceive(iAsyncResult);
if (bytesReceived == 0)
{
return;
}
var packet = new byte[bytesReceived];
Array.Copy(_buffer, packet, bytesReceived);
ProcessPacketData(packet);
}
catch
{
Dispose();
}
finally
{
try
{
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, OnDataReceived, _socket);
}
catch
{
Dispose();
}
}
}
internal void Authenticate(string sso)
{
try
{
if (!TryLoadGameClientData(this, sso))
{
Dispose();
return;
}
_playerTimer = new PlayerTimer(this);
//todo: ban checking
//todo: load userstats
SendComposer(new AuthenticationComposer());
SendComposer(new AvatarEffectsComposer(Components.EffectComponent.PlayerEffects));
SendComposer(new NavigatorSettingsComposer(SelectColumnInt("home_room")));
//todo: FavouritesComposer
//todo: FigureSetIdsComposer
SendComposer(new UserRightsComposer(SelectColumnInt("rank")));
SendComposer(new CheckAvailabilityComposer());
//todo: AchievementScoreComposer
SendComposer(new BuildersClubMembershipComposer());
//todo: CfhTopicsInitComposer
//todo: BadgeDefinitionsComposer
//todo: SoundSettingsComposer
UpdateColumn("machine_id", MachineId);
//todo: give rank badge
//todo: subscriptions
Utilities.SendMotdNotification("Welcome message, using Hariak Emulator.");
//todo: check rewards
Logger.Info(SelectColumn("username") + " logged in");
}
catch (Exception exception)
{
Logger.Error(exception, "Error during player authentication.");
}
}
internal void SendComposer(PacketComposer packetComposer)
{
Logger.Trace("Sending Composer: " + packetComposer.ComposerId);
SendData(packetComposer.GetFinalBytes());
}
private void SendString(string data)
{
SendData(Encoding.UTF8.GetBytes(data));
}
internal void SendData(byte[] data)
{
try
{
_socket.BeginSend(data, 0, data.Length, 0, OnSend, null);
}
catch (SocketException socketException)
{
Logger.Error("Error sending message to socket: " + socketException.Message);
Logger.Error(socketException);
Dispose();
}
}
private void OnSend(IAsyncResult asyncResult)
{
try
{
if (_socket == null)
{
return;
}
_socket.EndSend(asyncResult);
}
catch (SocketException)
{
Dispose();
}
}
internal ARC4 Rc4Client
{
set { _rc4Client = value; }
get { return _rc4Client; }
}
internal string MachineId { private get; set; }
internal PlayerUtilities Utilities { get; }
internal string Guid => _guid;
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (!disposing || _disposing)
{
return;
}
_disposing = true;
_playerTimer?.Dispose();
if (!Hariak.HariakServer.GameManager.PlayerManager.TryRemovePlayer(_guid))
{
Logger.Error("Failed to remove a players instance from PlayerManager.");
}
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
}