/* * Проблема с костылями состоит в следующем. Отправка сообщения может быть реализована двумя путями: из обработчика 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); } } }
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()); } }