예제 #1
0
        /*
         * Проблема с костылями состоит в следующем. Отправка сообщения может быть реализована двумя путями: из обработчика OnData и из клиента и сервера напрямую. Если отправка выполняется из обработчика
         * OnData, то используется сокет SocketToSend (см. первый костыль). В любом случае, откуда бы ни была отправка, используется метод Send этого класса. Если отправка из обработчика, выставляется флаг
         * IsFromReceive, который поверяется в Send, и используется SocketToSend. Если отправка напрямую из сервера/клиента, то флаг не выставляется и выполняется абстрактный метод DoSend (читай - сервер/клиент
         * сам решает, какой сокет использовать для отправки). Проблема возникает в случае, когда одновременно используется отправка из обработчика и напрямую. Примерный сценарий этого может быть таков:
         * по получении определённого сообщения от какого-либо клиента сервер отправляет широковещательную отправку всем клиентам:
         *
         * Server.OnData += delegate(SocketBase sb, byte[] Data)
         *  {
         *      Server.SendToAll(Data);
         *  };
         *
         * В случае правильной реализации SendToAll вызывает Send, который вызывает DoSend, переопределённый в ServerSocket, а DoSend, в свою очередь, выполняет нужные действия. В текущей реализации SendToAll
         * вызовет Send, внутри Send произойдёт проверка на IsFromReceive, а поскольку вызов Send произошёл из обработчика OnData и флаг IsFromReceive выставлен, то выполнится отправка от сокета SocketToSend,
         * а перегруженный DoSend не исполнится. В итоге сообщение будет отправлено не широковещательно, а на сокет, находящийся в SocketState.Client, т. е. на клиента, отправившего сообщение.
         * P. S. Костыли убраны, код поправлен.
         * */

        protected void ReceiveCallback(IAsyncResult ar)
        {
            SocketState State       = (SocketState)ar.AsyncState;
            Socket      LocalClient = State.Client;
            int         BytesRead   = LocalClient.EndReceive(ar);

            if (BytesRead > 0)
            {
                if (State.IsStart)
                {
                    int Size = BitConverter.ToInt32(State.Buffer, 0);
                    State.Buffer  = new byte[Size];
                    State.IsStart = false;
                    State.Client.BeginReceive(State.Buffer, 0, State.Buffer.Length, SocketFlags.None, ReceiveCallback, State);
                }
                else
                {
                    State.IsStart = true;
                    CallbackedSocket socket = new CallbackedSocket(State.Client);
                    OnData(socket, State.Buffer);
                    State.Buffer = new byte[ReceiveBufferSize];
                    State.Client.BeginReceive(State.Buffer, 0, State.Buffer.Length, SocketFlags.None, ReceiveCallback, State);
                }
            }
        }
예제 #2
0
        private void AcceptCallback(IAsyncResult ar)
        {
            Interlocked.Increment(ref NumberOfClients);
            Socket           Listener    = (Socket)ar.AsyncState;
            Socket           LocalClient = Listener.EndAccept(ar);
            CallbackedSocket Client      = new CallbackedSocket(LocalClient);

            if (OnAccept != null)
            {
                OnAccept(Client);
            }
            lock (Sockets)
            {
                Sockets.Add(LocalClient);
            }
            Listener.BeginAccept(AcceptCallback, Listener);
            SocketState State = new SocketState();

            State.Client = LocalClient;
            try
            {
                State.Client.BeginReceive(State.Buffer, 0, State.Buffer.Length, SocketFlags.None, ReceiveCallback, State);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }