Instant Messaging изнутри

Косякин Антон

Xakep, номер #060, стр. 060-090-1


(deil@real.xakep.ru)

Создание своей IM системы

Я более чем уверен, что ты уже давно пользуешься ICQ или Jabber’ом. А ты когда-нибудь задавался вопросом, как это все устроено, как оно работает? Я сейчас говорю не о взаимодействии юзера с программой - всякие там менюшки и кнопочки. Нет! Я предлагаю заглянуть глубже – разобраться во взаимодействии клиента с сервером. В том, как это все организовано, как устроено и что происходит, когда ты, например, нажимаешь кнопку «log in». Заинтересовался? Ура! :) Тогда читай вдумчиво!

Как ты понимаешь, все это счастье имеет две составляющие: клиент, взаимодействующий с пользователем, и сервер, координирующий работу клиентов. Именно на сервере и лежат основные задачи. Так что для начала остановимся именно на нем. Начнем по порядку.

Протокол

Протокол является основой всего. Именно от того, как ты организуешь передачу данных между компонентами сети, будет зависеть стабильность и продуктивность работы сервера. Поэтому начнем с теории, а именно с небольшого примера: пользователь запустил программу-клиент, залогинился в систему и начал общаться с остальными. Немного поразмыслив, приходим к выводу, что вся работа клиента с сервером основывается на передаче некоторых блоков данных, в которых содержатся конкретные указания к дальнейшим действиям: залогиниться, получить какой-то статус, отправить сообщение и т.д. Для удобства придадим им некую общую структуру. Поэтому для простоты будем передавать в каждом блоке данных (далее будем называть его пакетом) номер отправителя (UIN), номер получателя и некую команду (залогиниться, отправить сообщение, etc). Но как быть, если получатель не конкретный пользователь, а сам сервер? Элементарно! Дадим ему особый номер. Допустим 0 :). Тогда при получении ответа от сервера в поле отправителя будет стоять этот заветный нолик, и мы поймем, от кого пришло сообщение. На С/С++ каждый пакет выглядит примерно так:

struct _packet {

unsigned int from;

unsigned int to;

unsigned char command;

};

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

struct _packet {

unsigned int from;

unsigned int to;

unsigned char command;

char data[1024];

};

Здесь я отвел 1 Кб для данных. Думаю, хватит :). Однако теперь есть два варианта дальнейшего развития событий: можно всегда передавать этот килобайт данных, даже если реально используется пара байт, или передавать только нужное количество данных.

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

Содержание  Вперед на стр. 060-090-2