//Кнопка подключения к серверу
var
host,port:string;
begin
{Проверка введены ли данные(ip,port,nickname)}
if (edit2.Text='') or (edit3.Text='') or (edit4.Text='') then
statusbar2.Panels[0].Text:='Заполните все поля'
else
begin
{Если уже есть подключение}
if ClientSocket1.Active then
begin
host:=edit2.Text;
port:=edit3.Text;
Nickname:=edit4.Text;
ClientSocket1.Host:=host;
ClientSocket1.port:=strtoint(port);
ClientSocket1.Open;
ClientSocket2.Host:=ClientSocket1.host;
ClientSocket2.port:=ClientSocket1.port+50;
ClientSocket2.Open;
end
{Если нет подключение}
else
ClientSocket1.Close;
ClientSocket2.Close;
host:=edit2.Text;
port:=edit3.Text;
Nickname:=edit4.Text;
ClientSocket1.Host:= host;
ClientSocket1.Port:= StrToInt(port);
Nickname:=edit4.Text;
ClientSocket1.Open;
ClientSocket2.Host:=ClientSocket1.host;
ClientSocket2.port:=ClientSocket1.port+50;
ClientSocket2.Open;
end;
end;
//Кнопка отключения от сервера
Begin
{Закрытие подключения}
ClientSocket1.Close;
ClientSocket2.Close;
end;
//Команды от сервера
var s,from_,to_: string;
temp:integer;
begin
{присваиваем s полученную от сервера строку}
s:= Socket.ReceiveText;
if Copy(s,1,2) = '#F' then
begin
Delete(s,1,2);
FStream:= TFileStream.Create('temp\'+s, fmCreate or fmShareDenyWrite);
exit;
end;
{Если сервер посылает нам Новый Ник}
if Copy(s,1,2) = '#K' then begin
Delete(s,1,2);
if copy(s,1,pos(';',s)-1)=NickName then begin
Delete(s,1,pos(';',s));
ShowMessage('Администратор изменил ваше имя на: -'+S);
edit4.Text:=S;
button3.Click;
button2.Click;
exit;
end;
exit;
end;
{Если сервер посылает нам User List}
if Copy(s,1,2) = '#U' then begin
Delete(s,1,2);
Temp:=0;
{Чистим 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}
richedit1.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
begin
richedit1.Lines.Insert(0,from_+' (private) > '+s);
RichEdit1.SelStart:=0;
RichEdit1.SelLength:=RichEdit1.Lines[1].Length;
RichEdit1.selAttributes.Color:= clred;
Exit;
end;
end;
if Copy(s,1,2) = '#D' then begin
Delete(s,1,2);
if s=nickname then begin
button3.Click;
ShowMessage('Вы отключены Администратором');
exit;
end;
end;
if Copy(s,1,2) = '#A' then begin
Delete(s,1,2);
if copy(s,1,pos(';',s)-1)=NickName then begin
Delete(s,1,pos(';',s));
ShowMessage('Администратор: -'+S);
exit;
end;
exit;
end;
end;
//Получение файла
var s,s1: string;
i: Integer;
iLen: Integer;
Bfr: Pointer;
begin
iLen:= Socket.ReceiveLength;
GetMem(Bfr, iLen);
try
Socket.ReceiveBuf(Bfr^, iLen);
FStream.Write(Bfr^, iLen);
finally
FreeMem(Bfr);
end;
end;
//Отправка сообщения
var s: string;
begin
if (CheckBox1.Checked)and(ListBox1.ItemIndex < 0) then begin
ShowMessage('Чтобы послать приватное сообшение, сначала выберите получателя!');
Exit;
end;
{Если это приватное сообщение}
if CheckBox1.Checked=true 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;
//Отправка файла
begin
FStream.Free;
opendialog1.Execute;
ClientSocket1.Socket.SendText('#F'+ExtractFileName(opendialog1.FileName));
ClientSocket2.Socket.SendStream(TFileStream.Create(opendialog1.FileName, fmOpenReadWrite or fmShareDenyWrite));
ClientSocket1.Socket.SendText('#S'+ExtractFileName(opendialog1.FileName));
FStream.Free;
Порядок работы с программой
Работа с сервером.
|
Рисунок1 - Настройки сервера |
Рисунок1 - Настройки сервера. Главной настройкой является поле «Порт» по умолчанию стоит порт «1010». Сервер можно запустить нажав на кнопку «Запуск», если порт свободен и нет больше никаких проблем то в строке состояния отобразится надпись «Сервер запушен», теперь клиенты могут подключаться к серверу. Отключение сервера происходит нажатием кнопкой «Отключить». Есть возможность свернуть сервер в трэй, нажатием кнопки «Свернуть в трэй».
Рисунок2 - Лог чата |
Рисунок2 – Лог чата. Это история сервера, в ней ведутся записи о подключении и отключении пользователей, времени запуска и отключении сервера. Кнопка «Сохранить», сохраняет историю в выбранный текстовый файл. Кнопка «Очистить», очищает историю.
Рисунок3 - Пользователи. Эта закладка со списком подключенных клиентов.
Кнопки:
· Отключить – отключает выбранного пользователя от сервера.
· Сообщение – посылает выбранному пользователю сообщение от администратора сервера.
·
Рисунок3 - Пользователи |
Сменить ник – изменяет имя клиента в чате на новое введённое администратором.
Работа с клиентом.
Рисунок №4 - Закладка «Чат». Закладка на которой и происходит переписка между клиентами. Для того чтобы отослать сообщение нужно написать текст в поле с надписью «Текст сообщения» и нажать кнопку «Send». В том случае если нужно послать сообщение только одному клиенту нужно поставить галочку «ПРИВАТНОЕ» и выбрать получателя из списка.
Для того чтобы послать файл нужно нажать кнопку «…», файл будет разослан всем клиентам вне зависимости от приватности.
|
Рисунок4 - Чат |
Рисунок 5 - Подключение и Настройки. Как видно из названия в этой закладке происходит подключение к серверу и настройка клиента.
· «IP» - адрес сервера к которому нужно подключится, для подключения к серверу который включен на том же компьютере что и клиент в поле «ip» пишется «LocalHost».
· «Порт» - порт использует сервер
· «NickName» - имя клиента которое будет отображено остальным клиентам.
·
Рисунок5 - Подключение и настройки |
Кнопка «Подключится» подключается к серверу с заданными параметрами, а кнопка «Отключится» соответственно отключается от подключенного сервера.
Тестирование системы
В ходе тестирования, сервер и клиент проверялись по локальной сети на 3х компьютерах, на двух компьютерах было запущена клиентская часть, а на третьем Сервер и Клиент одновременно, в ходе проверок клиент и сервер интенсивно проверялись на ошибки и исключительные ситуации. Все задачи Клиент-сервер выполняет хорошо, но были выявлены некоторые проблемы с передачей файлов.
· Существуют некоторые проблемы при передачи файлов, например если передать файл два раза подряд то на клиентской части выйдет ошибка доступа к файлу.
· При сильной нагрузки сервера или медленном соединении, файлы могут не доходить до получателя или доходить не полностью.
Заключение
В ходе проделанной мной работы был реализован клиент серверный чат. Сервер поддерживает большое количество пользователей, отправку файлов, пересылку приватных сообщений, ведёт список подключенных клиентов и администрирование клиентов, работая в локальной сети.
Клиентская часть поддерживает отправку общих и приватных сообщений, отправку файлов также клиент ведёт список пользователей, который получает от сервера, возможность выбрать имя в чате.
Достоинством этой системы является быстродействие текст моментально передаётся по сети даже при медленном соединении, возможность общаться большому количеству людей, делает эту систему удобной для работы группы лиц, решения общих проблем.
Одним из недостатков является то, что для реализации работы были использованные не актуальные компоненты, в которых не такой большой спектр возможностей, и возможно с ними не так удобно работать, как с более продвинутыми. Но целью моей работы являлось изучение методов и алгоритмов простейшей работы и взаимодействия приложений по сети, так что этот недостаток не так важен.
Путей дальнейшего совершенствования системы огромное множество, например:
· Перевод системы на актуальные компоненты работы по сети.
· Добавление видео чата.
· Добавления смайликов.
· Улучшение протокола, для оптимизации быстродействия.
· Доработка протокола пересылки файлов.
· Внедрение мульти платформенной системы, к примеру чтобы можно было подключится к чату с помощью телефона, или любой другой операционной системы.
· Введение регистрации пользователей, это также позволит реализовать доставку сообщений не активным в данный момент клиентам.
Используемые источники
1. Карих Н. Алгоритм работы сокетного сервера // ИсходникиRU [сайт]. URL: https://www.sources.ru/delphi/delphi_serv_sock.shtml (дата обращения: 10.05.2012).
2. Чат // Википедия — свободнfz энциклопедиz [сайт]. URL: https://ru.wikipedia.org/wiki/%D0%A7%D0%B0%D1%82(дата обращения: 06.05.2012).
3. Алгоритм работы сокетного сервера // Библиотека RTFM [сайт]. https://docs.luksian.com/programming/delphi/prsokdelph/index.php(дата обращения: 10.05.2012).
4. Сокеты в Delphi // DelphiSource [сайт]. URL: https://www.delphisources.ru/pages/faq/base/sockets_in_delphi.html(дата обращения: 10.05.2012).