Подскажите подойдет ли BackgroundWorker для такой цели :
После подключение юзера выполняется данный код
public static void AcceptPlayer(System.Net.Sockets.Socket socket) {
var ip = ((IPEndPoint) socket.RemoteEndPoint).Address;
ProtectProfiles.Add(ip, new ProtectProfile(socket));
}
нужно чтобы после new ProtectProfile(socket) в самом классе выполнялась функция, в которой будит содержаться while() и чтобы при выполнение его не блокировался поток - net 3.5 await async нету еще в нем. Или посоветуйте что я могу использовать как альтернитиву
Код сервера
private static IPEndPoint _localEndPoint;
private static TcpListener _listener;
public static Dictionary < IPAddress, ProtectProfile > ProtectProfiles = new Dictionary < IPAddress, ProtectProfile > ();
public void Awake() {
DontDestroyOnLoad(gameObject);
_localEndPoint = new IPEndPoint(IPAddress.Parse("178.44.152.88"), server.port + 2);
_listener = new TcpListener(_localEndPoint);
_listener.Start();
}
public void Update() {
if (_listener == null || !_listener.Pending()) return;
var connect = _listener.AcceptTcpClient();
var ip = ((IPEndPoint) connect.Client.RemoteEndPoint).Address;
UnityEngine.Debug.Log("Connect " + ip);
ProtectProfile.AcceptPlayer(connect);
}
Профиль
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace REDUX.CORE {
public class ProtectProfile {
public TcpClient TcpClient;
public ProtectProfile Profile;
public ProtectProfile(TcpClient client) {
Profile = this;
TcpClient = client;
var t = new Thread(() => Profile.GetStream()) {
IsBackground = true
};
t.Start();
}
public void GetStream() {
while (true) {
var stream = TcpClient.GetStream().Length;
switch (stream) {
default: Loom.QueueOnMainThread(() =>
Logger.Log(stream.ToString()));
continue;
}
}
}
#
region[STATIC CLASS]
public static Dictionary < IPAddress, ProtectProfile > ProtectProfiles =
new Dictionary < IPAddress, ProtectProfile > ();
public static void AcceptPlayer(TcpClient tcpClient) {
var ip = ((IPEndPoint) tcpClient.Client.RemoteEndPoint).Address;
ProtectProfiles.Add(ip, new ProtectProfile(tcpClient));
Loom.QueueOnMainThread(() =>
Logger.Log(ProtectProfiles.Count.ToString()));
}
#
endregion
}
}
Пример примитивного сервера для обработки входящий соединений от клиентов.
ClientSocketListener - открываем сокет и обрабатываем все входящие подключения
public sealed class ClientSocketListener
{
private static volatile ClientSocketListener INSTANCE;
private static object syncRoot = new Object();
private TcpListener _listener;
private Thread _thread;
private ClientSocketListener()
{
// Do nothing.
}
public void run()
{
_listener = new TcpListener(IPAddress.Any, Config.CLIENT_PORT);
_listener.Start();
_thread = new Thread(AwaitClientConnection);
_thread.IsBackground = true;
_thread.Start();
}
private void AwaitClientConnection()
{
while (true)
{
if (_listener.Pending())
{
TcpClient clientSocket = _listener.AcceptTcpClient();
accept(clientSocket);
}
}
}
private void accept(TcpClient tcpClient)
{
LoginClient client = new LoginClient(tcpClient);
}
public void stop()
{
_thread.Abort();
_listener.Stop();
}
public static ClientSocketListener getInstance
{
get
{
if (INSTANCE == null)
{
lock (syncRoot)
{
if (INSTANCE == null)
INSTANCE = new ClientSocketListener();
}
}
return INSTANCE;
}
}
}
LoginClient - создаём клиента и обрабатываем все его соединения.
public class LoginClient
{
protected TcpClient _client;
public NetworkStream _stream;
private byte[] _buffer;
public EndPoint _address;
public LoginClient(TcpClient client)
{
_client = client;
_stream = client.GetStream();
_address = client.Client.RemoteEndPoint;
new Thread(read).Start();
}
public void read()
{
try
{
_buffer = new byte[2];
_stream.BeginRead(_buffer, 0, 2, new AsyncCallback(OnReceiveCallbackStatic), null);
}
catch (Exception)
{
_client.Close();
}
}
private void OnReceiveCallbackStatic(IAsyncResult result)
{
try
{
if (_stream.EndRead(result) > 0)
{
short Length = BitConverter.ToInt16(_buffer, 0);
_buffer = new byte[Length - 2];
_stream.BeginRead(_buffer, 0, Length - 2, new AsyncCallback(OnReceiveCallback), result.AsyncState);
}
}
catch (Exception e)
{
_client.Close();
}
}
private void OnReceiveCallback(IAsyncResult result)
{
_stream.EndRead(result);
byte[] buff = new byte[_buffer.Length];
_buffer.CopyTo(buff, 0);
byte[] packet = new byte[buff.Length - 1];
Array.Copy(buff, 1, packet, 0, packet.Length);
// Отправка содержимого буфера в обработчик пакетов
ClientPacketHandler.handlePacket(this, buff[0], packet);
new System.Threading.Thread(read).Start();
}
}
Инициализация слушателя
ClientSocketListener.getInstance.run();
Остановка слушателя
ClientSocketListener.getInstance.stop();
Обработчик буфера и отправку ответа допишите сами. В LoginClient
классе можете создавать любые иные фоновые потоки по желанию. Они будут относиться именно к этому клиенту.
Метод обработки пакетов (пример):
public static LoginClientPacket handlePacket(LoginClient client, byte opcode, byte[] data)
{
LoginClientPacket msg = null;
switch (opcode)
{
case 0x00:
msg = new RecieveAuth(client, data);
break;
default:
_log.info("Unknown packet opcode: 0x" + opcode.ToString("X2"));
break;
}
return msg;
}
Список подключений не создавал. Не было необходимости.
Нагрузка на 200-300 подключений не проверял в C# реализации, но данная модель в Java держит гораздо больше, чем 50 человек.
P.S. если есть замечания по реализации, то с радостью выслушаю.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Нужно для отладки прочитать название всех полей класса и их значенияНу например, имеется экземпляр класса dog
У меня есть такой метод:
Подскажите, пожалуйста, почему при объявлении делегата не нужно вызывать его конструктор с помощью ключевого слова new?