Помощь с Silverlight сокетами и доставкой сообщений - PullRequest
2 голосов
/ 23 апреля 2010

Прошло 4 месяца с тех пор, как я прекратил разработку своей многопользовательской шахматной игры Silverlight.

альтернативный текст http://img408.imageshack.us/img408/8355/chess.gif

Проблема была в ошибке, которую я не мог воспроизвести. Мне очень грустно, потому что это был тест, и многие многопользовательские игры Silverlight придут, если это будет успешным. В Интернете нет примеров того, как делать подобные вещи, не говоря уже о том, что лишь немногие используют Sockets в своей жизни.

Поскольку на этой неделе у меня появилось немного свободного времени, мне удалось обнаружить проблему, и теперь я могу воспроизвести ошибку.

Похоже, что если я отправлю 10 сообщений от клиента, одно за другим, без задержки между ними, как в примере ниже

// when I press Enter, the client will 10 messages with no delay between them
private void textBox_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter && textBox.Text.Length > 0)
    {
        for (int i = 0; i < 10; i++)
        {
            MessageBuilder mb = new MessageBuilder();
            mb.Writer.Write((byte)GameCommands.NewChatMessageInTable);
            mb.Writer.Write(string.Format("{0}{2}: {1}", ClientVars.PlayerNickname, textBox.Text, i));
            SendChatMessageEvent(mb.GetMessage());

            //System.Threading.Thread.Sleep(100);
        }

        textBox.Text = string.Empty;
    }
}

    // the method used by client to send a message to server
    public void SendData(Message message)
    {
        if (socket.Connected)
        {
            SocketAsyncEventArgs myMsg = new SocketAsyncEventArgs();
            myMsg.RemoteEndPoint = socket.RemoteEndPoint;
            byte[] buffer = message.Buffer;
            myMsg.SetBuffer(buffer, 0, buffer.Length);

            socket.SendAsync(myMsg);
        }
        else
        {
            string err = "Server does not respond. You are disconnected.";
            socket.Close();
            uiContext.Post(this.uiClient.ProcessOnErrorData, err);
        }
    }

    // the method used by server to receive data from client
    private void OnDataReceived(IAsyncResult async)
    {
        ClientSocketPacket client = async.AsyncState as ClientSocketPacket;
        int count = 0;
        try
        {
            if (client.Socket.Connected)
                count = client.Socket.EndReceive(async);
            // THE PROBLEM IS HERE
            // IF SERVER WAS RECEIVE ALL MESSAGES SEPARATELY, ONE BY ONE, THE COUNT
            // WAS ALWAYS 15, BUT BECAUSE THE SERVER RECEIVE 3 MESSAGES IN 1, THE COUNT
            // IS SOMETIME 45
        }
        catch 
        {
            HandleException(client);
        }

        client.MessageStream.Write(client.Buffer, 0, count);

        Message message;

        while (client.MessageStream.Read(out message))
        {
            message.Tag = client;
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.processingThreadEvent.ServerGotData), message);
            totalReceivedBytes += message.Buffer.Length;
        }

        try
        {
            if (client.Socket.Connected)
                client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, 0, new AsyncCallback(OnDataReceived), client);
        }
        catch 
        {
            HandleException(client);
        }
    }

отправлено только 3 больших сообщения, и каждое большое сообщение содержит 3 или 4 маленьких сообщения. Это не то поведение, которое я хочу.

Если я поставлю задержку в 100 миллисекунд между доставкой сообщений, все будет нормально, но в реальном сценарии пользователи могут отправлять сообщения на сервер даже между 1 миллисекундами.

  1. Существуют ли какие-либо настройки, чтобы клиент мог отправлять только одно сообщение за раз, или
  2. Даже если я получаю 3 сообщения в 1, они все время являются полными сообщениями (я не хочу получать 2,5 сообщения в одном большом сообщении)? потому что, если они есть, я могу прочитать их и обработать эту новую ситуацию

1 Ответ

2 голосов
/ 04 мая 2010

Вы пропустили основную функцию TCP - это не протокол на основе сообщений.Все данные отправляются по одному «каналу».Когда вы кладете 5 стаканов воды в трубу, вы получаете ведро воды на другом конце, а не пять стаканов.Если вы достаточно быстры, чтобы вынуть воду из ведра, вы можете получить либо 5 чашек, либо 10 полчашек, либо одно ведро.То же самое с TCP.Если вам нужны сообщения, вы должны поместить несколько маркеров в начало и конец каждого сообщения и проанализировать поток на принимающей стороне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...