Сокеты делфи. Программирование серверов на основе сокетов в дельфи

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

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

Чтоб можно было отделить команды от файла, сначала пошлём клиенту примерно такую строку: "file#file.txt#16", то есть: команда + разделитель + имя файла + разделитель + размер файла.
При получении данной команды, клиент перейдёт в режим приёма файла и всё подряд будет записывать в буфер, до тех пор пока размер файла не будет равен размеру принятых данных. Таким образом клиент отделит команды от файла!

И так приступим к написанию кода:
Начнём с сервера (он будет посылать файл):

Разместите на форму следующие компоненты: TServerSocket, TButton, TEdit, TProgressBar и TStatiusBar. Расположите их как показанно на рисунке.
Установите у компонента TServerSocket, порт (port): 1001.
Установите у компонента TStatusBar, переменную SimplePanel в true.
В строке, вводится название файла для передачи, кнопка TButton, используется для передачи файла.

Сначала добавим буфер для файла в глобальные переменные:

Var Form1: TForm1; MS: TMemoryStream; // Буфер для файла

Теперь сделаем, чтоб при создании формы, открывался сокет:

Procedure TForm1.FormCreate(Sender: TObject); begin ServerSocket1.Open; // Открываем сокет end;

При завершении приложения, нужно не забыть закрыть сокет:

Procedure TForm1.FormDestroy(Sender: TObject); begin ServerSocket1.Close; // Закрываем сокет end;

При нажатии на кнопку посылаем файл:

Procedure TForm1.Button1Click(Sender: TObject); // Передаём файл var Size: integer; P: ^Byte; begin MS:= TMemoryStream.Create; // Создаём буфер для файла MS.LoadFromFile(Edit1.Text); // Загружаем файл в буфер // Посылаем информацию о файл (команда # название # размер) ServerSocket1.Socket.Connections.SendText("file#"+Edit1.Text+"#"+IntToStr(MS.Size)+"#"); MS.Position:= 0; // Переводим каретку в начало файла P:= MS.Memory; // Загружаем в переменную "P" файл Size:= ServerSocket1.Socket.Connections.SendBuf(P^, MS.Size); // Посылаем файл // Выводим прогресс ProgressBar1.Position:= Size*100 div MS.Size; StatusBar1.SimpleText:= "Отправлено "+IntToStr(Size)+" из "+IntToStr(MS.Size)+" байт"; end;

На событие OnClientRead, компонента TServerSocket, впишите следующий код:

Procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); begin if Socket.ReceiveText = "end" then // Если клиент принял файл, то... begin StatusBar1.SimpleText:= "Клиент принял файл"; MS.Free; // Убиваем буфер end; end;

Это нужно для того, чтоб сервер убил буфер, только после того, как клиент примет файл. Если убить буфер, сразу после передачи файла, то клиент не успеет принять весь файл! Как только клиент примет файл, он пошлёт серверу команду "end", что значит файл принят, и сервер убьёт буфер.

Теперь сделаем чтоб наш сервер выводил немного информации о соединении:
На событие OnClientConnect, компонента TServerSocket впишите следующий код:

Procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= "Соединение установлено"; end;

А на событие OnClientDisconnect впишите:

Procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= "Соединение не установлено"; end;

Вот сервер и готов! Теперь перейдём к клиенту (он принимает файл) с пим возни будет побольше:

Разместите на форуму компоненты: TClientSocket, две метки TLabel, TProgressBar и TStatusBar.
Установите у компонента TClientSocket, порт (port): 1001 (как у сервера), а переменную адрес (address): 127.0.0.1 (ваш IP).
Не забудьте установить у компонента TStatusBar, переменную SimplePanel в true, чтоб было видно наш текст.
В одном TLabel"е выводится имя фала, в другой размер файла.
Должно получиться что-то похожее на это:

Объявляем переменные и оду процедуру. Запишите переменные именно в private , иначе ничего не будет работать:

Procedure Writing(Text: string); // Процедура записи в данных в буфер private { Private declarations } Name: string; // Имя файла Size: integer; // Размер файла Receive: boolean; // Режим клиента MS: TMemoryStream; // Буфер для файла

На событие создания формы, мы соединяемся с сервером и ждём передачи файла:

Procedure TForm1.FormCreate(Sender: TObject); begin ClientSocket1.Open; // Открываем сокет Receive:= false; // Режим клиента - приём команд end;

При завершении приложения, закрываем сокет:

Procedure TForm1.FormDestroy(Sender: TObject); begin ClientSocket1.Close; // Закрываем сокет end;

Так-же как и у сервера, сделаем чтоб клиент выдавал информацию о соединении:

Procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= "Соединение установлено"; end; procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= "Соединение не установлено"; end;

Теперь нам нужно вписать код в процедуру Writing. Эта процедура нужна для того, чтоб принятые данные записывать в файл. Код процедуры:

Procedure TForm1.Writing(Text: string); begin if MS.Size < Size then // Если принято байт меньше размера файла, то... MS.Write(Text, Length(Text)); // Записываем в буфер // Выводим прогресс закачки файла ProgressBar1.Position:= MS.Size*100 div Size; StatusBar1.SimpleText:= "Принято "+IntToStr(MS.Size)+" из "+IntToStr(Size); if MS.Size = Size then // Если файл принят, то... begin Receive:= false; // Переводим клиента в нормальный режим MS.Position:= 0; // Переводим каретку в начало буфера MS.SaveToFile(Name); // Сохраняем файл ClientSocket1.Socket.SendText("end"); // Посылаем команду "end", то есть файл принят MS.Free; // Убиваем буфер StatusBar1.SimpleText:= "Файл принят"; end; end;

Теперь на событие OnClientRead компонента TClientSocket, впишите следующий код:

Procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket); var Rtext: string; // Принятый текст begin Rtext:= Socket.ReceiveText; if Receive then // Если клиент в режиме приёма файла, то... Writing(RText) // Записываем данные в буфер else // Если клиент не в режиме приёма файла, то... begin if Copy(Rtext, 0, Pos("#", Rtext) -1) = "file" then // Если это файл, то... begin MS:= TMemoryStream.Create; // Создаём буфер для файла Delete(Rtext, 1, Pos("#", Rtext)); // Определяем имя файла Name:= Copy(Rtext, 0, Pos("#", Rtext) -1); // Определяем имя файла Delete(Rtext, 1, Pos("#", Rtext)); // Определяем размер файла Size:= StrToInt(Copy(Rtext, 0, Pos("#", Rtext) -1)); // Определяем размер файла Delete(Rtext, 1, Pos("#", Rtext)); // Удаляем последний разделитель Label1.Caption:= "Размер файла: "+IntToStr(Size)+" байт"; // Выводим размер файла Label2.Caption:= "Имя файла: "+Name; // Выводим имя файла Receive:= true; // Переводим сервер в режим приёма файла Writing(RText); // Записываем данные в буфер end; end; end;

Таким образом, если файл большой, и событие OnClientRead будет вызываться ни один раз, а несколько, то если клиент в режиме приёма файла, он будет записывать данные в буфер, если же нет, то клиент определит принятую команду, и если это файл, то перейдёт в режим приёма файла. Если вы чего-то не поняли, то прочитайте код программы, я там не зря всё раскоментировал:-)

Ну вот и всё...
Клиент и сервер - готовы! Сначала запустите сервер, а за тем клиента и попробуйте передать файлы, размером в несколько мегабайт:-) Я без проблем пересылал по сети файлы размером 10-12 Мб.

Удачи в программировании!

В данной статье будут рассмотрены базовые свойства и функции компонентов Delphi: TClientSocket и TServerSocket – использующихся для работы с сетью по протоколу TCP\IP.

Внимание! Если вы используете версию Delphi выше 6.0, то предварительно вам необходимо установить Sockets Components, во всех версиях Delphi это делается следующим образом:

  • Заходим в диалог Install Packages… : (Главное меню) Component -> Install Packages;
  • Щелкаем по кнопке Add… , после чего находим папку Bin вашего Delphi (н-р: C:\Program Files\Borland\Delphi 7\bin , либо C:\Program Files\Embarcadero\RAD Studio\7.0\Bin);
  • В найденной папке Bin уже ищем файлик dclsockets[тут циферки] .bpl , жмем ОК ;
  • Радуемся, потому что теперь на вкладке панели компонентов на вкладке Internet у нас появились два замечательных компонента TServerSocket и TClientSocket.

При разработке любых сетевых приложений обычно разработку всегда начинают с сервера (конечно если у вас есть команда, дизайнеры интерфейсов могут приступать к работе над клиентом). Для реализации сервера, удивительно, необходимо использовать TServerSocket.

Основные свойства:

  • Active – поле типа boolean, при установлении в true – сервер запускается, можно использовать, как присвоение конкретных значений, так и вызывая функции ServerSocket1.Open (… Active:=true;) или ServerSocket1.Close (… Active:=false).
  • Port – порт на котором будет прослушивать (принимать клиентов) сервер, любое не занятое другими серверами в системе значение в пределах диапазона integer .

Основные события:

  • OnListen – вызывается при установлении сервера в режим прослушивания, может испоьзоватся, когда нам нужно определить время реального старта сервера.
  • OnClientRead – вызывается в момент принятия данных от клиента.
  • OnClientError
  • OnClientConnect – вызывается во время присоединения нового клиента к серверу.
  • OnClientDisconnect – обратное событие событию, OnClientConnect

у каждой функции события есть атрибут Socket: TCustomWinSocket , в него передаеться указатель на объект сокета с которым мы в данный момент работаем, если нам нужно что-то ответить или что-то сделать с клиентом, который вызвал событие, нам необходимо использовать именно этот объект, во всех остальных случаях мы используем ServerSocket1.Socket , аналогичная ситуация и с клиентским компонентом.

Readonly свойства и функции:

  • – возвращает количество активных соединений.
  • ServerSocket1.Socket.Connections – массив объектов типа TCustomWinSocket, массив всех объектов связанных с клиентами, счет индексов начинается с 0, длинна массива равна ServerSocket1.Socket.ActiveConnections .
  • Функции и свойства, применимые к элементам массива ServerSocket1.Socket.Connections и передаваемому атрибуту Socket в функцию события сервера:
  • Socket.LocalHost
  • Socket.LocalAdress – возвращает IP сервера.
  • Socket.RemoteHost
  • Socket.RemoteAdress – возвращает IP клиента.
  • Socket.ReceiveText – возвращает принятое от клиента текстовое сообщение, после чего очищает буфер, можно использовать только 1 раз, за 1 прием.
  • Socket.SendText(Text) – отсылает клиенту текстовое сообщение Text типа string .

Для компонента TClientSocket все практически тоже самое, только наоборот + основное визуальное отличие сервера от клиента, сервер в системе может быть запущен 1 на 1 значение порта, в количестве клиентов вас ограничивает только оперативная память.

Основные свойства:

  • Active – поле типа boolean, при установлении в true – клиент пытается соединится с сервером, можно использовать, как присвоение конкретных значений, так и вызывая функции ClientSocket1.Open (… Active:=true;) или ClientSocket1.Close (… Active:=false).
  • Port – порт по которому клиент сможет присоединиться к серверу, любое значение в пределах диапазона integer .
  • Adress – IPv4 адрес сервера типа string по шаблону 255.255.255.255, с которым будет соединяться клиент.

Основные события:

  • OnRead – вызывается в момент принятия данных от севера.
  • OnError – вызывается при возникновении ошибки в передаче данных.
  • OnConnecting – вызывается во время присоединения клиента к серверу.
  • OnDisconnect – обратное событие событию, OnConnecting , вызывается во время отсоединения от сервера клиента.

Readonly свойства и функции:

  • ClientSocket1.Socket.SendText() string
  • Socket.LocalHost – возвращает имя клиента в сети.
  • Socket.LocalAdress – возвращает IP клиента.
  • Socket.RemoteHost – возвращает имя сервера в сети.
  • Socket.RemoteAdress – возвращает IP сервера.
  • Socket.ReceiveText – возвращает принятое от сервера текстовое сообщение, после чего очищает буфер, можно использовать только 1 раз, за 1 прием.
  • Socket.SendText(Text) – отсылает серверу текстовое сообщение Text типа string .

Предоставленной информации вполне достаточно, чтобы реализовать небольшой серверный чат, удовлетворяющий техническому заданию: internet_sockets.doc (Word Doc 97-2003, 26.5 Kb).

Эта статья написана в Воскресенье, Октябрь 10th, 2010 at 1:24 в разделе . Вы можете подписаться на обновления комментариев к статье - . Вы можете

Данная статья посвящена созданию приложений архитектуры клиент/сервер в Borland Delphi на основе сокетов ("sockets" - гнезда). В отличие от предыдущей статьи на тему сокетов, здесь мы разберем создание серверных приложений.
Следует сразу заметить, что для сосуществования отдельных приложений клиента и сервера не обязательно иметь несколько компьютеров. Достаточно иметь лишь один, на котором Вы одновременно запустите и сервер, и клиент. При этом нужно в качестве имени компьютера, к которому надо подключиться, использовать хост-имя localhost или IP-адрес - 127.0.0.1.
Итак, начнем с теории. Если Вы убежденный практик (и в глаза не можете видеть всяких алгоритмов), то Вам следует пропустить этот раздел.
Алгоритм работы сокетного сервера
Что же позволяет делать сокетный сервер?.. По какому принципу он работает?.. Сервер, основанный на сокетном протоколе, позволяет обслуживать сразу множество клиентов. Причем, ограничение на их количество Вы можете указать сами (или вообще убрать это ограничение, как это сделано по умолчанию). Для каждого подключенного клиента сервер открывает отдельный сокет, по которому Вы можете обмениваться данными с клиентом. Также отличным решением является создание для каждого подключения отдельного процесса (Thread).
Ниже следует примерная схема работы сокетного сервера в Дельфи-приложениях:

Разберем схему подробнее: ·Определение св-в Port и ServerType - чтобы к серверу могли нормально подключаться клиенты, нужно, чтобы порт, используемый сервером точно совпадал с портом, используемым клиентом (и наоборот). Свойство ServerType определяет тип подключения (подробнее см.ниже); ·Открытие сокета - открытие сокета и указанного порта. Здесь выполняется автоматическое начало ожидания подсоединения клиентов (Listen); ·Подключение клиента и обмен данными с ним - здесь подключается клиент и идет обмен данными с ним. Подробней об этом этапе можно узнать ниже в этой статье и в статье про сокеты (клиентская часть); ·Отключение клиента - Здесь клиент отключается и закрывается его сокетное соединение с сервером; ·Закрытие сервера и сокета - По команде администратора сервер завершает свою работу, закрывая все открытые сокетные каналы и прекращая ожидание подключений клиентов.
Следует заметить, что пункты 3-4 повторяются многократно, т.е. эти пункты выполняются для каждого нового подключения клиента.
Примечание: Документации по сокетам в Дельфи на данный момент очень мало, так что, если Вы хотите максимально глубоко изучить эту тему, то советую просмотреть литературу и электронную документацию по Unix/Linux-системам - там очень хорошо описана теория работы с сокетами. Кроме того, для этих ОС есть множество примеров сокетных приложений (правда, в основном на C/C++ и Perl).
Краткое описание компонента TServerSocket
Здесь мы познакомимся с основными свойствами, методами и событиями компонента
Свойства
Socket - класс TServerWinSocket, через который Вы имеете доступ к открытым сокетным каналам. Далее мы рассмотрим это свойство более подробно, т.к. оно, собственно и есть одно из главных. Тип: TServerWinSocket;
ServerType - тип сервера. Может принимать одно из двух значений: stNonBlocking - синхронная работа с клиентскими сокетами. При таком типе сервера Вы можете работать с клиентами через события OnClientRead и OnClientWrite. stThreadBlocking - асинхронный тип. Для каждого клиентского сокетного канала создается отдельный процесс (Thread). Тип: TServerType;
ThreadCacheSize - количество клиентских процессов (Thread), которые будут кэшироваться сервером. Здесь необходимо подбирать среднее значение в зависимости от загруженности Вашего сервера. Кэширование происходит для того, чтобы не создавать каждый раз отдельный процесс и не убивать закрытый сокет, а оставить их для дальнейшего использования. Тип: Integer;
Active - показатель того, активен в данных момент сервер, или нет. Т.е., фактически, значение True указывает на то, что сервер работает и готов к приему клиентов, а False - сервер выключен. Чтобы запустить сервер, нужно просто присвоить этому свойству значение True. Тип: Boolean;
Port - номер порта для установления соединений с клиентами. Порт у сервера и у клиентов должны быть одинаковыми. Рекомендуются значения от 1025 до 65535, т.к. от 1 до 1024 - могут быть заняты системой. Тип: Integer;
Service - строка, определяющая службу (ftp, http, pop, и т.д.), порт которой будет использован. Это своеобразный справочник соответствия номеров портов различным стандартным протоколам. Тип: string;
Методы
Open - Запускает сервер. По сути, эта команда идентична присвоению значения True свойству Active;
Close - Останавливает сервер. По сути, эта команда идентична присвоению значения False свойству Active.
События
OnClientConnect - возникает, когда клиент установил сокетное соединение и ждет ответа сервера (OnAccept);
OnClientDisconnect - возникает, когда клиент отсоединился от сокетного канала;
OnClientError - возникает, когда текущая операция завершилась неудачно, т.е. произошла ошибка;
OnClientRead - возникает, когда клиент передал берверу какие-либо данные. Доступ к этим данным можно получить через пеаедаваемый параметр Socket: TCustomWinSocket;
OnClientWrite - возникает, когда сервер может отправлять данные клиенту по сокету;
OnGetSocket - в обработчике этого события Вы можете отредактировать параметр ClientSocket;
OnGetThread - в обработчике этого события Вы можете определить уникальный процесс (Thread) для каждого отдельного клиентского канала, присвоив параметру SocketThread нужную подзадачу TServerClientThread;
OnThreadStart, OnThreadEnd - возникает, когда подзадача (процесс, Thread) запускается или останавливается, соответственно;
OnAccept - возникает, когда сервер принимает клиента или отказывает ему в соединении;
OnListen - возникает, когда сервер переходит в режим ожидания подсоединения клиентов.
TServerSocket.Socket (TServerWinSocket)
Итак, как же сервер может отсылать данные клиенту? А принимать данные? В основном, если Вы работаете через события OnClientRead и OnClientWrite, то общаться с клиентом можно через параметр ClientSocket (TCustomWinSocket). Про работу с этим классом можно прочитать в статье про клиентские сокеты, т.к. отправка/посылка данных через этот класс аналогична - методы (Send/Receive)(Text,Buffer,Stream). Также и при работе с TServerSocket.Socket. Однако, т.к. здесь мы рассматриваем сервер, то следует выделить некоторые полезные свойства и методы: ·ActiveConnections (Integer) - количество подключенных клиентов; ·ActiveThreads (Integеr) - количество работающих процессов; ·Connections (array) - массив, состоящий из отдельных классов TClientWinSocket для каждого подключенного клиента. Например, такая команда:·ServerSocket1.Socket.Connections.SendText("Hello!");·отсылает первому подключенному клиенту сообщение "Hello!". Команды для работы с элементами этого массива - также (Send/Receive)(Text,Buffer, Stream); ·IdleThreads (Integer) - количество свободных процессов. Такие процессы кэшируются сервером (см. ThreadCacheSize); ·LocalAddress, LocalHost, LocalPort - соответственно - локальный IP-адрес, хост-имя, порт; ·RemoteAddress, RemoteHost, RemotePort - соответственно - удаленный IP-адрес, хост-имя, порт; ·Методы Lock и UnLock - соответственно, блокировка и разблокировка сокета.
Практика и примеры
А теперь рассмотрим вышеприведенное на конкретном примере. Скачать уже готовые исходники можно, щелкнув здесь.
Итак, рассмотрим очень неплохой пример работы с TServerSocket (этот пример - наиболее наглядное пособие для изучения этого компонента). В приведенных ниже исходниках демонстрируется протоколирование всех важных событий сервера, плюс возможность принимать и отсылать текстовые сообщения:
Пример 1. Протоколирование и изучение работы сервера, посылка/прием сообщений через сокеты.

{... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1}

{Полный исходник смотри здесь}

procedure TForm1.Button1Click (Sender: TObject ) ;

begin

{Определяем порт и запускаем сервер}

ServerSocket1.Port := 1025 ;

{Метод Insert вставляет строку в массив в указанную позицию}

Memo2.Lines .Insert (0 ,"Server starting" ) ;

ServerSocket1.Open ;

end ;

procedure TForm1.Button2Click (Sender: TObject ) ;

begin

{Останавливаем сервер}

ServerSocket1.Active := False ;

Memo2.Lines .Insert (0 ,"Server stopped" ) ;

end ;

procedure TForm1.ServerSocket1Listen (Sender: TObject ;

Socket: TCustomWinSocket) ;

begin

{Здесь сервер "прослушивает" сокет на наличие клиентов}

Memo2.Lines .Insert (0 ,"Listening on port " +IntToStr (ServerSocket1.Port ) ) ;

end ;

procedure TForm1.ServerSocket1Accept (Sender: TObject ;

Socket: TCustomWinSocket) ;

begin

{Здесь сервер принимает клиента}

Memo2.Lines .Insert (0 ,"Client connection accepted" ) ;

end ;

procedure TForm1.ServerSocket1ClientConnect (Sender: TObject ;

Socket: TCustomWinSocket) ;

begin

{Здесь клиент подсоединяется}

Memo2.Lines .Insert (0 ,"Client connected" ) ;

end ;

procedure TForm1.ServerSocket1ClientDisconnect (Sender: TObject ;

Socket: TCustomWinSocket) ;

begin

{Здесь клиент отсоединяется}

Memo2.Lines .Insert (0 ,"Client disconnected" ) ;

end ;

procedure TForm1.ServerSocket1ClientError (Sender: TObject ;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer ) ;

begin

{Произошла ошибка - выводим ее код}

Memo2.Lines .Insert (0 ,"Client error. Code = " +IntToStr (ErrorCode) ) ;

end ;

procedure TForm1.ServerSocket1ClientRead (Sender: TObject ;

Socket: TCustomWinSocket) ;

begin

{От клиента получено сообщение - выводим его в Memo1}

Memo2.Lines .Insert (0 ,"Message received from client" ) ;

Memo1.Lines .Insert (0 ,"> " +Socket.ReceiveText ) ;

end ;

procedure TForm1.ServerSocket1ClientWrite (Sender: TObject ;

Socket: TCustomWinSocket) ;

begin

{Теперь можно слать данные в сокет}

Memo2.Lines .Insert (0 ,"Now can write to socket" ) ;

end ;

procedure TForm1.ServerSocket1GetSocket (Sender: TObject ; Socket: Integer ;

var ClientSocket: TServerClientWinSocket) ;

begin

Memo2.Lines .Insert (0 ,"Get socket" ) ;

end ;

procedure TForm1.ServerSocket1GetThread (Sender: TObject ;

ClientSocket: TServerClientWinSocket;

var SocketThread: TServerClientThread) ;

begin

Memo2.Lines .Insert (0 ,"Get Thread" ) ;

end ;

procedure TForm1.ServerSocket1ThreadEnd (Sender: TObject ;

begin

Memo2.Lines .Insert (0 ,"Thread end" ) ;

end ;

procedure TForm1.ServerSocket1ThreadStart (Sender: TObject ;

Thread: TServerClientThread) ;

begin

Memo2.Lines .Insert (0 ,"Thread start" ) ;

end ;

procedure TForm1.Button3Click (Sender: TObject ) ;

var i: Integer ;

begin

{Посылаем ВСЕМ клиентам сообщение из Edit1}

for i:= 0 to ServerSocket1.Socket .ActiveConnections -1 do begin

ServerSocket1.Socket .Connections [ i] .SendText (Edit1.Text ) ;

end ;

Memo1.Lines .Insert (0 ,"< " +Edit1.Text ) ;

end ;

Далее мы будем рассматривать уже не примеры, а приемы работы с TServerSocket.
Приемы работы с TServerSocket (и просто с сокетами)
Хранение уникальных данных для каждого клиента.
Наверняка, если Ваш сервер будет обслуживать множество клиентов, то Вам потребуется хранить какую-либо информацию для каждого клиента (имя, и др.), причем с привязкой этой информации к сокету данного клиента. В некоторых случаях делать все это вручную (привязка к handle сокета, массивы клиентов, и т.д.) не очень удобно. Поэтому для каждого сокета существует специальное свойство - Data. На самом деле, Data - это всего-навсего указатель. Поэтому, записывая данные клиента в это свойство будьте внимательны и следуйте правилам работы с указателями (выделение памяти, определение типа, и т.д.)!
Посылка файлов через сокет.
Здесь мы рассмотрим посылку файлов через сокет (по просьбе JINX-а) :-). Итак, как же послать файл по сокету? Очень просто! Достаточно лишь открыть этот файл как файловый поток (TFileStream) и отправить его через сокет (SendStream)! Рассмотрим это на примере:

{Посылка файла через сокет}

procedure SendFileBySocket(filename: string ) ;

var srcfile: TFileStream;

begin

{Открываем файл filename}

Srcfile:= TFileStream.Create (filename,fmOpenRead) ;

{Посылаем его первому подключенному клиенту}

ServerSocket1.Socket .Connections [ 0 ] .SendStream (srcfile) ;

{Закрываем файл}

Srcfile.Free ;

end ;

Нужно заметить, что метод SendStream используется не только сервером, но и клиентом (ClientSocket1.Socket.SendStream(srcfile))
Почему несколько блоков при передаче могут обьединяться в один
Это тоже по просьбе JINX-а:-). За это ему огромное спасибо! Итак, во-первых, надо заметить, что посылаемые через сокет данные могут не только объединяться в один блок, но и разъединяться по нескольким блокам. Дело в том, что сокет - обычный поток, но в отличие, скажем, от файлового (TFileStream), он передает данные медленнее (сами понимаете - сеть, ограниченный трафик, и т.д.). Именно поэтому две команды:
ServerSocket1.Socket.Connections.SendText("Hello, ");
ServerSocket1.Socket.Connections.SendText("world!");
совершенно идентичны одной команде:
ServerSocket1.Socket.Connections.SendText("Hello, world!");
И именно поэтому, если Вы отправите через сокет файл, скажем, в 100 Кб, то тому, кому Вы посылали этот блок, придет несколько блоков с размерами, которые зависят от трафика и загруженности линии. Причем, размеры не обязательно будут одинаковыми. Отсюда следует, что для того, чтобы принять файл или любые другие данные большого размера, Вам следует принимать блоки данных, а затем объединять их в одно целое (и сохранять, например, в файл). Отличным решением данной задачи является тот же файловый поток - TFileStream (либо поток в памяти - TMemoryStream). Принимать частички данных из сокета можно через событие OnRead (OnClientRead), используя универсальный метод ReceiveBuf. Определить размер полученного блока можно методом ReceiveLength. Также можно воспользоваться сокетным потоком (см. статью про TClientSocket). А вот и небольшой примерчик (приблизительный):

{Прием файла через сокет}

procedure TForm1.ClientSocket1Read (Sender: TObject ;

Socket: TCustomWinSocket) ;

var l: Integer ;

Buf: PChar ;

Src: TFileStream;

begin

{Записываем в l размер полученного блока}

L:= Socket.ReceiveLength ;

{Заказываем память для буфера}

GetMem (buf,l+1 ) ;

{Записываем в буфер полученный блок}

Socket.ReceiveBuf (buf,l) ;

{Открываем временный файл для записи}

Src:= TFileStream.Create ("myfile.tmp" ,fmOpenReadWrite) ;

{Ставим позицию в конец файла}

Src.Seek (0 ,soFromEnd) ;

{Записываем буфер в файл}

Src.WriteBuffer (buf,l) ;

{Закрываем файл}

Src.Free ;

{Освобождаем память}

FreeMem (buf) ;

end ;

Как следить за сокетом
Это вопрос сложный и требует долгого рассмотрения. Пока лишь замечу, что созданный Вашей программой сокет Вы можете промониторить всегда:-). Сокеты (как и большинство объектов в Windows) имеют свой дескриптор (handle), записанный в свойстве Handle. Так вот, узнав этот дескриптор Вы свободно сможете управлять любым сокетом (даже созданным чужой программой)! Однако, скорее всего, чтобы следить за чужим сокетом, Вам придется использовать исключительно функции WinAPI Sockets.
Эпилог
В этой статье отображены основные приемы работы с компонентом TServerSocket в Дельфи и несколько общих приемов для обмена данными по сокетам. Если у Вас есть вопросы - скидывайте их мне на E-mail: [email protected] , а еще лучше - пишите в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи смогли увидеть Ваш вопрос и попытаться на него ответить!
Карих Николай (Nitro). Московская область, г.Жуковский


Данная статья посвящена созданию приложений архитектуры клиент/сервер в Borland Delphi на основе сокетов ("sockets" - гнезда). В отличие от предыдущей статьи на тему сокетов, здесь мы разберем создание серверных приложений.

Следует сразу заметить, что для сосуществования отдельных приложений клиента и сервера не обязательно иметь несколько компьютеров. Достаточно иметь лишь один, на котором Вы одновременно запустите и сервер, и клиент. При этом нужно в качестве имени компьютера, к которому надо подключиться, использовать хост-имя localhost или IP-адрес - 127.0.0.1.

Итак, начнем с теории. Если Вы убежденный практик (и в глаза не можете видеть всяких алгоритмов), то Вам следует пропустить этот раздел.

Алгоритм работы сокетного сервера

Что же позволяет делать сокетный сервер?.. По какому принципу он работает?.. Сервер, основанный на сокетном протоколе, позволяет обслуживать сразу множество клиентов. Причем, ограничение на их количество Вы можете указать сами (или вообще убрать это ограничение, как это сделано по умолчанию). Для каждого подключенного клиента сервер открывает отдельный сокет, по которому Вы можете обмениваться данными с клиентом. Также отличным решением является создание для каждого подключения отдельного процесса (Thread).

Ниже следует примерная схема работы сокетного сервера в Дельфи-приложениях:

Разберем схему подробнее:

  1. Определение св-в Port и ServerType - чтобы к серверу могли нормально подключаться клиенты, нужно, чтобы порт, используемый сервером точно совпадал с портом, используемым клиентом (и наоборот). Свойство ServerType определяет тип подключения (подробнее см.ниже);
  2. Открытие сокета - открытие сокета и указанного порта. Здесь выполняется автоматическое начало ожидания подсоединения клиентов (Listen);
  3. Подключение клиента и обмен данными с ним - здесь подключается клиент и идет обмен данными с ним. Подробней об этом этапе можно узнать ниже в этой статье и в статье про сокеты (клиентская часть);
  4. Отключение клиента - Здесь клиент отключается и закрывается его сокетное соединение с сервером;
  5. Закрытие сервера и сокета - По команде администратора сервер завершает свою работу, закрывая все открытые сокетные каналы и прекращая ожидание подключений клиентов.
  6. Следует заметить, что пункты 3-4 повторяются многократно, т.е. эти пункты выполняются для каждого нового подключения клиента.

Примечание:

Документации по сокетам в Дельфи на данный момент очень мало, так что, если Вы хотите максимально глубоко изучить эту тему, то советую просмотреть литературу и электронную документацию по Unix/Linux-системам - там очень хорошо описана теория работы с сокетами. Кроме того, для этих ОС есть множество примеров сокетных приложений (правда, в основном на C/C++ и Perl).

Краткое описание компонента TServerSocket

Здесь мы познакомимся с основными свойствами, методами и событиями компонента TServerSocket.

Свойства Методы События:

Socket класс TServerWinSocket, через который Вы имеете доступ к открытым сокетным каналам. Далее мы рассмотрим это свойство более подробно, т.к. оно, собственно и есть одно из главных. Тип: TServerWinSocket; ServerType тип сервера. Может принимать одно из двух значений: stNonBlocking - синхронная работа с клиентскими сокетами. При таком типе сервера Вы можете работать с клиентами через события OnClientRead и OnClientWrite. stThreadBlocking - асинхронный тип. Для каждого клиентского сокетного канала создается отдельный процесс (Thread). Тип: TServerType; ThreadCacheSize количество клиентских процессов (Thread), которые будут кэшироваться сервером. Здесь необходимо подбирать среднее значение в зависимости от загруженности Вашего сервера. Кэширование происходит для того, чтобы не создавать каждый раз отдельный процесс и не убивать закрытый сокет, а оставить их для дальнейшего использования. Тип: Integer; Active показатель того, активен в данных момент сервер, или нет. Т.е., фактически, значение True указывает на то, что сервер работает и готов к приему клиентов, а False - сервер выключен. Чтобы запустить сервер, нужно просто присвоить этому свойству значение True. Тип: Boolean; Port номер порта для установления соединений с клиентами. Порт у сервера и у клиентов должны быть одинаковыми. Рекомендуются значения от 1025 до 65535, т.к. от 1 до 1024 - могут быть заняты системой. Тип: Integer; Service строка, определяющая службу (ftp, http, pop, и т.д.), порт которой будет использован. Это своеобразный справочник соответствия номеров портов различным стандартным протоколам. Тип: string; Open Запускает сервер. По сути, эта команда идентична присвоению значения True свойству Active; Close Останавливает сервер. По сути, эта команда идентична присвоению значения False свойству Active. OnClientConnect возникает, когда клиент установил сокетное соединение и ждет ответа сервера (OnAccept); OnClientDisconnect возникает, когда клиент отсоединился от сокетного канала; OnClientError возникает, когда текущая операция завершилась неудачно, т.е. произошла ошибка; OnClientRead возникает, когда клиент передал берверу какие-либо данные. Доступ к этим данным можно получить через пеаедаваемый параметр Socket: TCustomWinSocket; OnClientWrite возникает, когда сервер может отправлять данные клиенту по сокету; OnGetSocket в обработчике этого события Вы можете отредактировать параметр ClientSocket; OnGetThread в обработчике этого события Вы можете определить уникальный процесс (Thread) для каждого отдельного клиентского канала, присвоив параметру SocketThread нужную подзадачу TServerClientThread; OnThreadStart, OnThreadEnd возникает, когда подзадача (процесс, Thread) запускается или останавливается, соответственно; OnAccept возникает, когда сервер принимает клиента или отказывает ему в соединении; OnListen возникает, когда сервер переходит в режим ожидания подсоединения клиентов.

TServerSocket.Socket (TServerWinSocket)

Итак, как же сервер может отсылать данные клиенту? А принимать данные? В основном, если Вы работаете через события OnClientRead и OnClientWrite, то общаться с клиентом можно через параметр ClientSocket (TCustomWinSocket). Про работу с этим классом можно прочитать в статье про клиентские сокеты, т.к. отправка/посылка данных через этот класс аналогична - методы (Send/Receive)(Text,Buffer,Stream). Также и при работе с TServerSocket.Socket. Однако, т.к. здесь мы рассматриваем сервер, то следует выделить некоторые полезные свойства и методы:

ActiveConnections (Integer) количество подключенных клиентов; ActiveThreads (Integеr) количество работающих процессов; Connections (array) - массив, состоящий из отдельных классов TClientWinSocket для каждого подключенного клиента. Например, такая команда:


ServerSocket1.Socket.Connections.SendText("Hello!");

отсылает первому подключенному клиенту сообщение "Hello!". Команды для работы с элементами этого массива - также (Send/Receive)(Text,Buffer, Stream); IdleThreads (Integer) количество свободных процессов. Такие процессы кэшируются сервером (см. ThreadCacheSize); LocalAddress, LocalHost, LocalPort соответственно - локальный IP-адрес, хост-имя, порт; RemoteAddress, RemoteHost, RemotePort соответственно - удаленный IP-адрес, хост-имя, порт; Методы Lock и UnLock соответственно, блокировка и разблокировка сокета.

Практика и примеры

А теперь рассмотрим вышеприведенное на конкретном примере. Скачать уже готовые исходники можно, щелкнув здесь.

Итак, рассмотрим очень неплохой пример работы с TServerSocket (этот пример - наиболее наглядное пособие для изучения этого компонента). В приведенных ниже исходниках демонстрируется протоколирование всех важных событий сервера, плюс возможность принимать и отсылать текстовые сообщения:

Пример 1. Протоколирование и изучение работы сервера, посылка/прием сообщений через сокеты.


{... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1} procedure TForm1.Button1Click(Sender: TObject); begin {Определяем порт и запускаем сервер} ServerSocket1.Port:= 1025; {Метод Insert вставляет строку в массив в указанную позицию} Memo2.Lines.Insert(0, "Server starting"); ServerSocket1.Open; end ; procedure TForm1.Button2Click(Sender: TObject); begin {Останавливаем сервер} ServerSocket1.Active:= False; Memo2.Lines.Insert(0, "Server stopped"); end ; procedure TForm1.ServerSocket1Listen(Sender: TObject; Socket: TCustomWinSocket); begin {Здесь сервер "прослушивает" сокет на наличие клиентов} Memo2.Lines.Insert(0, "Listening on port " + IntToStr(ServerSocket1.Port)); end ; procedure TForm1.ServerSocket1Accept(Sender: TObject; Socket: TCustomWinSocket); begin {Здесь сервер принимает клиента} Memo2.Lines.Insert(0, "Client connection accepted"); end ; procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin {Здесь клиент подсоединяется} Memo2.Lines.Insert(0, "Client connected"); end ; procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin {Здесь клиент отсоединяется} Memo2.Lines.Insert(0, "Client disconnected"); end ; procedure TForm1.ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin {Произошла ошибка - выводим ее код} Memo2.Lines.Insert(0, "Client error. Code = " + IntToStr(ErrorCode)); end ; procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); begin {От клиента получено сообщение - выводим его в Memo1} Memo2.Lines.Insert(0, "Message received from client"); Memo1.Lines.Insert(0, "> " + Socket.ReceiveText); end ; procedure TForm1.ServerSocket1ClientWrite(Sender: TObject; Socket: TCustomWinSocket); begin {Теперь можно слать данные в сокет} Memo2.Lines.Insert(0, "Now can write to socket"); end ; procedure TForm1.ServerSocket1GetSocket(Sender: TObject; Socket: Integer; var ClientSocket: TServerClientWinSocket); begin Memo2.Lines.Insert(0, "Get socket"); end ; procedure TForm1.ServerSocket1GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread); begin Memo2.Lines.Insert(0, "Get Thread"); end ; procedure TForm1.ServerSocket1ThreadEnd(Sender: TObject; Thread: TServerClientThread); begin Memo2.Lines.Insert(0, "Thread end"); end ; procedure TForm1.ServerSocket1ThreadStart(Sender: TObject; Thread: TServerClientThread); begin Memo2.Lines.Insert(0, "Thread start"); end ; procedure TForm1.Button3Click(Sender: TObject); var i: Integer; begin {Посылаем ВСЕМ клиентам сообщение из Edit1} for i:= 0 to ServerSocket1.Socket.ActiveConnections - 1 do ServerSocket1.Socket.Connections[i].SendText(Edit1.Text); Memo1.Lines.Insert(0, "end;

Приемы работы с TServerSocket (и просто с сокетами)

Хранение уникальных данных для каждого клиента.

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

Посылка файлов через сокет

Здесь мы рассмотрим посылку файлов через сокет (по просьбе JINX-а) :-). Итак, как же послать файл по сокету? Очень просто! Достаточно лишь открыть этот файл как файловый поток (TFileStream) и отправить его через сокет (SendStream)! Рассмотрим это на примере:


Нужно заметить, что метод SendStream используется не только сервером, но и клиентом (ClientSocket1.Socket.SendStream(srcfile))

Почему несколько блоков при передаче могут обьединяться в один

Это тоже по просьбе JINX-а:-). За это ему огромное спасибо! Итак, во-первых, надо заметить, что посылаемые через сокет данные могут не только объединяться в один блок, но и разъединяться по нескольким блокам. Дело в том, что сокет - обычный поток, но в отличие, скажем, от файлового (TFileStream), он передает данные медленнее (сами понимаете - сеть, ограниченный трафик, и т.д.). Именно поэтому две команды:


ServerSocket1.Socket.Connections.SendText("Hello, "); ServerSocket1.Socket.Connections.SendText("world!");

совершенно идентичны одной команде:


ServerSocket1.Socket.Connections.SendText("Hello, world!");

И именно поэтому, если Вы отправите через сокет файл, скажем, в 100 Кб, то тому, кому Вы посылали этот блок, придет несколько блоков с размерами, которые зависят от трафика и загруженности линии. Причем, размеры не обязательно будут одинаковыми. Отсюда следует, что для того, чтобы принять файл или любые другие данные большого размера, Вам следует принимать блоки данных, а затем объединять их в одно целое (и сохранять, например, в файл). Отличным решением данной задачи является тот же файловый поток - TFileStream (либо поток в памяти - TMemoryStream). Принимать частички данных из сокета можно через событие OnRead (OnClientRead), используя универсальный метод ReceiveBuf. Определить размер полученного блока можно методом ReceiveLength. Также можно воспользоваться сокетным потоком (см. статью про TClientSocket). А вот и небольшой примерчик (приблизительный):


Как следить за сокетом

Это вопрос сложный и требует долгого рассмотрения. Пока лишь замечу, что созданный Вашей программой сокет Вы можете промониторить всегда:-). Сокеты (как и большинство объектов в Windows) имеют свой дескриптор (handle), записанный в свойстве Handle. Так вот, узнав этот дескриптор Вы свободно сможете управлять любым сокетом (даже созданным чужой программой)! Однако, скорее всего, чтобы следить за чужим сокетом, Вам придется использовать исключительно функции WinAPI Sockets.

Эпилог

В этой статье отображены основные приемы работы с компонентом TServerSocket в Дельфи и несколько общих приемов для обмена данными по сокетам. Если у Вас есть вопросы - скидывайте их мне на E-mail: [email protected], а еще лучше - пишите в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи смогли увидеть Ваш вопрос и попытаться на него ответить!

Ноябрь 16th, 2013 admin

Сокеты (от socket (англ.) - разъём, гнездо) - это программный интерфейс, обеспечивающий процессы обмена информацией между процессами.

В этой статье рассказывается о том, как разрабатываются приложения на основе сокетов на Borland Delphi. Стоит обратить внимание на то, что сокеты – база для протоколов. Иными словами, с их помощью можно самостоятельно создать (имитировать) POP, FTP, HTTP или любой другой протокол – даже новый, свой собственный.

Принцип работы с сокетными протоколами

Одни из основных достоинств сокетного обмена информацией в сети можно назвать его гибкость. Главный принцип работы с сокетами состоит в отправке последовательности символов другому компьютеру, будь то сообщение или целый файл. Причём без «ручного» контроля правильности передачи (как во время работы с COM-портами).

Примерный алгоритм работы с сокетами Delphi

Определение свойств Port и Host . Для успешного соединения свойствам Port и Host компонента TClientSocket необходимо присвоить некоторые значения.

В свойстве Port нужно указать номер порта для подключения (1 – 65535, но лучше брать из диапозона 1001 – 65535, потому что номера до 1000 могут оказаться заняты системными службами).

Host — хост-имя или IP-адрес компьютера, с которым требуется соединиться. Например, rus.delphi.com или 192.128.0.0.

Открытие сокета . Будем рассматривать сокет как очередь символов, передающихся с одного компьютера на другой. Открыть сокет можно, вызвав метод Open (компонент TClientSocket ) или присвоив значение True свойству Active . Тут нелишним будет поставить обработчик исключения на случай неудавшегося соединения.

Отправка/прием данных . Это как раз то, ради чего всё затеяно. От сервера зависит и то, через какой протокол производится обмена данными.

Закрытие сокета . По завершению обмена данными нужно закрыть сокет, вызвав метод Close компонента TClientSocket или присвоив значение False свойству Active .

Компонент TClientSocket

Столкнувшись с необходимостью работы с компонентом TClientSocket, разумным будет познакомиться с ним поближе.

Свойства:

Active (тип: Boolean) – показатель того, открыт или закрыт сокет. Открыт – значение True, закрыт – значение False. Доступно для записи.

Host (тип: string) – хост-имя компьютера, с которым нужно соединиться.

Address (тип: string) – тут IP-адрес компьютера, с которым нужно соединиться. В отличие от Host, здесь может быть указан только IP. Разница состоит в том, что если в Host указано буквенное имя компьютера, то IP запросится у DNS.

Port (тип: Integer (Word)) – номер порта компьютера, с которым нужно соединиться (1-65535).

Service (тип: string) – определяет службу, с портом которой произойдёт соединение (pop, ftp и т.д.). Можно сказать, что это некий справочник для сопоставления номера порта с каким-либо стандартным протоколом.

ClientType — содержит тип передачи данных :

ctBlocking — синхронная передача (OnRead и OnWrite не работают). Синхронный тип подключения подходит для поточного обмена данными;

ctNonBlocking — асинхронная передача (отправка/приём данных может производиться при помощи событий OnRead и OnWrite).

Методы:

Open — открывает сокет (присвоение свойству Active значения True).

Close — закрывает сокет (присвоение свойству Active значения False).

События:

OnConnect – возникает при установке подключения. В обработчике уже можно приступать к авторизации или отправке/приему данных.

OnConnecting – также возникает при подключении. Отличается от OnConnect тем, что подключение еще не установлено. Чаще всего используется, например, чтобы обновить статус.

OnDisconnect – событие возникает при закрытии сокета вашей программой, удаленным компьютером или из-за сбоя. OnError – событие возникает при ошибке. Во время открытия сокета это событие не поможет выловить ошибку. Во избежание появления сообщения от Windows об ошибке, лучше позаботиться о внутренней обработке исключений путём помещения операторов открытия в блок «try..except».

OnLookup – событие возникает при попытке получить IP-адрес от DNS.

OnRead – событие возникает при отправке вам каких-либо данных удалённым компьютером. При вызове OnRead возможна обработка принятых данных.

OnWrite – событие возникает, когда вашей программе разрешено писать данные в сокет.

Пример:


{В самом начале необходимо создать форму TForm1 и экземпляр Form1, создать на форме кнопку TButton, при нажатии на которую будет вызываться процедура Button1Click — обработчик события OnClick, и два поля TEdit, в которые предварительно нужно будет ввести хост-имя в один и порт в другой.
Обязательно нужно поместить компонент TClientSocket на форму!}

Procedure Button1Click(Sender: TObject); begin {В Host и Port пишем введённые в форме значения} ClientSocket1.Host:= Edit1.Text; ClientSocket1.Port:= StrToInt(Edit2.Text); {Открываем сокет и пытаемся подключиться} ClientSocket1.Open; end; procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); begin {Если подключение прошло успешно, сокет закрываем, подключение обрываем} ClientSocket1.Close; end;

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

Например, некоторые методы TClientSocket.Socket (TCustomWinSocket, TClientWinSocket) :

SendBuf(var Buf; Count: Integer) – отправка буфера через сокет. Это может быть любой тип: простой Integer, структура (record), или что-то ещё. Указать буфер нужно параметром Buf. Во втором параметре должен быть указан размер (в байтах) передаваемых данных (Count );

SendText(const S: string) – отправка текстовой строки;

SendStream(AStream: TStream) – отправка содержимого потока любого типа: файлового, из ОЗУ и т.д. Этот поток должен быть открыт.

В заключение

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

Clientsocket onlookup delphi delphi сокеты пример работа с сокетами делфи delphi 2010 рабоиа с сокетами delphi все о работе с сокетами

Сокеты в делфи работа с сокетами делфи работа сокетов в делфи delphi все о работе с сокетами clientsocket onlookup delphi

 
Статьи по теме:
Календарь: как использовать онлайн-сервис для планирования личного времени
Данное средство Outlook поможет вам спланировать наилучшим образом свои дела (встречи, собрания, события) в течение дня, недели или месяца. С помощью календаря Outlook можно планировать следующее. Встреча . Для этого требуется выделить время в деловом рас
HDD vs SSD в играх: сравнение времени загрузки и производительности
Привет всем Я постараюсь простыми словами рассказать вам что лучше использовать для игр: жесткий диск или SSD. Но это все мои личные мысли я не претендую на истину, ну это так… Я немного разбираюсь в SSD и в HDD, вообще люблю железо.. Все мы знаем что SS
WiFi SiStr – бесплатная утилита для отображения силы сигнала Wi-Fi сетей Программа для поиска точек доступа wifi
В статье рассматривается бесплатное программное обеспечение (ПО) под управлением Microsoft Windows, позволяющее производить предварительный анализ радиопокрытия территории на предмет наличия стороннего оборудования, работающего в Wi-Fi диапазоне 2.4/5 ГГц
Обзор Samsung Galaxy А5 (2016): удачное перерождение Какой экран на самсунг галакси а5
Samsung обновил Galaxy A5 в 2016 году и проделал фантастическую работу над этим Android-смартфоном среднего класса. В прошлом году Samsung приложил немало усилий для модернизации своей топовой серии S, начав с тогдашнего флагмана Samsung Galaxy S6. В 2016