Как написать чат или практика работы с winsock...
С самого начала хочу сказать, что я не в коем случае не хочу показаться каким-нибудь "отцом" в плане сетевого программирования. Этот чат я написал от нечего делать для себя, а точнее для своей группы :).
Вообще я написал несколько чатов, но расскажу только о первом и последнем, иначе это будет вторая "война и мир" :), хотя я расскажу про способы решения определенных проблем, которые применялись в ранних версиях чата. Вся "серия" этих чатов называется LightChat...
Самый первый мне предложил написать мой брат чисто в целях саморазвития :), в тот момент мы имели только поверхностные знания, касающиеся написания программ для работы сетью. Я делал сервер, а он делал клиента. Мы сразу решили, что сервер не будет встраиваться в программу клиента, хотя бы потому что мы жили далеко друг от друга и очень не хотелось связываться "по-диалапу" для обновления исходного текста и компиляции... Мы соединялись только для проверки их работоспособности. Возникшие проблемы мы решали по телефону, причем иногда это затягивалось на долго :))
Для начинающих, которые, как и мы тогда, ничего не представляют о том как написать сетевую программу, советую воспользоваться C++Bulder'ом - там имеются RAD-компоненты (ServerSocket и ClientSocket) для работы с сокетами (что вам собственно и нужно). Сразу скажу что эти компоненты мне не нравятся, потому что у них обнаружилось пара серьезных глюков, но это сейчас, а тогда - когда появилась первая строчка в окне клиента, меня просто распирало от радости... Эта первая строчка, которая, как я помню состояла только из матов :), означала, что долгие споры и обсуждения по телефону не прошли даром... А тот баг с RAD компонентами заключается в том, что при обработки события ошибки клиента (ClientError, на сколько я помню) сервер начинал выводить сообщение об ошибки на клиенте и выводил его до тех пор, пока не закроешь сервер :) Ну,естественно, клиенты в это время безуспешно пытались общаться с сервером, но ему было уже все равно...
Так вот при написании сервера сразу же стоит решить о том, как сервер будет управлять клиентами, ведь клиент должен иметь ник, IP адрес (хотя для сервера знать IP не обязательно), статус (доступен или нет) и все то, что вы захотите, чтобы сервер знал о клиенте.
Сразу же после этого нужно решить формат пакетов. У нас пакет состоял из Имени отправителя, Имени принимающего, Типа пакета и, собственно, сообщения. Эти "поля" разделялись" определенным символом, который не должен был встречаться при печати. Таким образом - пакет мог иметь переменную длину, что нам казалось большим плюсом. На самом же деле, это оказалось двумя минусами :). Первый минус заключался в том, что поля пакетов (т.е. ник, тип и т.д.) должны были извлекаться вручную - т.е. у вас была строка, которую вы приняли от клиента, из этой строки вам необходимо было извлечь сначала ник отправителя, потом, по достижении того самого спец. символа, извлекался ник получателя, тип, а остальное считалось сообщением. К стати, второй минус тесно связан с первым - у протокола TCP есть свойство соединять слишком маленькие пакеты в один, по идеи это повышает эффективность, но, в таком случае, второй пакет на сервере не распознавался - он был частью сообщения первого - Мы очень часто наблюдали как в выведенном сообщении в конце был полностью следующий пакет, вместе с типом, никами и сообщением :). Чтобы избежать таких неприятностей, ведь не все пакеты содержали сообщения - некоторые были управляющими, мы ввели задержку после отправки пакета,по-моему ок 20мс.
К стати, тип пакета, желательно, должен быть числом, а то я до сих пор улыбаюсь, когда смотрю на двухбайтовую строку Типа, а ведь еще хотели добиться от чата хорошей скорости :)) Единственная забавная возможность, которая была на сервере - это то, что можно было отправлять пакеты от имени любого пользователя, причем не только сообщения, но и управляющие пакеты тоже. Представьте себе, что вы наезжаете на пользователя от имени другого пользователя, а потом его кикаете, от имени этого же пользователя - вот и разберись потом что произошло :))
Ну наверно самое смешное, над чем я сейчас смеюсь больше, чем над самим чатом, было то, что мы хотели его продать :)))
Следующие версии чата я писал в гордом одиночестве, кто знает - может оно и к лучшему.
Следующие версии стали более принципиальными - в них применяются шифрование пакетов, недопущение отладки программ, недопущение переполнения буфера, какая-никакая, но все же защита от взлома сервера, да и клиента тоже :) И самое главное отличие в том, что вся сетевая часть сервера и клиента полностью написана руками. Поэтому чат стал очень стабильным и чтобы вызвать его неправильную работу нужно очень потрудится.
За каждого клиента отвечает отдельный, независимый поток, что также обеспечивает быстродействие.
Все пакеты имеют фиксированную длину и тип теперь - однобайтовое число (char)- это позволило убрать задержки и необходимость "доставать" данные из принятой строки, а также не тратить время на сравнение строк, чтобы узнать тип пакета... Кроме этого при формировании пакета высчитывается его контрольная сумма, при приеме она позволяет определить целостность пакета, то, что теперь пакеты имеют заголовки, позволяет определить подлинность пакета. Если пакет не прошел тест на подлинность или целостность - он игнорируется...
Появилась возможности регистрации ников - данные о регистрации хранятся на сервере в виде двух 4ех байтовых контрольных сумм, при входе пользователя проверяется его ник и если находится такая же контрольная сумма, то его просят ввести пароль, если он вводит не правильный пароль или не вводит его вообще, после 60ти секунд, его кикают :)
Также появилась поддержка банов - при входе проверяется IP адрес пользователя, и если он забанен - соединение закрывается...
Кроме этого имеется возможность оставить сообщение для отсутствующего пользователя. Сообщение должно быть не длиннее размера 1024 байт (это размер данных по умолчанию).
В добавок ко всему - на сервере постоянно имеся поток, который отслеживает возможные атаки. Атаками считаются все соединения, которые не сменяют ник с ника "по-умолчанию" - "default". Если этот поток находит такое подключение, то он его закрывает.
Ну вот, в принципе и все, что можно было рассказать "в двух словах". Если вас это заинтересовало, то можете скачать исходный текст и исполняемые файлы чата LightChat v4.0.1.1 [RAR, 430kb], которые прилагаются к статье. Здесь содержатся мои идеи, которые реализованы при написании чата LightChat. Надеюсь,что после прочтения этой статьи и просмотра исходного кода, вы узнаете что-нибудь новое для себя.
Если какой-то код западет квам в душу и вы решите использовать его в ваших программах, то вспомните, что я совершенно бесплатно предоставил вам исходный код, который является реализацией лично моих идей, и, поэтому, не забудьте упоминать и сослаться на меня как автора.
Ну и если у вас есть какие-то предложения, а может и замечания, то пишите мне на мыло...
Об остальных аспектах написано в файлах readme.txt, прилагающихся к чату.
Скачать исходник [RAR, 430kb]
Оставить комментарий
Комментарии
у мну где то валялось нечто похоже на перле и сях ...
некий самописный icq chat (:
поделки и коленописки не рулят (: это я усвоил из нашего с тобой эксперимента ... ((:
теперь если что то делается на продакшн, клепается не за один день/два дня ... (:
удачи!
Придётся осваивать С++ или Delphi.net
Но тема сетевых технологий мне видиться даже во сне!=))