Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Пример чата для локальной сети



В этом примере два приложения - чат-сервер и чат-клиент. Чат-клиенты подключаются к чат-серверу и через него обмениваются сообщениями. Чат-сервер может быть запущен и на том компьютере, где запущен один из клиентов. Кроме того, для тестирования Вы можете запустить на своем компьютере сразу чат-сервер и несколько чат-клиентов. Для этого нужно указать localhost в поле Host, а в поле Port у сервера и у клиента должны быть одинаковые значения. Не путайте сервер в понимании программы, принимающей вызовы клиентов, с компьютером-сервером! То же самое и с клиентом.

Разработка чат-сервера

1. Создайте форму и разместите на ней следующие компоненты: ListBox1, ServerSocket1 и Panel1. На
 
 

компоненте Panel1 разместите Button1 (Start), Button2 (Stop). (рис.3)

Рис.3 Пример окна формы чат-сервера

2. Введите текст процедуры обработки события нажатия на кнопку Button1:

{Запуск сервера}
procedure TForm1.Button1Click(Sender: TObject);
var s: string;
begin
{Запрашиваем порт}
s:= InputBox('Start chat server','Enter port:','1001');
if s = '' then
Exit;
{Чистим лист пользователей}
ListBox1.Items.Clear;
{Устанавливаем порт}
ServerSocket1.Port:= StrToInt(s);
{Запускаем сервер}
ServerSocket1.Open;
end;

3. Введите текст процедуры обработки события нажатия на кнопку Button2:

procedure TForm1.Button2Click(Sender: TObject);
begin
{Чистим юзер лист и останавливаем сервер}
ListBox1.Items.Clear;
if ServerSocket1.Active then
ServerSocket1.Close;
end;


4. Введите текст процедуры обработки события OnClientRead для компонента ServerSocket1:

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var s: string;
i: Integer;
begin
{сохраняем в s присланную нам строку}
s:= Socket.ReceiveText;
{Если кто-то прислал нам свое имя}
if Copy(s,1,2) = '#N' then begin
Delete(s,1,2);
{Добавляем его в юзер лист}
ListBox1.Items.Add(s);
{Записываем в s команду для посылки нового списка пользователей}
s:= '#U';
for i:= 0 to ListBox1.Items.Count-1 do
s:= s+ListBox1.Items[i]+';';
{...и рассылаем этот список всем клиентам}
for i:= 0 to ServerSocket1.Socket.ActiveConnections-1 do
ServerSocket1.Socket.Connections[i].SendText(s);
Exit;
end;
{Если кто-то отправил сообщение - рассылаем его всем клиентам}
if (Copy(s,1,2) = '#M')or(Copy(s,1,2) = '#P') then begin
for i:= 0 to ServerSocket1.Socket.ActiveConnections-1 do
ServerSocket1.Socket.Connections[i].SendText(s);
Exit;
end;
end;

Первая строка - сохраняет полученные из сокета данные в s. Далее, функция Copy(s,1,2) возвращает первые два символа строки s, которые затем проверяются на соответствие с условно-введенной нами командой "#N", которая означает, что в строке s после самой команды содержится присланное кем-либо из клиентов имя (ник - псевдоним). Это имя затем добавляется в ListBox1. Таким образом ListBox1 становится списком подключенных клиентов.

Далее, в строку s (информация в которой уже не нужна) записывается команду "#U" и последовательно всех пользователей из списка ListBox1. Затем всю эту строку рассылаем ВСЕМ клиентам.

Затем, если получили не "#N", а "#M" или "#P" (простое или приватное сообщение) - рассылаем его всем клиентам.

5. Введите текст процедуры обработки событий OnClientDisconnect и OnAccept для компонента ServerSocket1:

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
var i: Integer;
begin
{Кто-то присоединился или отсоединился? Запрашиваем у всех пользователей их имена}
ListBox1.Items.Clear;
for i:= 0 to ServerSocket1.Socket.ActiveConnections-1 do
ServerSocket1.Socket.Connections[i].SendText('#N');
end;

ServerSocket1ClientDisconnect - обработчик события, возникающего когда кто-либо из клиентов отсоединился от сервера. Здесь мы очищаем список юзеров и посылаем всем клиентам запросы на получение их ников (псевдонимов).

Примечание:

Данный пример дан в упрощенной форме. Возможности нормального чата должны быть намного шире. Также имейте в виду, что команды типа "#N", "#U", "#M", и т.д. вводятся самим разработчиком для определения того, что прислали из сокета. Эти команды никак не привязаны непосредственно к сокетам.

Разработка чат-клиента

1. Создайте форму Form1 и разместите на ней следующие компоненты: Panel1, Panel2, Panel3, Memo1, ClientSocket1. На компонентe Panel1 разместите Button1 (Send), Button2 (Connect), Button3 (Disconnect), Edit1, CheckBox1 (Private message). На Panel2 – ListBox1 и Label1 (UserList). На Panel3 - Label2 (Status) и Label3 (Idle). (рис.4)

Рис.4 – Пример окна формы чат-клиента

2. Создайте форму Form2 (Connect) и разместите на ней следующие компоненты: Label1(Enter the host name…), Label2 (Host), Label3 (Port), Label4 (Nickname), Edit1, Edit2, Edit3, Button1 (Connect), Button2 (Cancel). (Рис.5)


 
 

Рис.5 – Пример окна формы подключения к серверу

3. Далее приведем исходный текст чат-клиента с необходи-мыми пояснениями:


{Для формы TForm1}

var
Form1: TForm1;
nickname: string; {Ник (псевдоним)}
implementation
uses conn; {Юнит с диалогом установки соединения}

{$R *.DFM}


// реакция на событие onClick для Button2
procedure TForm1.Button2Click(Sender: TObject);
var do_connect: Boolean;
host,port: string;
begin
{Показываем окно установки соединения с сервером}
Form2:= TForm2.Create(Application);
{do_connect = True, если была нажата кнопка Connect}
do_connect:= (Form2.ShowModal = mrOk);
{заполнение переменных до того, как мы уничтожим форму}
host:= Form2.Edit1.Text;
port:= Form2.Edit2.Text;
nickname:= Form2.Edit3.Text;
{Уничтожаем форму}
Form2.Free;
{Если была нажата кнопка Cancel, то уходим отсюда}
if not do_connect then
Exit;
{Если соединение уже установлено, то обрываем его}
if ClientSocket1.Active then
ClientSocket1.Close;
{Устанавливаем свойства Host и Port}
ClientSocket1.Host:= host;
ClientSocket1.Port:= StrToInt(port);
{Пытаемся соединиться}
ClientSocket1.Open;
end;

// реакция на событие onClick для Button3
procedure TForm1.Button3Click(Sender: TObject);
begin
{Закрываем соединение (если оно установлено)}
if ClientSocket1.Active then
ClientSocket1.Close;
end;

// реакция на события для ClientSocket1

//OnError

procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
{Если произошла ошибка, выводим ее код в Memo1}
{Insert вставляет строку в указанную позицию (в данном случае - 0 - в начало)}

Memo1.Lines.Insert(0,'Socket error ('+IntToStr(ErrorCode)+')');
end;

//OnLookUp
procedure TForm1.ClientSocket1Lookup(Sender: TObject;
Socket: TCustomWinSocket);
begin
{Сообщаем о том, что идет поиск хоста}
Memo1.Lines.Insert(0,'Looking up for server...');
end;

//OnConnecting
procedure TForm1.ClientSocket1Connecting(Sender: TObject;
Socket: TCustomWinSocket);
begin
{соединяемся...}
Memo1.Lines.Insert(0,'connecting...');
end;

//OnConnect
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
{соединились!}
Memo1.Lines.Insert(0,'connected!');
end;

//OnDisconnect
procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
{отсоединились:(}
Memo1.Lines.Insert(0,'disconnected');
end;


//OnRead
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var s,from_,to_: string;
begin
{присваиваем s полученную от сервера строку}
s:= Socket.ReceiveText;
{Если сервер посылает нам User List}
if Copy(s,1,2) = '#U' then begin
Delete(s,1,2);
{Чистим ListBox1}
ListBox1.Items.Clear;
{Добавляем по одному юзеру в список. Имена юзеров разделены знаком ";"}
while Pos(';',s) > 0 do begin
ListBox1.Items.Add(Copy(s,1,Pos(';',s)-1));
Delete(s,1,Pos(';',s));
end;
Exit;
end;
{Если нам прислали общее сообщение (видимое для всех юзеров)}
if Copy(s,1,2) = '#M' then begin
Delete(s,1,2);
{Добавляем его в Memo1}
Memo1.Lines.Insert(0,Copy(s,1,Pos(';',s)-1)+'> '+
Copy(s,Pos(';',s)+1,Length(s)-Pos(';',s)));
Exit;
end;
{Если нам прислали запрос на наше имя юзера}
if Copy(s,1,2) = '#N' then begin
{Посылаем ответ}
Socket.SendText('#N'+nickname);
Exit;
end;
{Если нам прислали приватное сообщение (или не нам:))}
if Copy(s,1,2) = '#P' then begin
Delete(s,1,2);
{Выделяем в to_ - кому оно предназначено}
to_:= Copy(s,1,Pos(';',s)-1);
Delete(s,1,Pos(';',s));
{Выделяем в from_ - кем отправлено}
from_:= Copy(s,1,Pos(';',s)-1);
Delete(s,1,Pos(';',s));
{Если оно для нас, или написано нами - добавляем в Memo1
(иногда полезно убрать этот оператор if:))}

if (to_ = nickname)or(from_ = nickname) then
Memo1.Lines.Insert(0,from_+' (private) > '+s);
Exit;
end;
end;

// реакция на событие onClick для Button1
procedure TForm1.Button1Click(Sender: TObject);
var s: string;
begin
{Если мы хотим послать приватное сообщение, но не выбрали адресата -
нас покарают замечанием:) и выгонят из обработчика}

if (CheckBox1.Checked)and(ListBox1.ItemIndex < 0) then begin
ShowMessage('At first you should select the user in the User List!');
Exit;
end;
{Если это приватное сообщение}
if CheckBox1.Checked then
s:= '#P'+ListBox1.Items[ListBox1.ItemIndex]+';' {добавляем спец.команду и адресат}
else {А если не очень приватное?}
s:= '#M'; {Просто спец.команду}
{Добавляем наше имя (от кого) и само сообщение}

s:= s+nickname+';'+Edit1.Text;
{Посылаем все эти данные по сокету}
ClientSocket1.Socket.SendText(s);
{И снова ждем ввода в уже чистом TEdit-е}
Edit1.Text:= '';
ActiveControl:= Edit1;
end;

// реакция на событие onKeyDown для Edit1
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
{Если была нажата Enter (для тех, кто с мышами не дружит) - тоже не
отказываемся послать сообщение}

if Key = VK_RETURN then
Button1.Click;
end;

Button2Click - вызывает диалог установки соединения (из второго юнита), а затем устанавливает это соединение.

ClientSocket1Read - сначала мы сохраняем полученные по сокету данные в строку s. Затем, если нам прислали список других подключенных клиентов, то мы выделяем из строки s по одному юзеру и добавляем их последовательно в ListBox1. Таким образом ListBox1 становится списком юзеров. Далее - если нам прислали команду "#M" - обычное сообщение, то мы выделяем из s отправителя и само сообщение, а затем все это в стандартной для чатов форме выводим в Memo1. Если же был получен запрос на имя пользователя (ник) - команда "#N", то посылаем серверу свой ник. А если пришло приватное сообщение ("#P"), то из строки s мы выделяем имя отправителя, адресата и само сообщение. Если сообщение адресовано нам, либо мы же его и отправили - выводим его в Memo1.

Button1Click - обработчик нажатия кнопки отправки сообщения. Если поставлен флаг CheckBox1 (т.е. сообщение - приватное), а адресат в списке пользователей не выделен - выдаем ошибку. Далее формируем в s команду для отправки сообщения: сначала тип ("#P" или "#M". Если "#P", то плюс имя адресата из списка юзеров), разделитель (";"), затем - имя отправителя, разделитель, и непосредственно сам текст сообщения. Далее идет отправка строки s по сокету, очистка поля ввода сообщения, и перевод в него фокуса (курсора).

Edit1KeyDown нужен для того, чтобы при отправке сообщения вместо нажатия кнопки Button1, просто нажимать Enter.





Дата публикования: 2015-04-10; Прочитано: 226 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.008 с)...