Простой способ отправки файлов при помощи tclientsocket & tserversocket


Diplom Consult.ru

SendBuf(var Buf; Count: Integer) — Посылка буфера через сокет. Буфером может являться любой тип, будь то структура (record), либо простой Integer. Буфер указывается параметром Buf, вторым параметром Вы должны указать размер пересылаемых данных в байтах (Count);

SendText(const S: string)— Посылка текстовой строки через сокет.

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

ReceiveBuf (var Buf; Count: Integer)— Прием данных в буферBuf, размеромCount. Важно знать, что при попытке чтения большего количества данных чем доступно на данный момент – возникнет ошибка чтения с сокета. Количество данных (в байтах), доступных для чтения с сокета, можно узнать в свойствеReceiveLength.

Для чтения простых данных с сокета можно воспользоваться свойством ReceiveText.

Работа с серверными сокетами (tServerSocket)

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

Основные этапы работы с tServerSocket

1) Определение свойств Port и ServerType — чтобы к серверу могли нормально подключаться клиенты, нужно, чтобы порт, используемый сервером точно совпадал с портом, используемым клиентом (и наоборот). СвойствоServerTypeопределяет тип подключения (подробнее см.ниже);

2) Открытие сокета— открытие сокета и указанного порта. Здесь выполняется автоматическое начало ожидания подсоединения клиентов (Listen);

3) Подключение клиента и обмен данными с ним— здесь подключается клиент и идет обмен данными с ним.

4) Отключение клиента— Здесь клиент отключается и закрывается его сокетное соединение с сервером.

5) Закрытие сервера и сокета— По команде администратора сервер завершает свою работу, закрывая все открытые сокетные каналы и прекращая ожидание подключений клиентов.

Следует заметить, что пункты 3-4 повторяются многократно, т.е. эти пункты выполняются для каждого нового подключения клиента.

Основные свойства компонента TServerSocket

Класс TServerWinSocket, через который Вы имеете доступ к открытым сокетным каналам. Далее мы рассмотрим это свойство более подробно, т.к. оно, собственно и есть одно из главных.

Тип сервера. Может принимать одно из двух значений: stNonBlocking— синхронная работа с клиентскими сокетами. При таком типе сервера Вы можете работать с клиентами через событияOnClientReadиOnClientWrite.stThreadBlocking— асинхронный тип. Для каждого клиентского сокетного канала создается отдельный процесс (Thread).

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

Показатель того, активен в данных момент сервер, или нет. Т.е., фактически, значение True указывает на то, что сервер работает и готов к приему клиентов, а False— сервер выключен. Чтобы запустить сервер, нужно просто присвоить этому свойству значениеTrue.

Номер порта для установления соединений с клиентами. Порт у сервера и у клиентов должны быть одинаковыми. Рекомендуются значения от 1025 до 65535, т.к. от 1 до 1024 — могут быть заняты системой.

Основные методы компонента TServerSocket

Запускает сервер. По сути, эта команда идентична присвоению значения TrueсвойствуActive

Останавливает сервер. По сути, эта команда идентична присвоению значения FalseсвойствуActive

Основные события компонента TServerSocket

Возникает, когда клиент установил сокетное соединение и ждет ответа сервера (OnAccept)

Возникает, когда клиент отсоединился от сокетного канала

Возникает, когда клиент передал серверу какие-либо данные. Доступ к этим данным можно получить через передаваемый параметр Socket: TCustomWinSocket

Возникает, когда сервер может отправлять данные клиенту по сокету

В обработчике этого события Вы можете отредактировать параметр ClientSocket

В обработчике этого события Вы можете определить уникальный процесс (Thread) для каждого отдельного клиентского канала, присвоив параметру SocketThread нужную подзадачу TServerClientThread

Возникает, когда подзадача (процесс, Thread) запускается

Возникает, когда подзадача (процесс, Thread) останавливается

Возникает, когда сервер принимает клиента или отказывает ему в соединении

Возникает, когда сервер переходит в режим ожидания подсоединения клиентов

Простой способ отправки файлов при помощи tclientsocket & tserversocket

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

Для начала давайте найдем необходимые компоненты TServerSocket и TClientSocket. Чаще всего они не входят в стандартный пакет установки Delphi, но их можно установить дополнительно. Для этого запустим Delphi, зайдем в «Component/Install Packages», затем нажмем кнопку «Add». В открывшемся диалоговом окне нужно найти файл «dclsocketsXX.bpl» (он лежит в папке bin, которая находится в папке с Delphi), где XX — это числовой номер версии вашего Delphi. Находим файл, нажимаем «Открыть», а затем в окне «Install Packages» нажимаем «OK».

Теперь, во вкладке «Internet» появились два компонента — TServerSocket и TClientSocket, работу с которыми мы и будем рассматривать в этом уроке.

Не сложно догадаться по названиям самих компонентов, что компонент TClientSocket выполняет роль клиента в сети, который подсоединяется к серверу с компонентом TServerSocket.

[note]В рамках данной статьи, в качестве сервера мы будем рассматривать серверную программу, которая выполняет роль сервера, а клиентами мы будем называть клиентские программы, которые соединяются с сервером.[/note]

Сервер служит обычно для сетевого взаимодействия клиентов. Таким образом клиент может отсылать какую-либо информацию на сервер, а сервер будет эту информацию отсылать остальным клиентам.

Давайте рассмотрим работу сетевого чата. Предположим, что к серверу чата подключено несколько клиентов. Один из клиентов отправляет новое сообщение на сервер. Сервер принимает сообщение и отправляет его обратно остальным клиентам. Остальные клиенты принимают сообщение с сервера и таким образом и осуществляется передача сообщений чата.

[note]Такие сетевые приложения, в работе которых участвуют клиент и сервер, называются клиент-серверными приложениями.[/note]

Теперь попробуем разобраться, как же все таки работать с этими компонентами. Попробуем реализовать аналогичный клиент-серверный чат.

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

Создадим новое приложение в Delphi, поместим на него компонент TServerSocket и в его параметрах укажем следующие значения:

Active = false
Name = srv
Port = 22500
ServerType = stNonBlocking

Параметр Active отвечает за состояние сервера, активен он или не активен на данный момент.

В событие OnCreate формы не забудем добавить srv.active:=true, чтобы сервер запустился.


В параметре Port необходимо указать порт, по которому будут передаваться пакеты с информацией от клиента к серверу и обратно.

Также поместим на форму компонент Memo1 (дадим ему название log), который нам понадобиться для того, чтобы отслеживать работу чата.

Теперь у srv создадим событие onClientConnect, в котором мы сможем фиксировать подключения клиентов к серверу. В коде самого события напишем:

[cc lang=»delphi»]procedure TForm1.srvClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
log.Lines.Add(‘Подключился клиент с IP адресом ‘+Socket.RemoteAddress);
end;[/cc]

Таким образом мы можем узнать IP адрес подключившегося к серверу клиента.

В переменной Socket в событии хранится вся необходимая информация о клиента, который произвел подключение к серверу.

Обработчик события onClientRead служит для получения и обработки пришедшей от клиента информации. Рассмотрим пример:

[cc lang=»delphi»]procedure TForm1.srvClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
str:string;
i:integer;
begin
str:=Socket.ReceiveText;
log.Lines.Add(str);
for i:= 0 to srv.Socket.ActiveConnections -1 do
srv.Socket.Connections[i].SendText(str);
end;[/cc]

Переменной str мы присваиваем значение принятого текстового сообщения от клиента и добавляем принятое сообщение в лог. После этого мы отсылаем сообщение всем клиентам. Кол-во подключенных клиентов можно узнать в srv.Socket.ActiveConnections.

Предположим, если мы хотим отправить сообщение конкретному клиенту, то это можно сделать так:

[cc lang=»delphi»]srv.Socket.Connections[a].SendText(‘test message’); [/cc]

В данном случае в качестве переменной a выступает числовой идентификатор в srv.Socket.Connections. Эти идентификаторы находятся в диапазоне от 0 до srv.Socket.ActiveConnections -1. Но как же, например, отправить сообщение клиенту с определенным IP адресом, который нам извествен заранее? Делается это так:

[cc lang=»delphi»]for i:= 0 to srv.Socket.ActiveConnections -1 do
if srv.Socket.Connections[i].RemoteAddress= ‘123.123.123.123’ then begin
srv.Socket.Connections[i].SendText(‘test message’);
break;
end;[/cc]

Мы перебираем все соединения на сервере. Если IP адрес клиента совпадает с «123.123.123.123» (может быть и любой другой), то отправляем сообщение этому клиенту и завершаем цикл.

Ну и наконец, рассмотрим еще одно событие у TServerSocket — onClientDisconnect, которое обрабатывает отключение клиента от сервера.

[cc lang=»delphi»]procedure TForm1.srvClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
log.Lines.Add(‘Клиент ‘+socket.RemoteAddress+’ отключился от сервера.’);
end; [/cc]

Теперь перейдем к клиенту. Создадим новое приложение Delphi и поместим в него компонент TClientSocket и дадим этому компоненту имя «client». Присвоим параметрам компонента client значения:

Active = false
Port = 25500
ClientType = ctNonBlocking
Address = 127.0.0.1

В параметре address укажите IP адрес компьютера, на котором запущено серверное приложение. Если провести подключение по IP адресу «127.0.0.1», то компьютер подключится грубо говоря сам к себе и будет работать с серверной программой, которая запущена там же, где и запущена клиентская. Такой способ очень удобен для тестирования сетевых приложений.

[warning]Значение Port у клиента необходимо присвоить такое же как и у сервера! [/warning]

Также добавим компонент TMemo с именем log, чтобы отображать пришедшие от сервера сообщения.

Рассмотрим параметр OnCreate формы, где производиться подключение к серверу.

[cc lang=»delphi»]procedure TForm1.FormCreate(Sender: TObject);
begin
<Пытаемся установить соединение>
ClientSocket1.Open;
end;[/cc]

Илон Маск рекомендует:  PShortString - Тип Delphi

Теперь разместим на форме клиента кнопку Button1 и однострочное текстовое поле Edit1. Они нам понадобятся для отправки сообщений на сервер. В событии OnClick у компонента Button1 напишите:

Таким образом на сервер будет отправляться сообщение, введенное в Edit1.

После того как сообщение было отослано на сервер, сервер отсылает сообщение всем клиентам, поэтому нужно принять сообщение от сервера. Для этого нам понадобиться событие OnRead:

[cc lang=»delphi»]procedure ClientRead(Sender: TObject; Socket: TCustomWinSocket);
begin
<Если пришло сообщение — добавляем его в log>
Log.Lines.Add(Socket.ReceiveText);
end; [/cc]

Осталось только написать событие отключения от сервера. Для этого можем создать еще одну кнопку и в ее событии OnClick указать

[cc lang=»delphi»] client.close; [/cc]

Запустите клиент и сервер. Попробуйте отослать сообщение на сервер, сервер в ответ должен вернуть его вам. Если возникает ошибка «Asynchronous socket error 10061», то это скорее всего связано с недоступностью сервера. Проверьте соответствие портов, IP адресов и работоспособность сетевого соединения.

На этом наш урок можно считать завершенным. Смело задавайте вопросы в комментариях и подписывайтесь на рассылку новых уроков прямо на ваш e-mail!

Основные этапы работы с TServerSocket

Работа с сокетами в Delphi

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

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

Важно различать два типа сокетов: клиентские сокеты, и серверные сокеты.

Для работы с «клиентским» типом сокетов в Delphi существует компонент TClientSocket, с «серверными» сокетами можно работать при помощи компонента TServerSocket.

Установка компонентов

Зачастую компоненты TServerSocket и TClientSocket не входят в стандартный пакет установки Delphi, но их можно установить дополнительно.

Зайдите на вкладку компонентов «Internet», и проверьте присутствуют ли там компоненты TServerSocket и TClientSocket, если нет, то установите их. Зайдите в меню «Component/Install Packages», затем нажмите кнопку «Add». В открывшемся диалоговом окне нужно найти файл «dclsocketsXX.bpl» (он лежит в папке bin, которая находится в папке с Delphi), где XX — это числовой номер версии вашего Delphi. Найдите файл, нажмите «Открыть», а затем в окне «Install Packages» нажмите «OK». Теперь, во вкладке «Internet» появились два компонента — TServerSocket и TClientSocket.

Работа с клиентскими сокетами (TClientSocket)

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

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

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

Отправка/прием данных.

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

Основные свойства компонента TClientSocket
Active Показатель того, открыт или закрыт сокет. Открыт – значение True, закрыт – значение False. Доступно для записи.
Host Хост-имя, с которым нужно соединиться
Address IP-адрес компьютера, с которым нужно соединиться. В отличие от Host, здесь может быть указан только IP. Разница состоит в том, что если в Host указано буквенное имя компьютера, то IP запросится у DNS
Port Номер порта компьютера, с которым нужно соединиться (1-65535)
ClientType Содержит тип передачи данных: ctBlocking — синхронная передача (OnRead и OnWrite не работают). Синхронный тип подключения подходит для поточного обмена данными; ctNonBlocking — асинхронная передача (отправка/приём данных может производиться при помощи событий OnRead и OnWrite)
Основные методы компонента TClientSocket
Open Открывает сокет (присвоение свойству Active значения True)
Close Закрывает сокет (присвоение свойству Active значения False)
Основные события компонента TClientSocket
OnConnect Возникает при установке подключения. В обработчике уже можно приступать к авторизации или отправке/приему данных
OnConnecting Также возникает при подключении. Отличается от OnConnect тем, что подключение еще не установлено. Чаще всего используется, например, чтобы обновить статус
OnDisconnect Событие возникает при закрытии сокета вашей программой, удаленным компьютером или из-за сбоя
OnError Событие возникает при ошибке. Во время открытия сокета это событие не поможет выловить ошибку. Во избежание появления сообщения от Windows об ошибке, лучше позаботиться о внутренней обработке исключений путём помещения операторов открытия в блок «try..except»
OnLookup Событие возникает при попытке получить IP-адрес от DNS
OnRead Событие возникает при отправке вам каких-либо данных удалённым компьютером. При вызове OnRead возможна обработка принятых данных
OnWrite Событие возникает, когда вашей программе разрешено писать данные в сокет

Для приема или отправки данных необходимо использовать методы объекта TClientSocket.Socket:

SendBuf(var Buf; Count: Integer) — Посылка буфера через сокет. Буфером может являться любой тип, будь то структура (record), либо простой Integer. Буфер указывается параметром Buf, вторым параметром Вы должны указать размер пересылаемых данных в байтах (Count);


SendText(const S: string) — Посылка текстовой строки через сокет.

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

ReceiveBuf (var Buf; Count: Integer) — Прием данных в буфер Buf, размером Count. Важно знать, что при попытке чтения большего количества данных чем доступно на данный момент – возникнет ошибка чтения с сокета. Количество данных (в байтах), доступных для чтения с сокета, можно узнать в свойстве ReceiveLength.

Для чтения простых данных с сокета можно воспользоваться свойством ReceiveText.

Работа с серверными сокетами (TServerSocket)

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

Основные этапы работы с TServerSocket

1) Определение свойств Port и ServerType— чтобы к серверу могли нормально подключаться клиенты, нужно, чтобы порт, используемый сервером точно совпадал с портом, используемым клиентом (и наоборот). Свойство ServerType определяет тип подключения (подробнее см.ниже);

2) Открытие сокета — открытие сокета и указанного порта. Здесь выполняется автоматическое начало ожидания подсоединения клиентов (Listen);

3) Подключение клиента и обмен данными с ним — здесь подключается клиент и идет обмен данными с ним.

4) Отключение клиента — Здесь клиент отключается и закрывается его сокетное соединение с сервером.

5) Закрытие сервера и сокета — По команде администратора сервер завершает свою работу, закрывая все открытые сокетные каналы и прекращая ожидание подключений клиентов.

Следует заметить, что пункты 3-4 повторяются многократно, т.е. эти пункты выполняются для каждого нового подключения клиента.

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

Пример работы сокетами

См. демонстрационные проекты в папках /lab1/tcp-ip-client/ и /lab1/tcp-ip-server/

| следующая лекция ==>
Социально-педагогические технологии работы с семьей, воспитывающей ребенка с ограниченными возможностями | Скопируйте этот текст три раза

Дата добавления: 2020-09-03 ; просмотров: 765 | Нарушение авторских прав

Простой способ отправки файлов при помощи tclientsocket & tserversocket

На вопрос «Как я могу отправлять файлы через TClientSocket & TServerSocket?» даём ответ:

Категория : Разные | Добавил : Барон (14.12.2011) Просмотров : 610 | Теги : TServerSocket, TClientSocket | Рейтинг : 0.0 /

[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Как установить TClientSocket и TServerSocket для мультиплатформенности?

В C ++ Builder, как я могу установить TClientSocket а также TServerSocket для использования в мультиплатформенном приложении? В настоящее время я использую их в проекте только для VCL.

Решение

Как я могу установить TClientSocket и TServerSocket?

Это описано в документации Embarcadero:

Компоненты сокета не установлены по умолчанию. Чтобы использовать компоненты сокета, вы должны установить dclsockets пакет.

Чтобы установить компоненты сокета:
1. Выберите Компонент> Установить пакеты.
2. В диалоговом окне «Установка пакетов» нажмите «Добавить».
3. В диалоговом окне «Добавить пакет дизайна» перейдите к C:\Program Files (x86)\Embarcadero\Studio\17.0\bin ,
4. Выберите dclsockets230.bpl и нажмите Открыть.
5. Нажмите OK, чтобы закрыть диалоговое окно Install Packages.
6. Компоненты сокетов (TClientSocket и TServerSocket) перечислены в категории «Интернет» панели инструментов.

Примечание. Эти шаги являются одноразовыми инструкциями по установке. Компоненты сокетов должны быть доступны для всех будущих проектов.

Что, как говорится…

Мне нужно использовать его для мультиплатформенного приложения, теперь у меня были эти компоненты только в проекте VCL.

TClientSocket а также TServerSocket НЕ являются мультиплатформенными компонентами. Они тесно связаны с библиотекой Microsoft WinSock под Windows и работают только в проектах VCL, а не в проектах FMX. Для работы с мультиплатформенными сокетами вы можете использовать Инди вместо этого, который предварительно установлен в RADStudio, или вы можете установить актуальная версия вручную.

Простой способ отправки файлов при помощи tclientsocket & tserversocket

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, ExtCtrls, StdCtrls;

type
TForm1 = class (TForm)
Image1: TImage;
Image2: TImage;
ClientSocket1: TClientSocket;
ServerSocket1: TServerSocket;
Button1: TButton;
procedure Image1Click(Sender: TObject );
procedure FormCreate(Sender: TObject );
procedure ClientSocket1Connect(Sender: TObject ;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientRead(Sender: TObject ;
Socket: TCustomWinSocket);
procedure ClientSocket1Read(Sender: TObject ; Socket: TCustomWinSocket);
private
< Private declarations >
Reciving: boolean ;
DataSize: integer ;
Data: TMemoryStream;
public
< Public declarations >
end ;

var
Form1: TForm1;

procedure TForm1.Image1Click(Sender: TObject );
begin
// Это процедура для открытия сокета на ПРИЁМ (RECEIVING).
// Button1.Click is this procedure as well.
ClientSocket1.Active:= true ;
end ;

procedure TForm1.FormCreate(Sender: TObject );
begin
// Открытие ОТПРАВЛЯЮЩЕГО (SENDING) сокета.
ServerSocket1.Active:= true ;
end ;

procedure TForm1.ClientSocket1Connect(Sender: TObject ;
Socket: TCustomWinSocket);
begin
// Посылаем команду для начала передачи файла.
Socket.SendText( ‘send’ );
end ;

procedure TForm1.ClientSocket1Read(Sender: TObject ;
Socket: TCustomWinSocket);
var
s, sl: string ;
begin
s:= Socket.ReceiveText;
// Если мы не в режиме приёма:
if not Reciving then
begin
// Теперь нам необходимо получить длину потока данных.
SetLength (sl, StrLen ( PChar (s))+ 1 ); // +1 for the null terminator
StrLCopy (@sl[ 1 ], PChar (s), Length (sl)- 1 );
DataSize:= StrToInt (sl);
Data:= TMemoryStream.Create;
// Удаляем информацию о размере из данных.
Delete (s, 1 , Length (sl));
Reciving:= true ;
end ;
// Сохраняем данные в файл, до тех пор, пока не получим все данные.
try
Data.Write(s[ 1 ], length (s));
if Data.Size = DataSize then
begin
Data.Position:= 0 ;
Image2.Picture.Bitmap.LoadFromStream(Data);
Data.Free;
Reciving:= false ;
Socket.Close;
end ;
except
Data.Free;
end ;
end ;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject ;
Socket: TCustomWinSocket);
var
ms: TMemoryStream;
begin
// Клиент получает команду на передачу файла.
if Socket.ReceiveText = ‘send’ then
begin
ms:= TMemoryStream.Create;
try
// Получаем данные на передачу.
Image1.Picture.Bitmap.SaveToStream(ms);
ms.Position:= 0 ;
// Добавляем длину данных, чтобы клиент знал, сколько данных будет передано
// Добавляем #0 , чтобы можно было определить, где заканчивается информация о размере.
Socket.SendText( IntToStr (ms.Size) + #0 );
// Посылаем его.
Socket.SendStream(ms);
except
// Итак, осталось освободить поток, если что-то не так.
ms.Free;
end ;
end ;
end ;

delphi
unit Unit1;

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;

type
TForm1 = class (TForm)
ClientSocket1: TClientSocket;
ServerSocket1: TServerSocket;
btnTestSockets: TButton;
procedure ClientSocket1Read(Sender: TObject ; Socket: TCustomWinSocket);
procedure FormCreate(Sender: TObject );
procedure FormDestroy(Sender: TObject );
procedure ClientSocket1Disconnect(Sender: TObject ;
Socket: TCustomWinSocket);
procedure ClientSocket1Connect(Sender: TObject ;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientConnect(Sender: TObject ;
Socket: TCustomWinSocket);
procedure btnTestSocketsClick(Sender: TObject );
private
FStream: TFileStream;
< Private-Deklarationen >
public
< Public-Deklarationen >
end ;

var
Form1: TForm1;

procedure TForm1.ClientSocket1Read(Sender: TObject ;
Socket: TCustomWinSocket);
var
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 ;

procedure TForm1.FormCreate(Sender: TObject );
begin
FStream := nil ;
end ;

procedure TForm1.FormDestroy(Sender: TObject );
begin
if Assigned (FStream) then
begin
FStream.Free;
FStream := nil ;
end ;
end ;


procedure TForm1.ClientSocket1Disconnect(Sender: TObject ;
Socket: TCustomWinSocket);
begin
if Assigned (FStream) then
begin
FStream.Free;
FStream := nil ;
end ;
end ;

procedure TForm1.ClientSocket1Connect(Sender: TObject ;
Socket: TCustomWinSocket);
begin
FStream := TFileStream.Create( ‘c:\temp\test.stream.html’ , fmCreate or fmShareDenyWrite);
end ;

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject ;
Socket: TCustomWinSocket);
begin
Socket.SendStream(TFileStream.Create( ‘c:\temp\test.html’ , fmOpenRead or fmShareDenyWrite));
end ;

procedure TForm1.btnTestSocketsClick(Sender: TObject );
begin
ServerSocket1.Active := True ;
ClientSocket1.Active := True ;
end ;

Простой способ отправки файлов при помощи tclientsocket & tserversocket

259 просмотра

1 ответ

30 Репутация автора

Есть ли решение для работы с TServerSocket в ScktComp.dcu от delphi, которое позволяет мне отправлять с синхронизацией один файловый поток или многофайловый поток в Multi TClientSocket . У меня есть этот код здесь:

Что мне в точности нужно, так это заменить функцию цикла хорошим выражением, которое позволяет мне передавать или отправлять любой поток файлов, любой текст или любую команду в multi TClientSocket, но с методом Syncronize и означать, что каждый клиент, связанный с моим сервером, должен получать то, что мой TClientServer отправляет или передает одновременно, не теряя других клиентов и не ожидая, пока один за другим отправит другим . Наконец, если это возможно для этого компонента, я буду признателен за любые предложения от любого, кто отвечает и хорошо ценится.

Ответы (1)

4 плюса

361855 Репутация автора

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

Есть два способа справиться с этим, и оба требуют использования буфера исходящих данных для каждого клиента. Мне нравится использовать TServerSocket.OnClientConnect событие для создания TMemoryStream буфера и присвоения его TCustomWinSocket.Data свойству, чтобы его можно было легко отслеживать. Используйте все, что имеет смысл для вашего кода.

переведите сервер в режим блокировки потоков, чтобы каждый клиент работал в своем собственном выделенном рабочем потоке. Оберните буфер данных критическим разделом. Если вы хотите записать данные на конкретный клиент, заблокируйте буфер клиента, добавьте данные в конец буфера и разблокируйте его. Пусть рабочий поток клиента постоянно проверяет буфер на наличие новых данных и отправляет его через сокет клиента. Удалите отправленные байты из передней части буфера, как вы идете.

Шпаргалка: TClientSocket & TServerSocket

В C++Builder 6 для передачи какой-либо информации по сети удобнее всего использовать компоненты закладки Internet: TClientSocket и TServerSocket.

Чтобы лучше разобраться в работе этих компонентов я предлагаю написать простенький сетевой чат, на примере которого можно будет легко увидеть компоненты в действии.

Для начала создадим новый проект(File->New->Application), поместим на форму компоненты:

TClientSocket и TServerSocket, чтобы наша программа могла быть и клиентом и сервером (не одновременно конечно ;) ).

Далее разместим компонент TMemo (закладка Standart) — в нем как вы догадались будет отображаться текст чата.

Следующим на форму нужно кинуть компонент TEdit (Standart) — в него мы будем писать текcт, который нужно отправить собеседнику.

Ну и конечно тяжело обойтись без кнопки отправить — кидаем на форму TButton. Кроме того что уже есть на форме, нам еще понадобится три кнопки и два эдита (TEdit) (их назначение описывается по ходу обращения к ним).

ClientSocket1 и ServerSocket1

Теперь изменяем свойства:

Button1->Caption на «Отправить»

Button2->Caption на «Создать»

Button3->Caption на «Соединиться» и

Button4->Caption на «Отключить».

Убираем текст во всех Эдитах. Свойство Memo1->ReadOnly = true,

ClientSocket1->Host — нужно написать IP-адрес сервера к которому вы будете присоеденяться

(IP-адресс устанавливается в настройках соединения Windows), если прописать 127.0.0.1, то вы будете конектиться к себе на компьютер (так удобно делать, когда проверяешь на работоспособность свою программу. Запустив ее дважды, одна клиент с 127.0.0.1, а другая сервер !) если же вы коннектитесь к другу, то заранее договоритесь какой будет Ай-Пи-адрес (143.0.0.5 — например). Но для того чтобы Ай-Пи -адресс можно было легко сменить, мы и положили на форму один из Эдитов, его текст при коннекте и будет отвечать свойству ClientSocket1->Host и ClientSocket1->Address.

В свойстве ClientSocket1->Port и ServertSocket1->Port — должны стоять одинаковые значения, чтобы Сервер и Клиент прослушивали и работали на один порт. Число можно выбрать любое (1024 например).

Кнопку «Отключиться» изначально нужно сделать недоступной(Enabled = false)так как вначале отсоеденяться нам нет от кого.

Дальше опишем обработчики событий для кнопок «Создать», «Соединиться», «Отключить».

Кнопка «Создать» — активизирует сервер. Он начинает прослушивать порт на коннект со стороны клиента.

void __fastcall TForm1::Button2Click(TObject *Sender)

// Делаем недоступную «Соединиться» (так как мы уже сервер)

// Делаем доступную «Отключиться» (понятно зачем)

Так наша программа стала сервером!

Давайте опишем клиента!(Кнопка «Соединиться»)

В Edit3->Text впишите 127.0.0.1 — предполагается что тестироваться будет на одном компьютере (что б других не заморачивать:)

void __fastcall TForm1::Button3Click(TObject *Sender)

Edit3->Text = ClientSocket1->Host // ПрисваиваемКлиентуАй-ПиизЭдита

// Делаем недоступную «Создать» (так как мы коннектимся)

// Делаем доступную «Отключиться» (понятно зачем)

Вот Вы и написали тот минимум который надо для освоения компонентов!

Но кто хочет останавливаться? А чат доделать! Правильно пишем дальше:


Дальше будем описывать свойства компонентов Клиента и Сервера OnConnect (когда присоединился).

void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,

Это когда вы сервер и к Вам присоединились, на Мемо появится надпись!

Для клиента почти так само:

void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,

Понятно, да? Отлично, дальше остается только рассказать Вам зачем Edit2 на форме и описать кнопку «Отправить».

Итак, Эдит2 нам нужен для Вашего ника! Ведь какой чат без ника!

Теперь самое главное — описание кнопки «Отправить:

ShowMessage(«Введите текст который надо отправить»);

//Это была обработка исключительных ситуаций, типа пустых строк ввода ;

if (ServerSocket1->Active == true) <

Теперь разберемся с этой кучей кода:

//добавляем свое сообщение себе в Мемо

if (ServerSocket1->Active == true)Socket->

Если мы сервер, то посылаем нашу строку первому в списке клиенту ( чат розщитан на двоих ), иначе:

Посылаем строку серверу!

Независимо от того кто мы (клиент-сервер)

Также надо описать прием информации и занесение ее в Мемо1. Делается это обработчиком события OnRead у TClientSocket и TserverSocket:

void __fastcall TForm1::ClientSocket1Read(TObject *Sender,

void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,

Вот вроди бы и все. С TClientSocket и TserverSocket разобрались, а кого заинтересовала тема чата, заходите в раздел «Мои программы» И качайте доделанную мной, с большим колличеством настроек программу вместе с исходниками.

Работа с сокетами в Qt

Введение

Как-то несколько лет назад, на одном из форумов, я нашел такую замечательную фразу — «Каждый уважающий себя программист в жизни должен написать свой чат-клиент». Тогда мои знания не позволяли сделать это. Я просто улыбнулся и прошел мимо этой фразы. Но вот совсем недавно я столкнулся именно с данной проблемой — нужно было написать свой чат. Ну а так как последнее время мой интерес был направлен на изучение и разработку Qt-приложений, на чем будет сделан он, решилось само собой.

Работа с сетью в Qt осуществляется через QtNetwork. А для того чтобы проект начал поддерживать его, в .pro файле нужно дописать QT += network. Qt поддерживает несколько типов сокетного соединения. Основные это: QUdpSocket и QTcpSocket. QUdpSocket — это дейтаграммный сокет, для осуществления обмена пакетами данных. С помощью этого сокета данные отправляются без проверки дошли ли данные или нет. QTcpSocket же устанавливает связь точка-точка и предоставляет дополнительные механизмы, направленные против искажения и потери данных.

Оба класса наследованы от класса QAbstractSocket. Также есть класс QSslSocket, но мне он на тот момент был не нужен, поэтому затрагивать его не буду.

Когда начал проектировать архитектуру приложения, стал вопрос: «А собственно как будут взаимодействовать пользователи чата между собой?». Просто сам чат должен был поддерживать как общее окно чата, так и приват-сообщения с возможностью передачи файлов. Если с передачей файлов было все ясно — тут только TCP, так как должен быть контроль и проверка пришли ли пакеты, то вот с основным чатом были трудности. Ведь в чате нет четко выраженного сервера. Да и если взаимодействие их сделать через TCP, то для каждого пользователя нужно будет выделить порт, что немного накладно. Ну а раз не TCP, значит UDP! Он полностью подходит для этого. Прослушивая определенный порт, мы получаем сообщения от пользователя, который отправил их на тот же порт всем. И если какое-то сообщение чата потеряется, это будет не так страшно.

QUdpSocket

UdpChat(QString nick, int port) <
nickname = nick;
socket = new QUdpSocket( this );
_port = port;
socket->bind(QHostAddress::Any, port);
// тут еще какой то код конструктора //
connect(socket, SIGNAL(readyRead()), SLOT(read()));
>

* This source code was highlighted with Source Code Highlighter .

void send(QString str, qint8 type) <
QByteArray data;
QDataStream out (&data, QIODevice::WriteOnly);
out out out out .device()->seek(qint64(0));
out sizeof (qint64));
socket->writeDatagram(data, QHostAddress::Broadcast, _port);
>

void read() <
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
QHostAddress *address = new QHostAddress();
socket->readDatagram(datagram.data(), datagram.size(), address);

qint64 size = -1;
if ( in .device()->size() > sizeof (qint64)) <
in >> size;
> else return ;
if ( in .device()->size() — sizeof (qint64) return ;

qint8 type = 0;
in >> type;

if (type == USUAL_MESSAGE) <
QString str;
in >> str;
// код по перенаправке сообщения в классы выше //
> else if (type == PERSON_ONLINE) <
// Добавление пользователя с считанным QHostAddress //
> else if (type == WHO_IS_ONLINE) <
sending(nickname, qint8(PERSON_ONLINE));
>
>

* This source code was highlighted with Source Code Highlighter .

Все прозрачно и ясно. Осталось прикрутить интерфейс, соединить все сигналы и основное окно чата готово.

QTcpSocket

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

С отправкой сообщения нет никаких сложностей. А вот для отправки файла сделаем классический трюк. Так как весь файл засунуть в поток не получится, то будет считывать данные из файла и порционно писать в поток, а затем отправлять их.

void sendFile(QString fileName) <
if (sendFile != NULL) <
return ;
>
sendFile = new QFile(fileName);
if (sendFile->open(QFile::ReadOnly)) <
QByteArray data;
QDataStream out (&data, QIODevice::WriteOnly);
// подготовка данных для записи //
clientSocket->write(data);
clientSocket->waitForBytesWritten();
connect(clientSocket, SIGNAL(bytesWritten(qint64)), this , SLOT(sendPartOfFile()));
sendPartOfFile();
> else <
emit this ->errorSendFile(QString( «File not can open for read» ));
return ;
>
>

void sendPartOfFile() <
char block[SIZE_BLOCK_FOR_SEND_FILE];
if (!sendFile->atEnd()) <
qint64 in = sendFile->read(block, sizeof (block));
qint64 send = clientSocket->write(block, in );
> else <
sendFile->close();
sendFile = NULL;
disconnect(clientSocket, SIGNAL(bytesWritten(qint64)), this , SLOT(sendPartOfFile()));
emit endSendFile();
>
>

* This source code was highlighted with Source Code Highlighter .

void receiveFile(QString fileName) <
QString savePath = «Downloads/» ;
QDir dir;
dir.mkpath(savePath);
receiveFile = new QFile(savePath + fileName);
sizeReceivedData = 0;
receiveFile();
>

void receiveFile() <
QDataStream in (clientSocket);
if (!bufferForUnreadData.isEmpty()) <
receiveFile->write(bufferForUnreadData);
sizeReceivedData += bufferForUnreadData.size();
bufferForUnreadData.clear();
>
char block[SIZE_BLOCK_FOR_SEND_FILE];
while (! in .atEnd()) <
qint64 toFile = in .readRawData(block, sizeof (block));
sizeReceivedData += toFile;
receiveFile->write(block, toFile);
>
if (sizeReceivedData == sizeReceiveFile) <
receiveFile->close();
receiveFile = NULL;
sizeReceiveFile = 0;
sizeReceivedData = 0;
>
>

* This source code was highlighted with Source Code Highlighter .

Это суть работы приват-сообщения. Конечно здесь не хватает части сигналов, коннектов и специфичного кода. Например send- и recieve-файл — это только общий вид. Многое пропущено. Но если все добавить, прикрутить интерфейс, то можно получить вполне рабочий, написанный вами чат-клиент.

Целью же статьи было показать на примере, что работать с сокетами просто и легко. Надеюсь, что кому то данная статья поможет в будущем. Удачи.

Шпаргалка: TClientSocket & TServerSocket

В C++Builder 6 для передачи какой-либо информации по сети удобнее всего использовать компоненты закладки Internet: TClientSocket и TServerSocket.

Чтобы лучше разобраться в работе этих компонентов я предлагаю написать простенький сетевой чат, на примере которого можно будет легко увидеть компоненты в действии.

Для начала создадим новый проект(File->New->Application), поместим на форму компоненты:


TClientSocket и TServerSocket, чтобы наша программа могла быть и клиентом и сервером (не одновременно конечно ;) ).

Далее разместим компонент TMemo (закладка Standart) — в нем как вы догадались будет отображаться текст чата.

Следующим на форму нужно кинуть компонент TEdit (Standart) — в него мы будем писать текcт, который нужно отправить собеседнику.

Ну и конечно тяжело обойтись без кнопки отправить — кидаем на форму TButton. Кроме того что уже есть на форме, нам еще понадобится три кнопки и два эдита (TEdit) (их назначение описывается по ходу обращения к ним).

ClientSocket1 и ServerSocket1

Теперь изменяем свойства:

Button1->Caption на «Отправить»

Button2->Caption на «Создать»

Button3->Caption на «Соединиться» и

Button4->Caption на «Отключить».

Убираем текст во всех Эдитах. Свойство Memo1->ReadOnly = true,

ClientSocket1->Host — нужно написать IP-адрес сервера к которому вы будете присоеденяться

(IP-адресс устанавливается в настройках соединения Windows), если прописать 127.0.0.1, то вы будете конектиться к себе на компьютер (так удобно делать, когда проверяешь на работоспособность свою программу. Запустив ее дважды, одна клиент с 127.0.0.1, а другая сервер !) если же вы коннектитесь к другу, то заранее договоритесь какой будет Ай-Пи-адрес (143.0.0.5 — например). Но для того чтобы Ай-Пи -адресс можно было легко сменить, мы и положили на форму один из Эдитов, его текст при коннекте и будет отвечать свойству ClientSocket1->Host и ClientSocket1->Address.

В свойстве ClientSocket1->Port и ServertSocket1->Port — должны стоять одинаковые значения, чтобы Сервер и Клиент прослушивали и работали на один порт. Число можно выбрать любое (1024 например).

Кнопку «Отключиться» изначально нужно сделать недоступной(Enabled = false)так как вначале отсоеденяться нам нет от кого.

Дальше опишем обработчики событий для кнопок «Создать», «Соединиться», «Отключить».

Кнопка «Создать» — активизирует сервер. Он начинает прослушивать порт на коннект со стороны клиента.

void __fastcall TForm1::Button2Click(TObject *Sender)

// Делаем недоступную «Соединиться» (так как мы уже сервер)

// Делаем доступную «Отключиться» (понятно зачем)

Так наша программа стала сервером!

Давайте опишем клиента!(Кнопка «Соединиться»)

В Edit3->Text впишите 127.0.0.1 — предполагается что тестироваться будет на одном компьютере (что б других не заморачивать:)

void __fastcall TForm1::Button3Click(TObject *Sender)

Edit3->Text = ClientSocket1->Host // ПрисваиваемКлиентуАй-ПиизЭдита

// Делаем недоступную «Создать» (так как мы коннектимся)

// Делаем доступную «Отключиться» (понятно зачем)

Вот Вы и написали тот минимум который надо для освоения компонентов!

Но кто хочет останавливаться? А чат доделать! Правильно пишем дальше:

Дальше будем описывать свойства компонентов Клиента и Сервера OnConnect (когда присоединился).

void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,

Это когда вы сервер и к Вам присоединились, на Мемо появится надпись!

Для клиента почти так само:

void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,

Понятно, да? Отлично, дальше остается только рассказать Вам зачем Edit2 на форме и описать кнопку «Отправить».

Итак, Эдит2 нам нужен для Вашего ника! Ведь какой чат без ника!

Теперь самое главное — описание кнопки «Отправить:

ShowMessage(«Введите текст который надо отправить»);

//Это была обработка исключительных ситуаций, типа пустых строк ввода ;

if (ServerSocket1->Active == true) <

Теперь разберемся с этой кучей кода:

//добавляем свое сообщение себе в Мемо

if (ServerSocket1->Active == true)Socket->

Если мы сервер, то посылаем нашу строку первому в списке клиенту ( чат розщитан на двоих ), иначе:

Посылаем строку серверу!

Независимо от того кто мы (клиент-сервер)

Также надо описать прием информации и занесение ее в Мемо1. Делается это обработчиком события OnRead у TClientSocket и TserverSocket:

void __fastcall TForm1::ClientSocket1Read(TObject *Sender,

void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,

Вот вроди бы и все. С TClientSocket и TserverSocket разобрались, а кого заинтересовала тема чата, заходите в раздел «Мои программы» И качайте доделанную мной, с большим колличеством настроек программу вместе с исходниками.

Илон Маск рекомендует:  Собираем серьезный игровой компьютер за 35000 рублей
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL