BackgroundWorker для while

213
18 июля 2018, 21:50

Подскажите подойдет ли 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
    }
}
Answer 1

Пример примитивного сервера для обработки входящий соединений от клиентов.

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. если есть замечания по реализации, то с радостью выслушаю.

READ ALSO
Перечислить все поля и их значения C#

Перечислить все поля и их значения C#

Нужно для отладки прочитать название всех полей класса и их значенияНу например, имеется экземпляр класса dog

184
Редактирование datagrid wpf

Редактирование datagrid wpf

чувствую себя совсем тупымне могу сделать редактируемую таблицу

198
Конструктор делегата

Конструктор делегата

Подскажите, пожалуйста, почему при объявлении делегата не нужно вызывать его конструктор с помощью ключевого слова new?

184