Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Работа с базами данных 3 страница




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

Далее приводится краткое описание компонента TServerSocket. На рис. 23 и 24 приводятся свойства и события компонента, соответственно, которые отображаются в окне Инспектора объектов. Табл. 19 содержит описание указанных свойств и событий.

Свойство Socket компонента TServerSocket. Как же сервер может отсылать данные клиенту или принимать данные? Если вы работаете через события OnClientRead и OnClientWrite, то общаться с клиентом можно через свойство Socket (TCustomWinSocket). Отправка/посылка данных через свойство Socket класса TServerSocket аналогична работе клиента(методы SendText(), SendBuf(), SendStream(), ReceiveText()). Однако, следует выделить некоторые полезные свойства и методы, характерные для для сервера: ActiveConnections (Integer) – количество подключенных клиентов; ActiveThreads (Integer) – количество работающих процессов; Connections (array) – массив, состоящий из отдельных классов TClientWinSocket для каждого подключенного клиента. Например, такая команда

 

 

 
 

Рис 23. Свойства компонента TServerSocket

 

 

 
 

Рис. 24. События компонента TServerSocket

 

ServerSocket1->Socket->Connections[i]->SendText(“Hello!”);

 

отсылает i-тому подключенному клиенту сообщение “Hello!”); IdleThreads (Integer) – количество свободных процессов (такие процессы кэшируются сервером, см. свойство ThreadCacheSize); LocalAddress, LocalHost, LocalPort – соответственно, локальный IP-адрес, хост-имя, порт; RemoteAddress, RemoteHost, RemotePort – соответственно, удаленный IP-адрес, хост-имя, порт; методы Lock и UnLock – соответственно, блокировка и разблокировка сокета.

 

Таблица 19

Свойства События
Socket – класс TServerWinSocket, через который вы имеете доступ к открытым сокетным каналам. ServerType – тип сервера. ThreadCacheSize – количество клиентских процессов (Thread), которые будут кэшироваться сервером. Кэширование происходит для того, чтобы не создавать каждый раз отдельный процесс и не уничтожать закрытый сокет, а оставить их для дальнейшего использования. Тип: int. Active –Значение True указывает на то, что сервер работает и готов к приему клиентов, а False – сервер выключен. Port – номер порта для установления соединений. Порт у сервера и у клиентов должны быть одинаковыми. Рекомендуются значения от 1025 до 65535. Service – строка, определяющая службу (ftp, http, pop и т.д.), порт которой будет использован. Тип:String. OnClientConnect – возникает, когда клиент установил сокетное соединение и ждет ответа сервера. OnClientDisconnect – возникает, когда клиент отсоединился. OnClientError – возникает, когда операция завершилась неудачно. OnClientRead – возникает, когда клиент передал серверу данные. OnClientWrite – возникает, когда сервер может отправлять данные клиенту по сокету. OnGetSocket – в обработчике этого события можно отредактировать параметр ClientSocket. OnGetThread – в обработчике события можно определить уникальный процесс (Thread) для каждого клиента канала, присвоив параметру SocketThread нужную подзадачу TServerClientThread. OnThreadStart, OnThreadEnd – возникает, когда процесс Thread запускается или останавливается. OnAccept – возникает, когда сервер принимает клиента или отказывает ему в соединении. OnListen – возникает, когда сервер переходит в режим ожидания подсоединения клиентов.

 

Пример. Создадим приложение-сервер. На форму нужно поместить кнопки Button1 и Button2, поле Edit1 и компоненты Memo1 и Memo2. При создании формы вызывается обработчик события OnCreate (FormCreate), в котором активизируется сервер. Свойство компонента TServerSocket->Active устанавливается в true, что означает, что сокетное соединение открыто и доступно для коммуникации с клиентами. В компоненте Edit1 указано значение прослушиваемого порта. Когда ServerSocket1 должен записать информацию в ClientSocket1, возникает событие OnClientWrite и вызывается функция ServerSocketClientWrite(). На рис. 25 приведена форма приложения в процессе проектирования.

 

 

Рис. 25. Форма приложения-сервера

 

Ниже приводится листинг приложения.

 

void __fastcall TForm1::FormCreate(TObject *Sender)

{

TServerSocket *ServerSocket = Form1->ServerSocket; // указатель на //сервер сокет

ServerSocket->Close(); // закрытие соединения(если слушали порт //Ранее)

ServerSocket->Port = Form1->Edit1->Text.ToInt(); // получение номера //порта

ServerSocket->Active = true; //прослушивание данного порта

}

//открытие сервера по нажатию кнопки

void __fastcall TForm1::Button2Click(TObject *Sender)

{

ServerSocket->Close(); // закрытие соединения

ServerSocket->Port=Form1->Edit1->Text.ToInt(); //получение порта

ServerSocket->Active = true; //прослушивание данного порта

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocketClientWrite(TObject *Sender,

TCustomWinSocket *Socket) //запись сообщения

{

Socket->SendText(Memo1->Text);// отправка сообщения

}

void __fastcall TForm1::Button1Click(TObject *Sender)

{

Memo1->Clear();

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocketClientRead(TObject *Sender,

TCustomWinSocket *Socket)

{

Memo2->Text = Socket->ReceiveText();

}

//отправка сообщения i-тому клиенту

void __fastcall TForm1::Button3Click(TObject *Sender)

{

int n=ServerSocket->Socket->ActiveConnections;

for(int i=0;i< n;i++)

ServerSocket->Socket->Connections[i]->SendText(

Memo1->Text+IntToStr(i));

}

 

Ниже рассматриваются некоторые приемы работы с компонентом TServerSocket.

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

Посылка файлов через сокет. Рассмотрим посылку файлов через сокет. Достаточно открыть этот файл как файловый поток (TFileStream) и отправить его через сокет (SendStream). Поясним это на примере:

ServerSocket1->Socket->Connections[i]->SendStream(srcfile);

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

Передача блоков информации. Посылаемые через сокет данные могут не только объединяться в один блок, но и разъединяться по нескольким блокам. Дело в том, что через сокет передается обычный поток, но в отличие от файлового потока (TFileStream) он передает данные медленнее (сеть, ограниченный трафик и т.д.). Именно поэтому две команды:

 

ServerSocket1->Socket->Connections[0]->SendText(“Hello,”);

ServerSocket1->Socket->Connections[0]->SendText(“world!”);

 

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

ServerSocket1->Socket->Connections[0]->SendText(“Hello, world!”);

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

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

 

//-- Клиент -------------------------------------------------------------------

void __fastcall TForm1::ClientSocketRead(TObject *Sender,

TCustomWinSocket *Socket)

{

Edit1->Text = Socket->ReceiveText();}

void __fastcall TForm1::Button1Click(TObject *Sender)

{ ClientSocket->Close();

if((Edit1->Text.Length() > 0)&&(Edit2->Text.Length() > 0)) {

ClientSocket->Host = Edit2->Text;

ClientSocket->Port = Edit1->Text.ToInt();

ClientSocket->Open();

}

}

//-- Сервер-------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender){

ServerSocket->Close(); // закрытие соединения

ServerSocket->Active = true; } //активизация сокета

//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender){

ServerSocket->Close(); }

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender){

ServerSocket->Socket->Connections[0]->SendText(Edit1->Text);

}

 

Потоки. Для создания распределенных приложений, работающих с не­сколькими клиентами, можно воспользоваться сокетным потоком. Потоки позволяют синхронизировать работу нескольких клиентов. Приведем пример создания многопотокового сервера и клиентской программы. По каждому запросу клиента сервер создаёт поток и определённое время ожидает ответа клиента. Потоки создаваемые сервером, это потомки класса TserverClientThread. Поэтому мы будем объявлять собственный потоковый класс, на­следуя его от TServerClientThread. Ниже приводится код программы с комментариями.

 

//Unit1.h- классы для сервера

#ifndef Unit1H

#define Unit1H

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ScktComp.hpp>

//---------------------------------------------------------------------------

class TForm1: public TForm

{

__published: // IDE-managed Components

TServerSocket *ServerSocket1;

TMemo *Memo1;

TButton *Button1;

TButton *Button2;

TMemo *Memo2;

TLabel *Label1;

TLabel *Label2;

void __fastcall ServerSocket1GetThread(TObject *Sender,

TServerClientWinSocket *ClientSocket, TServerClientThread *&SocketThread);

void __fastcall Button1Click(TObject *Sender);

void __fastcall Button2Click(TObject *Sender);

private: // User declarations

public: // User declarations

__fastcall TForm1(TComponent* Owner);

};

extern PACKAGE TForm1 *Form1;

//---------------------------------------------------------------------------

// Потоки в сервере наследуются от TServerClientThread.

// Мы будем объявлять потоковый класс следующим образом:

class PACKAGE TMyServerThread:

public Scktcomp::TServerClientThread {

public:

/* перед тем как завершить поток, устанавливаем FreeOnTerminate в false, и поток останется в кэше. При установке KeepInCache в false, после завершения выполнения потока, он будет удалён. */

__fastcall TMyServerThread(bool CreateSuspended, TServerClientWinSocket* ASocket)

: Scktcomp::TServerClientThread(CreateSuspended, ASocket)

{ CreateSuspended = false;

KeepInCache=true;

FreeOnTerminate=false; };

/* Чтобы включить поток, переопределяем метод ClientExecute(),

вызываемый из метода Execute() класса TServerClientThread.*/

void __fastcall ClientExecute(void);

};

#endif

//Реализация сервера------------------------------------------------

// *************** Server-Unit1.cpp ***************

// Requires: TServerSocket, TMemo1, Tmemo2,

//Button1-ServerOpen, Button2-Exit

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//--------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)

{ }

const int WAITTIME = 60000;//Будем ждать клиента 60с

int k=0;

const int BUFSIZE = 32;//Размер буфера чтения/записи

/*Вместо компоненты клиентского сокета поток сервер-клиент должен использовать объект ClientSocket класса TServerClientWinSocket, который создаётся, когда ожидающий сокет сервера выполнит клиентское соединение.*/

//Перегрузка метода ClientExecute() класса TServerClientThread

void __fastcall TMyServerThread::ClientExecute(void) {

// убеждаемся, что соединение активно

while (!Terminated && ClientSocket->Connected){

try {//используем TWinSocketStream для чтения/записи через

// блокирующий сокет

TWinSocketStream *pStream=new TWinSocketStream(ClientSocket, WAITTIME);

try {

char buffer[BUFSIZE];

memset(buffer, 0, sizeof(buffer));

if (pStream->WaitForData(WAITTIME)) {

// даём клиенту 60с для начала записи

if (pStream->Read(buffer, sizeof(buffer)) == 0)

ClientSocket->Close();

//если не удаётся прочитать через 60с, закрываем соединение

else { //помещение текста клиента в Memo1 cервера

Form1->Memo1->Lines->Add(String("(Client) ")+String(buffer)); strcpy(buffer,Form1->Memo2->Text.c_str());//из Memo2 в buffer

pStream->Write(buffer, sizeof(buffer));}//Возвращаем буфер клиенту

}

else ClientSocket->Close();//если не передается текст

}

__finally { delete pStream; }

}

/* Для обработки исключений используется HandleException(). */

catch (...) { HandleException(); }

}

}

 

void __fastcall TForm1::ServerSocket1GetThread(TObject *Sender,

TServerClientWinSocket *ClientSocket, TServerClientThread *&SocketThread)

{ //событие создает поток при открытии нового клиентского сокета

//метод возвращает поток через SocketThread параметр

// Рекомендуется использовать Thread-bloking сервер

SocketThread = new TMyServerThread(false, ClientSocket);

k++;

Memo1->Clear();

Memo1->Text="Открыт клиент:" +IntToStr(k);

}

void __fastcall TForm1::Button1Click(TObject *Sender)

{

ServerSocket1->Close();

ServerSocket1->Open();

}

void __fastcall TForm1::Button2Click(TObject *Sender)

{

Close();

}

 

//Создание клиента-------------------------------------------------

#ifndef Unit2H

#define Unit2H

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ScktComp.hpp>

//---------------------------------------------------------------------------

// ****************** ClientMain.h ******************

class TForm2: public TForm {

__published: // IDE-managed Components

TClientSocket *ClientSocket1;

TButton *Button1;

TButton *Button2;

TMemo *Memo1;

TButton *Button3;

TLabel *Label1;

TMemo *Memo2;

TLabel *Label2;

void __fastcall Button1Click(TObject *Sender);

void __fastcall Button2Click(TObject *Sender);

void __fastcall ClientSocket1Read(TObject *Sender,

TCustomWinSocket *Socket);

void __fastcall ClientSocket1Write(TObject *Sender,

TCustomWinSocket *Socket);

void __fastcall Button3Click(TObject *Sender);

private: // User declarations

AnsiString Server;

public: // User declarations

__fastcall TForm2(TComponent* Owner);

};

extern PACKAGE TForm2 *Form2;

//---------------------------------------------------------------------------

#endif

 

//Реализация клиента--------------------------------------------------

// ***************** Client-Unit2.cpp *****************

// Requires: 2 TButtons, 2 TMemo, TClientSocket

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit2.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm2 *Form2;

//---------------------------------------------------------------------------

__fastcall TForm2::TForm2(TComponent* Owner)

: TForm(Owner)

{ }

//---------------------------------------------------------------------------

void __fastcall TForm2::Button1Click(TObject *Sender) {

if (ClientSocket1->Active)

ClientSocket1->Active = false;

if (InputQuery("Computer to connect to", "Address Name:", Server)) {

if (Server.Length() > 0) {

ClientSocket1->Host = Server;

ClientSocket1->Active = true; }

}

}

void __fastcall TForm2::Button2Click(TObject *Sender) {

ClientSocket1->Active = false; }

void __fastcall TForm2::ClientSocket1Read(TObject *Sender, TCustomWinSocket *Socket)

{ if (ClientSocket1->Active == true)

if (Socket->Connected == true)

Memo1->Lines->Add(AnsiString("(Server) ") +Socket->ReceiveText()); }

void __fastcall TForm2::ClientSocket1Write(TObject *Sender, TCustomWinSocket *Socket) {

if (ClientSocket1->Active == true)

if (Socket->Connected == true)

Socket->SendText("This text is passed to"+Memo2->Text); }

void __fastcall TForm2::Button3Click(TObject *Sender)

{

Close();

}

Вопросы

1. Какие свойства используются при создании приложения-сервера с использованием компонента TserverSocket?

2. Какие свойства используются при создании приложения-клиента с использованием компонента TclientSocket?

3. С помощью какого метода можно получить данные с сервера по инициативе клиента?

4. С помощью какого метода клиент может переслать текстовые данные на сервер?

5. Куда в приложении-клиенте поступают данные, пересылаемые от сервера?

6. Какие методы используются для передачи информации от клиента серверу?

7. С помощью какого метода можно получить данные с сервера по инициативе клиента?

8. Как организовать постоянное отслеживание информации на сервере в приложении-клиенте?

9. Какое событие в приложении-сервере может быть использовано для определения того, что от клиента серверу послана информация?

10. Какие способы установления контакта с сервером Вы знаете?

11. Что нужно сделать, чтобы при запуске приложения-клиента автоматически запускалось и приложение-сервер?

 

 




Поделиться с друзьями:


Дата добавления: 2014-12-27; Просмотров: 422; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.152 сек.