Проектирование и разработка программы ЧАТ для локальной сети

АВТОНОМНАЯ НЕКОМЕРЧЕСКАЯОБРАЗОВАТЕЛЬНАЯ ОРГАНИЗАЦИЯВЫСШЕГОПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ ВОРОНЕЖСКИЙ ЭКОНОМИКО-ПРАВОВОЙИНСТИТУТ
ФИЛИАЛ г.СТАРЫЙОСКОЛ БЕЛГОРОДСКОЙ ОБЛАСТИ
ЭКОНОМИЧЧЕСКИЙФАКУЛЬТЕТ
КАФЕДРА «ГУМАНИТАРНЫХИ ЕСТЕСТВЕННОНАУЧНЫХ ДИСЦИПЛИН»
Курсовая работа
По дисциплине: Проектированиеинформационных систем
На тему
Проектирование иразработка программы ЧАТ для локальной сети
Выполнил
Кирилов О.И.

Содержание
Введение
Глава I. Историявозникновения чата
Виды чатов
Глава II. Созданиемногопользовательского чата
Листинг программы
Заключение
Приложение

ВведениеРаботая в сети Internet, мы очень частовстречаемся с разного рода многопользовательскими программами. Ими могут бытьпочтовые клиенты, чаты, форумы, FTP клиенты и т.п. Все эти приложенияиспользуют для своей работы разного рода протокола: FTP, POP, SMTP, HTTP, ит.д. Но базовым для них является единый протокол — TCP/IP. Типичное же приложениеTCP/IP построено на клиент-серверной архитектуре. Примером приложенияпостроенного на данной архитектуре, является чат реального времени. В даннойкурсовой работе я буду создавать чат средствами Borland Delphi. Для этой целимне необходимы компоненты TClientSocket и TServerSocket Выбранные компонентыпри работе с протоколом TCP/IP используют интерфейс сокетов. Но прежде чемперейти к разработке чата, разберем, что же такое сокеты.
Сокеты – это интерфейсприкладного программирования для сетевых приложений TCP/IP.Интерфейс сокетов был создан в восьмидесятых годах для операционной системы UNIX.Позднее интерфейс сокетов был перенесен в MicrosoftWindows. Сокеты до сих пориспользуются в приложениях для сетей TCP/IP.В переводе с английского «sockets»– гнезда, т.е. сетевые приложения используют сокеты, как виртуальные разъемыдля обмена данными между собой. Сокеты бывают трех видов: клиентские, слушающиеи серверные. Клиентские сокеты устанавливают связь с сервером и обмениваются сним данными. Клиентский сокет включен в компонент TClientSocket.Слушающий сокет принимает запрос на соединение от клиентского сокета, исоединяет сервер с клиентом. Слушающий сокет содержится в компоненте TServerSocket.Серверный сокет обменивается данными с клиентом по уже установленному(слушающим сокетом) соединению. Для того чтобы клиент мог установить соединениес сервером, ему необходимо указать его адрес (IP)и номер порта, через который будет происходить обмен данными.

Глава I. Историявозникновения чата
Вопросы общения интересовалилюдей всегда. Для того, чтобы можно было обмениваться информацией не только приличной встрече, но и на огромных расстояниях, люди изобретали всё новые и новыетехнические средства, организовывали почтовые системы, протягивали кабели черезконтиненты и океаны, запускали спутники связи. С развитием информационныхтехнологий стали возможным еще более глобальные коммуникации. Историческим«докомпьютерным» предшественником чатов, несомненно, был телефон. Ни почта, нителеграф не позволяли общаться в реальном времени и не были доступны в домашнейобстановке. Изобретение и распространение телефона по планете вызвало настоящуюреволюцию в средствах и способах общения. Возможность поговорить с собеседникомна другой стороне Земли казалась настоящим чудом.
Во второй половине XXвека начали бурно развиваться компьютеры. Однако долгое время они были большимии слишком дорогими, что препятствовало тому, чтобы расходовать драгоценноемашинное время на забавы с обменом сообщениями вместо расчетов атомных бомб. Ктому же, до конца 60-х годов они не были связаны друг с другом. ПредокИнтернета, сеть ARPANET, в 1969 году насчитывала только четыре связанных друг сдругом научных компьютера. Чуть позже, в 1971 году, была придумана электроннаяпочта, которая стала необычайно популярна ввиду своего удобства. Постепеннопоявились новые службы сообщений, такие, как списки почтовой рассылки,новостные группы и доски объявлений. Однако в то время сеть ARPANET ещё немогла легко взаимодействовать с другими сетями, построенными на другихтехнических стандартах, что затрудняло её распространение. Но тем не менее, этапроблема вскоре была решена после перехода сетей на протокол обмена даннымиTCP/IP, который успешно применяется до сих пор. Именно в 1983 году термин«Интернет» закрепился за сетью ARPANET.
Программы для обменатекстовыми строками, несмотря на простоту самой идеи, появились не сразу.Примерно в 1974 году для мэйнфрейма PLATO был разработана программа Talkomatic,потенциально позволявшая общаться между тысячей терминалов системы. В 1980-xпоявилась система Freelancing’ Round table. Однако по-настоящему популярнымстал разработанный в 1988 году протокол, названный Internet Relay Chat (IRC),что примерно можно перевести как ретранслируемый интернет-разговор. Где-то в этоже время появилось и распространилось само понятие «чат». Общение в IRC быстростало популярным из-за простоты процесса и дружественности среды. В 1991 годуво время операции «Буря в пустыне» была организована IRC-трансляция новостей —сообщения со всего мира собирались в одном месте и в режиме реального временипередавались в IRC. Есть сведения, что подобным образом IRC использовался и вовремя путча в СССР, когда пользователи из Москвы моментально сообщали всемумиру о происходящем на улицах. Для клиентов IRC, написано множество ботов,например, Eggdrop, автоматизирующие многие рутинные операции. Самым известнымиз клиентов IRC стал mIRC; благодаря простой и эффективной системе команд длянего было написано множество скриптов, которые также позволяют выполнятьширокий спектр действий. Боты и mIRC-боты используются для различных игр вканалах — «Мафия», «Викторина», и других. Разработчики IRC настолько хорошопродумали его архитектуру, что её с тех пор практически не требовалосьизменять. Конечно, у него есть недостатки: короткие сообщения, проблема скодировками, невозможность посмотреть историю сообщений при подключении. Однакоон был и остаётся популярным средством для чата, хотя и в значительной мерепотеснен со своих позиций. В частности, в 1998 году был придуман похожегоназначения протокол Jabber — даже его название (англ. jabber болтовня, трёп;тарабарщина) отсылало к слову chat. Jabber содержал в себе многие техническиеновшества и постепенно получил широкое распространение, а также стал основой многихсервисов. Были и другие протоколы, менее известные, например, SIP.
Виды чатов
Существует несколькоразновидностей программной реализации чатов:
HTTP или веб-чаты.Такой чат выглядит как обычная веб-страница, где можно прочесть последниенесколько десятков фраз, написанные участниками чата и модераторами. Чаты,использующие технологию Adobe Flash. Вместо периодической перезагрузкистраницы, между клиентом и сервером открывается сокет, что позволяетмоментально отправлять или получать сообщения, расходуя меньше трафика.
IRC, специализированныйпротокол для чатов.
Программы-чаты дляобщения в локальных сетях (например, Vypress Chat, Intranet Chat). Часто естьвозможность передачи файлов.
Чаты, реализованныеповерх сторонних протоколов (например чат, использующий ICQ).
По применению чатыделятся на:
all2all — групповаякоммуникация (например, IRC, Jabber, Yahoo! Chat, AVACS Live Chat);
p2p — персональныекоммуникации (например, ICQ, Jabber, Skype, Yahoo! Messenger,AOL InstantMessenger, Hamachi)— личное общение.

Глава II.Создание многопользовательского чата (Multy-useron-line)
Multy-user- один сервери множество клиентов. Сервер при этом выполняет обработку входящих сообщений,пересылает их по нужным каналам, регистрирует пользователей и показывает всем,сколько пользователей общаются в текущий момент.
Начнем разработкуприложения чата с новой формы. Вот, что должно быть в форме:
PortEdit (Edit)
HostEdit (Edit)
NikEdit (Edit)
TextEdit (Edit)
ChatMemo (Memo)
ClientBtn (Button)
ServerBtn (Button)
SendBtn (Button)
ServerSocket (ServerSocket)
ClientSocket (ClientSocket)
UserListView (ListView)
ImageList (ImageList)
ServerTimer (Timer)
КомпонентыизстандартногопакетаDelphi ServerSocket иClientSocket не всегдамогутбытьотображенывпалитреInternet, и ихнужнозагрузитьследующимобразом:выбратьменю:Component — Install Packages… — Add., далеенужноуказатьфайл…\bin\dclsockets70.bpl.
Как правило, разработкалюбой программы начинается с определения задач, которые она должна выполнять, иопределения уже на этом этапе нужных компонентов. Программа представляет собойчат для нескольких пользователей, каждый из которых может быть как сервером,так и клиентом, значит, кидаем в форму компоненты ServerSocket и ClientSocket. Важным параметром длявсех является порт. Только при одинаковом значении свойства Port, связь между ними установится.Кинем в форму компонент Edit,чтобы оперативно изменять порт, назовем его PortEdit. Для соединения с сервером необходимоуказывать IP сервера или его имя, поэтому кинем еще один Edit, назовем его HostEdit. Так же нам понадобятся ещедва Edit’а дляуказания ника и ввода текста сообщения, назовем их NikEdit и TextEdit, соответственно. Текстпринимаемых и отправляемых сообщений будет отображаться в Memo, кинем его в форму и назовем ChatMemo. Установим сразувертикальную полосу прокрутки: ScrollBars= ssVertical, и свойство ReadOnly= True. Добавимклавиши управления Button:ServerBtn – длясоздания/закрытия сервера, ClientBtn– для подключения/отключения клиента к серверу, SendBtn — для отправки сообщений. Изменим Caption этих клавиш на “Создать сервер”, “Подключиться” и “Отправить”, соответственно. UserListViewпредназначен для вывода списка пользователей, который будет динамическиобновляться при подключении или отключении пользователей. Сам компонент ListViewнастраивается как табличный отчет: свойство ViewStyle = vsReport (стильтаблицы), свойство ShowColumnHeaders = False (не показывать имена столбцов),свойство ReadOnly = True (только отображение), свойство SmallImages = ImageList(массив с иконками). Двойным кликом на компоненте ListView выводится редактор EditingUserListView.Columns. Добавляется один столбец (порядковый номер -0). В ImageListчерез Add закидываются иконки, в нашем случае две, с изображением силуэта пользователя:в белом – пометка сервера, в красном – пометка клиента.
Теперь разберем принципработы сервера. Традиционно в ServerSocket для приема клиентских пакетовиспользуется OnClientRead, но данный способ не очень удобен, ведь дляидентификации пакета (кто прислал) потребуется повозиться со структурой“прием\ответ” и решить каким образом будет происходить синхронизация. Гораздопроще и эффективнее использовать цикл по числу пользователей, в котором ведется“прослушивание” всех каналов и обработка пакета, если он пришел на конкретныйканал, закрепленный за конкретным пользователем. Процедура “прослушивания”каналов выполняется в теле таймера, интервал (Interval) работы которого можноизменять по необходимости (для чата нормально 500 мс, для игр нужно существенноменьше). Вот так выглядит общая структура процедуры опроса:
procedure TForm1.Timer1Timer(Sender: TObject);
begin //условие на наличие установленных каналов
if ServerSocket.Socket.ActiveConnections0then begin // цикл посуществующимканалам
for i:=1 to ServerSocket.Socket.ActiveConnections dobegin // сохраним пакет(еслиничегонеприслали,попакетпустой)
text:=ServerSocket.Socket.Connections.ReceiveText();// условие, что пакет не пуст iftext” thenbegin {тутобработка строки, выделение составляющих кода команд (com)и пр.} // определение команд casecom ofкод:begin {процедура}end; код: begin{процедура}end; ……………………………………. end;end; end;end; // разрешение на выполнениепроцедур обновления ifUpdDo=Truethen begin{процедуры}// блокируем разрешение UpdDo:=False;end; end;
Если заметили, что циклначинается с единицы, а в инициализации канала странное выражение (вместологичного начала с нуля и инициализации), то такое решение существенным образомоблегчает организацию ряда процедур. Например, в списке пользователей, серверчислится под номером “0”, а клиенты — начиная с “1”. Так же удобно совмещатьколичество каналов (ServerSocket.Socket.ActiveConnections) с процедурамиопределения активности пользователей. Последнее условие в теле таймеранеобходимо для задержки выполнения некоторых процедур обновления. Эти процедурыдолжны выполняться в самом конце “прослушивания” открытых каналов, и не всегда(если будет команда). Данный алгоритм применим практически к любого родасоединениям Клиент-сервер, в том числе и для игр.
Перейдемнепосредственно к приложению чата и его процедурам. Проверок на корректностьввода значений в поля не будет. Создадим новый тип, для использования массиваобъектов, так гораздо удобнее:
TypeTUserList = object Status: Byte; // 1 — сервер, 2 — клиент Rec: Boolean; //отметка записи пользователя в список Name: String; // имя (ник) Image: Byte; //индекс иконки end;
Вот переменные, которыепонадобятся в программе:
var Form1: TForm1; i, j, com, ContList: Byte; len,pos, x: Word; text, StrUserList: String; UpdDo: Boolean; Buf: array[0..3] ofByte; UserMas: array[0..255] of TUserList; //массивобъектовUItems: TListItem;
ОпишемпроцедуруOnCreate формы:
procedure TForm1.FormCreate(Sender: TObject); begin //заголовокформыCaption:=’Многопользовательскийчат’;Application.Title:=Caption; // предложенноезначенияпортаPortEdit.Text:=’Портсервера’;// адресприпроверкепрограммынаодномПК(«самнасебя»)HostEdit.Text:=’ Адрессервера’; // введемникпо-умолчанию,остальныеполяпростоочистимNikEdit.Text:=’Ананим’;TextEdit.Clear; ChatMemo.Lines.Clear; end;
Процедура“прослушивания”открытыхканаловсервером,выглядиттак:procedureTForm1.ServerTimerTimer(Sender: TObject); begin // условиенаналичиеустановленныхканаловif ServerSocket.Socket.ActiveConnections0 then begin //циклпосуществующимканаламfor i:=1 to ServerSocket.Socket.ActiveConnections do begin // сохранимпакет(еслиничегонеприслали,попакетпустой)
text:=ServerSocket.Socket.Connections.ReceiveText();// условие, что пакет не пуст if text” then begin // получим кодкоманды, длину строки com:=StrToInt(Copy(text,1,1)); len:=Length(text)-1; //определение команд case com of // код приема сообщения 0: begin // добавим в ChatMemoсообщение клиента ChatMemo.Lines.Add(Copy(text,2,len)); // разошлем сообщениепользователям (кроме того, кто прислал) for j:=0 toServerSocket.Socket.ActiveConnections-1 do begin if (j+1)i thenServerSocket.Socket.Connections[j].SendText(’0′+Copy(text,2,len)); end; end;// код приема ника клиента 1: begin // запишем в массив полученный ник UserMas.Name:=Copy(text,2,len);// отметим, что пользователь записан в список UserMas.Rec:=True; // обновляемсписок UpdateUserList; end; end; end; end; end; // разрешение на выполнениепроцедур обновления if UpdDo=True then begin // обновляем массив пользователей UpdateUserMas;// обновляем список пользователей UpdateUserList; // блокируем разрешение UpdDo:=False;end; end;
Перевод программы врежим сервера осуществляется клавишей “Создатьсервер” (ServerBtn). Вот так выглядит процедура на нажатие клавиши ServerBtn (OnClick):
procedureTForm1.ServerBtnClick(Sender: TObject); begin if ServerBtn.Tag=0 then begin //клавишу ClientBtn и поля HostEdit, PortEdit, NikEdit заблокируем ClientBtn.Enabled:=False;HostEdit.Enabled:=False; PortEdit.Enabled:=False; NikEdit.Enabled:=False; //запишем указанный порт в ServerSocket ServerSocket.Port:=StrToInt(PortEdit.Text);// запускаем сервер ServerSocket.Active:=True; // добавим в ChatMemo сообщениес временем создания ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Сервер создан.’);// изменяем тэг ServerBtn.Tag:=1; // меняем надпись клавиши ServerBtn.Caption:=’Закрытьсервер’; // включаем таймер сервера ServerTimer.Enabled:=True; // вписываемпараметры сервера UserMas[0].Status:=1; UserMas[0].Rec:=True; UserMas[0].Name:=NikEdit.Text;UserMas[0].Image:=1; // разрешаем обновление UpdDo:=True; end else begin //выключаем таймер сервера ServerTimer.Enabled:=False; // стираем параметры сервераUserMas[0].Status:=0; UserMas[0].Rec:=False; UserMas[0].Name:=’Неизвестный’; UserMas[0].Image:=0;// разрешаем обновление UpdDo:=True; // очищаем список клиентов UserListView.Items.Clear;// клавишу ClientBtn и поля HostEdit, PortEdit, NikEdit разблокируем ClientBtn.Enabled:=True;HostEdit.Enabled:=True; PortEdit.Enabled:=True; NikEdit.Enabled:=True; //закрываем сервер ServerSocket.Active:=False; // выводим сообщение в ChatMemo ChatMemo.Lines.Add(’[‘+TimeToStr(Time)+’]Сервер закрыт.’); // возвращаем тэгу исходное значение ServerBtn.Tag:=0; //возвращаем исходную надпись клавиши ServerBtn.Caption:=’Создать сервер’; end; end;
Далее идут события,которые должны происходить при определенном состоянии ServerSocket’а. Напишемпроцедуру, когда клиент подсоединился к серверу (OnClientConnect):
procedureTForm1.ServerSocketClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin// добавим в ChatMemo сообщение с временем подключения клиента ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’]Подключился клиент.’); // разрешаем обновление UpdDo:=True; end;
Напишем процедуру,когда клиент отключается (OnClientDisconnect):
procedureTForm1.ServerSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);begin // добавим в ChatMemo сообщение с временем отключения клиента ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’]Клиент отключился.’); // разрешаем обновление UpdDo:=True; end;
Отправка сообщений.Она осуществляется нажатием клавиши “Отправить” (SendBtn), но необходимапроверка режима программы сервер или клиент. Напишем ее процедуру (OnClick):
procedureTForm1.SendBtnClick(Sender: TObject); begin // проверка, в каком режименаходится программа if ServerSocket.Active=True then // отправляем сообщение ссервера всем пользователям for i:=0 to ServerSocket.Socket.ActiveConnections-1do ServerSocket.Socket.Connections.SendText(’0[‘+TimeToStr(Time)+’]‘+NikEdit.Text+’: ‘+TextEdit.Text) else // отправляем сообщение с клиента ClientSocket.Socket.SendText(’0[‘+TimeToStr(Time)+’]‘+NikEdit.Text+’: ‘+TextEdit.Text); // отобразим сообщение в ChatMemo ChatMemo.Lines.Add(’[‘+TimeToStr(Time)+’]‘+NikEdit.Text+’: ‘+TextEdit.Text); // очищаем TextEdit TextEdit.Clear; end;
Режим клиента.При нажатии клавиши “Подключиться” (ClientBtn), блокируется ServerBtn иактивируется ClientSocket. Вот процедура ClientBtn (OnClick):
procedureTForm1.ClientBtnClick(Sender: TObject); begin if ClientBtn.Tag=0 then begin //клавишу ServerBtn и поля HostEdit, PortEdit заблокируем ServerBtn.Enabled:=False;HostEdit.Enabled:=False; PortEdit.Enabled:=False; // запишем указанный порт вClientSocket ClientSocket.Port:=StrToInt(PortEdit.Text); // запишем хост иадрес (одно значение HostEdit в оба) ClientSocket.Host:=HostEdit.Text; ClientSocket.Address:=HostEdit.Text;// запускаем клиента ClientSocket.Active:=True; // изменяем тэг ClientBtn.Tag:=1;// меняем надпись клавиши ClientBtn.Caption:=’Отключиться’; end else begin //клавишу ServerBtn и поля HostEdit, PortEdit разблокируем ServerBtn.Enabled:=True;HostEdit.Enabled:=True; PortEdit.Enabled:=True; // закрываем клиента ClientSocket.Active:=False;// очищаем список клиентов UserListView.Items.Clear; // выводим сообщение вChatMemo ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Сессия закрыта.’); //возвращаем тэгу исходное значение ClientBtn.Tag:=0; // возвращаем исходнуюнадпись клавиши ClientBtn.Caption:=’Подключиться’; end; end;
ПроцедурынаOnConnect, OnDisconnect, OnRead клиентаClientSocket. Сначаланачтениесообщенияссервера(OnRead):
procedure TForm1.ClientSocketRead(Sender: TObject; Socket:TCustomWinSocket); begin // получимтекст,кодкомманды,длинустрокиtext:=Socket.ReceiveText(); com:=StrToInt(Copy(text,1,1)); len:=Length(text)-1;// определение коммандcase com of // добавимвChatMemo сообщение ссервера0: ChatMemo.Lines.Add(Copy(text,2,len)); // отошлемсвойникнасервер1: ClientSocket.Socket.SendText(‘1’+NikEdit.Text); // примемстрокуспискапользователей2: begin // очищаемсписокклиентовUserListView.Items.Clear; // добавимключконцастроки(т.к.вырезкасимволовсзадержкой)text:=text+Chr(152); // укажем начальныйсимволpos:=2; // обнулимсчетчиксимволовx:=0; // пробегаемподлинестрокиспискаfor j:=2 to len+1 do begin // записываемвсчетчиксдвигx:=x+1; // еслинайденключ(отделениениковвстроке)if Copy(text,j,1)=Chr(152) then begin // добавимвUserListView строку UItems:=UserListView.Items.Add;UItems.Caption:=Copy(text,pos,x-1); // укажемсоответствующуюиконкупользователяif pos>2 then UItems.ImageIndex:=0 elseUItems.ImageIndex:=1; // изменимтекущуюпозициювстрокеспискаpos:=j+1; // обнулимсчетчиксимволовx:=0; end; end; end; end; end;
Дальше обычноедобавление в ChatMemo определенного сообщения:
procedureTForm1.ClientSocketConnect(Sender: TObject; Socket: TCustomWinSocket); begin //добавим в ChatMemo сообщение о соединении с сервером ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’]Подключение к серверу.’); end;
procedureTForm1.ClientSocketDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin// добавим в ChatMemo сообщение о потере связи ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’]Сервер не найден.’); end;
Хранителем информации опользователях у нас выступает массив, процедура его заполнения и обновлениявыглядит так:
procedureTForm1.UpdateUserMas; begin // очищаем массив с информацией for i:=1 to 255 do beginUserMas.Status:=0; UserMas.Rec:=False; UserMas.Name:=’Неизвестный’; UserMas.Image:=0;end; // заполняем данные пользователей if ServerSocket.Socket.ActiveConnections0then begin for i:=1 to ServerSocket.Socket.ActiveConnections do begin UserMas.Status:=2;UserMas.Name:=’Неизвестный’; UserMas.Image:=0; // запрашиваем имя (ник)пользователя по его каналу (код команды — 1) ServerSocket.Socket.Connections.SendText(’1′);end; end; end;
Список UserListViewобновляется в следующей процедуре:
procedureTForm1.UpdateUserList; begin // очищаем список клиентов UserListView.Items.Clear;// очищаем переменную StrUserList:=”; // обнуляем пометку записи ContList:=0; //пробегаем по диапазону каналов for i:=0 to 255 do begin // если запись непустая if UserMas.Status0 then begin // добавим в UserListView строку UItems:=UserListView.Items.Add;UItems.Caption:=UserMas.Name; UItems.ImageIndex:=UserMas.Image; // еслипользователь не записан if UserMas.Rec=False then ContList:=1; // составляемстроку пользователей StrUserList:=StrUserList+UserMas.Name+Chr(152); end; end; //если все пользователи отметились, и есть хоть один канал if (ContList=0) and(ServerSocket.Socket.ActiveConnections0) then begin // пробегаем повсем открытым каналам for i:=0 to ServerSocket.Socket.ActiveConnections-1 do begin// отправим строку списка пользователей (код команды — 2) ServerSocket.Socket.Connections.SendText(’2′+StrUserList);end; end; end;
Листингпрограммы
unit MainUnit;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes,Graphics, Controls, Forms,
 Dialogs, StdCtrls, ScktComp, ExtCtrls, ImgList,ComCtrls, jpeg;
type
 TForm1 = class(TForm)
 ServerSocket: TServerSocket;
 ClientSocket: TClientSocket;
 PortEdit: TEdit;
 NikEdit: TEdit;
 TextEdit: TEdit;
 ChatMemo: TMemo;
 HostEdit: TEdit;
 ServerBtn: TButton;
 ClientBtn: TButton;
 SendBtn: TButton;
 Label1: TLabel;
 Label2: TLabel;
 Label3: TLabel;
 Label4: TLabel;
 Label5: TLabel;
 UserListView: TListView;
 Label6: TLabel;
 ImageList: TImageList;
 ServerTimer: TTimer;
 Image1: TImage;
 procedure FormCreate(Sender: TObject);
 procedure UpdateUserList;
 procedure UpdateUserMas;
 procedure ServerBtnClick(Sender: TObject);
 procedure ClientBtnClick(Sender: TObject);
 procedure ServerSocketClientConnect(Sender:TObject;
 Socket: TCustomWinSocket);
 procedure ServerSocketClientDisconnect(Sender:TObject;
 Socket: TCustomWinSocket);
 procedure SendBtnClick(Sender: TObject);
 procedure ClientSocketRead(Sender: TObject; Socket:TCustomWinSocket);
 procedure ClientSocketDisconnect(Sender: TObject;
 Socket: TCustomWinSocket);
 procedure ClientSocketConnect(Sender: TObject;
 Socket: TCustomWinSocket);
 procedure ServerTimerTimer(Sender: TObject);
 procedure TextEditKeyDown(Sender: TObject; var Key:Word;
 Shift: TShiftState);
 private
 { Private declarations }
 public
 { Public declarations }
 end;
Type
 TUserList = object
 Status: Byte;
 Rec: Boolean;
 Name: String;
 Image: Byte;
 end;
var
 Form1: TForm1;
 i, j, com, ContList: Byte;
 len, pos, x: Word;
 text, StrUserList: String;
 UpdDo: Boolean;
 Buf: array[0..3] of Byte;
 UserMas: array[0..255] of TUserList;
 UItems: TListItem;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
 Caption:=’Многопользовательскийчат’;
 Application.Title:=Caption;
 PortEdit.Text:=’Портсервера’;
 HostEdit.Text:=’Адрессервера’;
 NikEdit.Text:=’Ананим’;
 TextEdit.Clear;
 ChatMemo.Lines.Clear;
end;
procedure TForm1.UpdateUserList;
begin
 UserListView.Items.Clear;
 StrUserList:=”;
 ContList:=0;
 For i:=0 to 255 do
 Begin
 If UserMas[i].Status0 then
 Begin
 UItems:=UserListView.Items.Add;
 UItems.Caption:=UserMas[i].Name;
 UItems.ImageIndex:=UserMas[i].Image;
 If UserMas[i].Rec=False then ContList:=1;
 StrUserList:=StrUserList+UserMas[i].Name+Chr(152);
 end;
 end;
 If (ContList=0) And(ServerSocket.Socket.ActiveConnections0) then
 Begin
 For i:=0 to ServerSocket.Socket.ActiveConnections-1do
 Begin
 ServerSocket.Socket.Connections[i].SendText(‘2’+StrUserList);
 end;
 end;
end;
procedure TForm1.UpdateUserMas;
begin
 For i:=1 to 255 do
 Begin
 UserMas[i].Status:=0;
 UserMas[i].Rec:=False;
 UserMas[i].Name:=’Неизвестный’;
 UserMas[i].Image:=0;
 end;
 If ServerSocket.Socket.ActiveConnections0then
 Begin
 For i:=1 to ServerSocket.Socket.ActiveConnectionsdo
 Begin
 UserMas[i].Status:=2;
 UserMas[i].Name:=’Неизвестный’;
 UserMas[i].Image:=0;
 ServerSocket.Socket.Connections[i-1].SendText(‘1’);
 end;
 end;
end;
procedure TForm1.ServerBtnClick(Sender: TObject);
begin
 If ServerBtn.Tag=0 then
 Begin
 ClientBtn.Enabled:=False;
 HostEdit.Enabled:=False;
 PortEdit.Enabled:=False;
 NikEdit.Enabled:=False;
 ServerSocket.Port:=StrToInt(PortEdit.Text);
 ServerSocket.Active:=True;
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Серверсоздан.’);
 ServerBtn.Tag:=1;
 ServerBtn.Caption:=’Закрытьсервер’;
 ServerTimer.Enabled:=True;
 UserMas[0].Status:=1;
 UserMas[0].Rec:=True;
 UserMas[0].Name:=NikEdit.Text;
 UserMas[0].Image:=1;
 UpdDo:=True;
 end
 else
 Begin
 ServerTimer.Enabled:=False;
 UserMas[0].Status:=0;
 UserMas[0].Rec:=False;
 UserMas[0].Name:=’Неизвестный’;
 UserMas[0].Image:=0;
 UpdDo:=True;
 UserListView.Items.Clear;
 ClientBtn.Enabled:=True;
 HostEdit.Enabled:=True;
 PortEdit.Enabled:=True;
 NikEdit.Enabled:=True;
 ServerSocket.Active:=False;
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Серверзакрыт.’);
 ServerBtn.Tag:=0;
 ServerBtn.Caption:=’Создатьсервер’;
 end;
end;
procedure TForm1.ClientBtnClick(Sender: TObject);
begin
 If ClientBtn.Tag=0 then
 Begin
 ServerBtn.Enabled:=False;
 HostEdit.Enabled:=False;
 PortEdit.Enabled:=False;
 ClientSocket.Port:=StrToInt(PortEdit.Text);
 ClientSocket.Host:=HostEdit.Text;
 ClientSocket.Address:=HostEdit.Text;
 ClientSocket.Active:=True;
 ClientBtn.Tag:=1;
 ClientBtn.Caption:=’Отключиться’;
 end
 else
 Begin
 ServerBtn.Enabled:=True;
 HostEdit.Enabled:=True;
 PortEdit.Enabled:=True;
 ClientSocket.Active:=False;
 UserListView.Items.Clear;
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Сессиязакрыта.’);
 ClientBtn.Tag:=0;
 ClientBtn.Caption:=’Подключиться’;
 end;
end;
procedure TForm1.ServerSocketClientConnect(Sender:TObject;
 Socket: TCustomWinSocket);
begin
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Подключилсяклиент.’);
 UpdDo:=True;
end;
procedureTForm1.ServerSocketClientDisconnect(Sender: TObject;
 Socket: TCustomWinSocket);
begin
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Клиентотключился.’);
 UpdDo:=True;
end;
procedure TForm1.SendBtnClick(Sender: TObject);
begin
 If ServerSocket.Active=True then
 For i:=0 to ServerSocket.Socket.ActiveConnections-1do
 ServerSocket.Socket.Connections[i].SendText(‘0[‘+TimeToStr(Time)+’]’+NikEdit.Text+’: ‘+TextEdit.Text)
 else
 ClientSocket.Socket.SendText(‘0[‘+TimeToStr(Time)+’]’+NikEdit.Text+’: ‘+TextEdit.Text);
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] ‘+NikEdit.Text+’:’+TextEdit.Text);
 TextEdit.Clear;
end;
procedure TForm1.ClientSocketRead(Sender: TObject;
 Socket: TCustomWinSocket);
begin
 text:=Socket.ReceiveText();
 com:=StrToInt(Copy(text,1,1));
 len:=Length(text)-1;
 Case com of
 0: ChatMemo.Lines.Add(Copy(text,2,len));
 1: ClientSocket.Socket.SendText(‘1’+NikEdit.Text);
 2: Begin
 UserListView.Items.Clear;
 text:=text+Chr(152);
 pos:=2;
 x:=0;
 For j:=2 to len+1 do
 Begin
 x:=x+1;
 If Copy(text,j,1)=Chr(152) then
 Begin
 UItems:=UserListView.Items.Add;
 UItems.Caption:=Copy(text,pos,x-1);
 If pos>2 then UItems.ImageIndex:=0 else UItems.ImageIndex:=1;
 pos:=j+1;
 x:=0;
 end;
 end;
 end;
 end;
end;
procedure TForm1.ClientSocketConnect(Sender:TObject;
 Socket: TCustomWinSocket);
begin
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Подключениексерверу.’);
end;
procedure TForm1.ClientSocketDisconnect(Sender:TObject;
 Socket: TCustomWinSocket);
begin
 ChatMemo.Lines.Add(‘[‘+TimeToStr(Time)+’] Серверненайден.’);
end;
procedure TForm1.ServerTimerTimer(Sender: TObject);
begin
 If ServerSocket.Socket.ActiveConnections0then
 Begin
 For i:=1 to ServerSocket.Socket.ActiveConnectionsdo
 Begin
 text:=ServerSocket.Socket.Connections[i-1].ReceiveText();
 If text” then
 Begin
 com:=StrToInt(Copy(text,1,1));
 len:=Length(text)-1;
 Case com of
 0: Begin
 ChatMemo.Lines.Add(Copy(text,2,len));
 For j:=0 to ServerSocket.Socket.ActiveConnections-1do
 Begin
 If (j+1)i thenServerSocket.Socket.Connections[j].SendText(‘0’+Copy(text,2,len));
 end;
 end;
 1: Begin
 UserMas[i].Name:=Copy(text,2,len);
 UserMas[i].Rec:=True;
 UpdateUserList;
 end;
 end;
 end;
 end;
 end;
 If UpdDo=True then
 Begin
 UpdateUserMas;
 UpdateUserList;
 UpdDo:=False;
 end;
end;
procedure TForm1.TextEditKeyDown(Sender: TObject;var Key: Word;
 Shift: TShiftState);
begin
 If Key=VK_RETURN then SendBtn.Click;
end;
end.

Заключение
В моей курсовой работея достиг, поставленных перед собою целей реализовав программный продукт онлайнобщения — чат. Данный проект может быть развит в перспективе до более высокогоуровня, добавив некоторые новые функциональных возможностей.
В данный момент, всвязи с бурным развитием WEBтехнологий, нет смысла создавать собственную программу чата. Так как в болееудобно взять уже готовый, полностью завершенный чат.

Приложение
Запущенный сервер:
/>

При подключение ксерверу (у сервера):
/>

При подключении ксерверу (у клиента):
/>

/>Отправкасообщений (у сервера и клиента):