Быстрая пересылка через Socket
От: impure_soul Россия  
Дата: 10.10.07 07:26
Оценка:
Доброго времени суток.
Вопрос в следующем. Есть сервер, основная задача которого — пересылка данных между двумя клиентами (т.е. он просто принимает с одного сокета и отправляет на другой).
Данные от клиента идут "пакетами" по 65536 байт или меньше (как получится). Если интервал между отправкой двух пакетов от одного клиента больше 100 мс, то всё работает нормально. Если задержку не ставить, то получающий клиент не может десериализовать сообщение т.к. вместо отправленых, например, 33500 байт получает 65536 или вообще что-то другое (например 1024 байта). Не могу понять где и почему портится пакет. После проверки оказалось что при быстрой отправке уже сервер получает пакет непрвильного размера, хотя на клиенте перед выполнением метода Send размер был верным. Возможно уже не вижу очевидных вещей. Подскажите в чём проблема?

Вот частичный код сервера:

public void Start()
{
   SetupServerSocket(); // тут настройка сокета (IP, Port, ...)
   _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}

// класс, используемый для возврата через IAsyncResult
private class ConnectionInfo
        {
            private readonly object on_lock = new object();
            public Int32 ClientID;
            private Socket _Socket;
            public Socket Socket
            {
                get { lock (on_lock) {return _Socket; } }
                set { lock (on_lock) { _Socket = value; } }
            }
            private byte[] _Buffer;
            public byte[] Buffer
            {
                get { lock (on_lock) { return _Buffer; } }
                set { lock (on_lock) { _Buffer = value; } }
            }
        }

private void AcceptCallback(IAsyncResult result)
        {
            
            ConnectionInfo connection = new ConnectionInfo();
            try
            {
                // Завершение операции Accept
                Socket s = (Socket)result.AsyncState;
                connection.Socket = s.EndAccept(result);
                connection.Buffer = new byte[65536];
                lock (_connections) _connections.Add(connection);
                connection.Socket.BeginReceive(connection.Buffer, 0, connection.Buffer.Length,
                            SocketFlags.None, new AsyncCallback(ReceiveCallback), connection);
              
                _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), result.AsyncState);
            }
            catch (SocketException exc)
            {
                CloseConnection(false, connection);
                Log("Описание ошибки: "+exc.SocketErrorCode);
            }
        }

        private void ReceiveCallback(IAsyncResult result)
        {
            ConnectionInfo connection = (ConnectionInfo)result.AsyncState;
            try
            {
                int bytesRead = connection.Socket.EndReceive(result); // << при "быстрой отправке" 
                                                                      //тут  bytesRead не совпадает
                                                                      //отправленным числом байт
                byte[] _tmp_buf = connection.Buffer;
                connection.Buffer = new byte[65536];

                connection.Socket.BeginReceive(connection.Buffer, 0, connection.Buffer.Length,
                              SocketFlags.None,new AsyncCallback(ReceiveCallback), connection);

                if (0 != bytesRead)
                {
                    MyMessageType MyMessage = null;
                    BinaryFormatter serializer = new BinaryFormatter();
                    #region Serialization
                    try
                    {
                        MemoryStream stream = new MemoryStream(_tmp_buf);
                            MyMessage = (MyMessageType)serializer.Deserialize(stream);
                            stream.Close();
                    }
                    catch
                    {
                        
                        return;
                    }
                    #endregion
                    #region Send
                    foreach (ConnectionInfo conn in _connections) // Перебераем всех  
                                                                  //подключённых клиентов
                    {
                    if (conn.ClientID == MyMessage.UsersTo.ID)
                    {
                        try
                        {
                         conn.Socket.Send(_tmp_buf, bytesRead, SocketFlags.None);
                         break;
                         }
                         catch { isOnline = false; }
                    }
                
                }
            }
            catch (SocketException exc)
            {
                CloseConnection(true,connection);
                Log("Описание ошибки: " + exc.SocketErrorCode);
            } 
        }



Частичный код клиента:

        void OnBeginReceive(IAsyncResult result)
        {
            ClientConnectionInfo conn = (ClientConnectionInfo)result.AsyncState;
            try
            {
                int bytesRead = client.EndReceive(result);
                byte[] _tmp_buf = new byte[bytesRead];
                Array.Copy(conn.Buffer, _tmp_buf, bytesRead);
                conn.Buffer = new byte[MAX_PACKET_LEN];
                client.BeginReceive(conn.Buffer, 0, MAX_PACKET_LEN, SocketFlags.None, 
                                            new AsyncCallback(OnBeginReceive), conn);

                if (0 != bytesRead)
                {
                    MyMessageType MyMessage = null;
                    BinaryFormatter serializer = new BinaryFormatter();
                    try
                    {
                        MemoryStream stream = new MemoryStream(_tmp_buf);
                            MyMessage = (MyMessageType)serializer.Deserialize(stream);
                            stream.Close();
                    }
                    catch
                    {
                        // Вот сюда вылетает получатель, при быстрой отправке.
                        MessageBox.Show("Не удалось десериализовать пришедшее сообщение.");
                        return;
                    }

                    GenerateMessageEvent(SRMessageDesserializeObj);
                 }
            }
            catch (Exception ex){ MessageBox.Show("Критическая ошибка "+'\n'+ex.Message);  }
        }

//Метод отправки данных с клиента

        public void DoWork(string path, int id, string name)
        {
            int MAX_DATA_LEN = 30000;
            string _path = path;
            FileStream stream = new FileStream(_path, System.IO.FileMode.Open,
                        System.IO.FileAccess.ReadWrite);
            BinaryReader r = new BinaryReader(stream);
            int segmentCount = (int)stream.Length / MAX_DATA_LEN + 1;
            int sourceIndex = 0;

            for (int i = 0; i < segmentCount; i++)
            {
                MyMessageType _message = new MyMessageType();
              
                int bytesToCopy = (int)stream.Length - sourceIndex;
                if (bytesToCopy > MAX_DATA_LEN) bytesToCopy = MAX_DATA_LEN;

                _message.DataContainer = r.ReadBytes(bytesToCopy);
                sourceIndex += bytesToCopy;

                MemoryStream mstream = new MemoryStream();
                BinaryFormatter serializer = new BinaryFormatter();
                serializer.Serialize(mstream, _message);
                byte[] buf = mstream.ToArray();
                try
                {
                    client.Send(buf, 0, buf.Length, SocketFlags.None);
                }
                catch { }
                Thread.Sleep(100); // << Вот та самая задержка. Если её убрать,
                                  // то возникает описанная проблема
            }
            stream.Close();
        }


Буду очень признтелен за помошь. Задачу очень нузно решить
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.