Мультиклиент, асинхронные сокеты в c#, лучших практиках? [закрытый]

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

17
задан Jason Miesionczek 13 June 2013 в 14:03
поделиться

4 ответа

При выполнении программирования уровня сокета то независимо от того, сколько портов Вы открываетесь для каждого типа сообщения, у Вас все еще должен быть какой-то заголовок. Даже если это - просто длина остальной части сообщения. Сказав, что легко добавить простой заголовок и структуру хвоста к сообщению. Я думал бы, что легче только должным быть иметь дело с одним портом на стороне клиента.

я полагаю, что современный MMORPGs (и возможно даже старые) имел два уровня серверов. Серверы входа в систему, которые проверяют Вас как платящий клиент. После того, как проверенный они выдают Вас к игровому серверу, которые содержат всю игровую информацию о мире. Несмотря на это, это все еще только требует, чтобы у клиента был один открытый сокет, но не запрещает наличие больше.

Дополнительно большинство MMORPGS также шифрует все свои данные. Если Вы запишете это как осуществление для забавы, то это не будет иметь значения так.

Для разработки/записи протоколов в целом вот вещи, о которых я волнуюсь:

Endianess

Является клиентом и сервером, всегда гарантировал, что имел тот же порядок байтов. Если не я должен обработать это в своем коде сериализации. Существует несколько способов обработать порядок байтов.

  1. Игнорируют его - Очевидно, плохой выбор
  2. Указывает порядок байтов протокола. Это - то, что более старые протоколы сделали следовательно порядок сети термина, который всегда был обратным порядком байтов. Это на самом деле не имеет значения, какой порядок байтов Вы указываете просто, что указываете один или другой. Некоторые твердые старые сетевые программисты встанут в руках, если Вы не будете использовать большой порядок байтов, но если Ваши серверы и большинство клиентов являются прямым порядком байтов, Вы действительно не покупаете себя ничто кроме дополнительной работы путем создания обратного порядка байтов протокола.
  3. Mark Endianess в каждом заголовке - можно добавить cookie, который скажет Вам порядок байтов клиента/сервера и позволит каждому сообщению быть преобразованным соответственно по мере необходимости. Дополнительная работа!
  4. Делают Вашего агностика протокола - Если Вы отправляете все, поскольку ASCII представляет в виде строки, затем порядок байтов не важен, но также и намного более неэффективен.

Из 4 я обычно выбирал бы 2 и указывал бы порядок байтов, чтобы быть тем из большинства клиентов, которые теперь дни будут прямым порядком байтов.

Вперед и Назад Совместимость

Делает протокол, должны быть форварды и назад совместимый. Ответ должен почти всегда быть да. В этом случае это определит, как я разрабатываю по всему протоколу с точки зрения управления версиями, и как каждое отдельное сообщение создается для обработки незначительных изменений, которые действительно не должны быть частью управления версиями. Можно плыть на плоскодонке на этом и использовать XML, но Вы теряете большую эффективность.

Для полного управления версиями я обычно разрабатываю что-то простое. Клиент отправляет сообщение управления версиями, указывающее, что оно говорит версию X.Y, пока сервер может поддерживать ту версию, оно передает сообщение обратно, подтверждая версию клиента, и все продолжается вперед. Иначе это обезглавливает клиент и завершает соединение.

Для каждого сообщения у Вас есть что-то как следующее:

+-------------------------+-------------------+-----------------+------------------------+
| Length of Msg (4 bytes) | MsgType (2 bytes) | Flags (4 bytes) | Msg (length - 6 bytes) |
+-------------------------+-------------------+-----------------+------------------------+

длина, очевидно, говорит Вам, какой длины сообщение, не включая саму длину. MsgType является типом сообщения. Только два байта для этого, с тех пор 65356 много типов сообщений для приложений. Флаги там для сообщения то, что сериализируется в сообщении. Это поле, объединенное с длиной, - то, что дает Вам Ваших форвардов и назад совместимость.

const uint32_t FLAG_0  = (1 << 0);
const uint32_t FLAG_1  = (1 << 1);
const uint32_t FLAG_2  = (1 << 2);
...
const uint32_t RESERVED_32 = (1 << 31);

Затем Ваш код десериализации может сделать что-то как следующее:

uint32 length = MessageBuffer.ReadUint32();
uint32 start = MessageBuffer.CurrentOffset();
uint16 msgType = MessageBuffer.ReadUint16();
uint32 flags = MessageBuffer.ReadUint32();

if (flags & FLAG_0)
{
    // Read out whatever FLAG_0 represents.
    // Single or multiple fields
}
// ...
// read out the other flags
// ...

MessageBuffer.AdvanceToOffset(start + length);

Это позволяет, Вы к [1 148] добавляете новые поля в конец из сообщений, не имея необходимость к пересмотру полный протокол. Это также гарантирует, что старые серверы и клиенты проигнорируют флаги, о которых они не знают. Если они должны использовать новые флаги и поля, то Вы просто изменяете полную версию протокола.

Использование Основа или Не

существует различные сетевые платформы, которых я рассмотрел бы использование для бизнес-приложения. Если у меня не было определенной потребности поцарапать, я пойду со стандартной платформой. В Вашем случае Вы хотите изучить программирование уровня сокета, таким образом, это - вопрос, уже отвеченный для Вас.

, Если Вы действительно используете платформу, удостоверяются, что она обращается к двум проблемам выше или по крайней мере не стоит на пути, если необходимо настроить ее в тех областях.

я имеющий дело с третьим лицом

Во многих случаях, можно иметь дело со сторонним сервером/клиентом, которым необходимо связаться с. Это подразумевает несколько сценариев:

  • Им уже определили протокол - Просто используют их протокол.
  • у Вас уже есть определенный протокол (и они готовы использовать его) - снова простое использование определенный протокол
  • , Они используют стандартную Платформу (базирующийся WSDL, и т.д.) - Использование платформа.
  • Никакой стороне не определили протокол - Попытка к determing лучшее решение на основе всех факторов под рукой (все те, я упомянул здесь), а также их уровень competencey (по крайней мере, насколько можно сказать). Независимо удостоверьтесь, что обе стороны договариваются и понимают протокол. На основе опыта это может быть болезненно или приятно. Это зависит от того, с кем Вы работаете.

В любом случае Вы не будете работать с третьим лицом, таким образом, это будет действительно просто добавлено для полноты.

я чувствую, как будто я мог записать намного больше об этом, но это уже довольно длинно. Я надеюсь, что это помогает и если у Вас есть какие-либо конкретные вопросы, просто спрашивают относительно Stackoverflow.

редактирование для ответа вопрос на knoopx:

30
ответ дан 30 November 2019 в 12:14
поделиться

Я думаю, что необходимо проверить перед обходом и перед выполнением. Сначала получите дизайн платформы и права соединений, затем волнуйтесь о масштабируемости. Если Ваша цель состоит в том, чтобы изучить C# и программирование tcp/ip, то не делайте это тяжелее на себе.

Продолжают Ваши начальные мысли и разделяют потоки данных.

весело проводят время и удача

2
ответ дан 30 November 2019 в 12:14
поделиться

Я отговорил бы от многочисленных связей для другой информации. Я разработал бы некоторый протокол, который содержит заголовок с информацией, которая будет обработана. Используйте как можно меньше ресурсы. Кроме того, Вы не можете хотеть отправлять обновления за различными положениями и статистикой от клиента к серверу. Иначе можно закончить в ситуации, где пользователь может изменить их данные, передаваемые обратно серверу.

Говорят, что пользователь фальсифицирует местоположение монстра для заканчивания чего-то. Я только обновил бы радиус-вектор пользователя и действия. Позвольте остальной части информации быть обработанной и проверенной сервером.

1
ответ дан 30 November 2019 в 12:14
поделиться

Да я думаю, что Вы правы относительно единственного соединения, и конечно клиент не отправил бы фактических данных на сервер, больше как просто простые команды любят, 'продвигаются', 'поверните налево', и т.д. и сервер переместил бы символ в карту и передал бы новые координаты обратно клиенту.

0
ответ дан 30 November 2019 в 12:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: