Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Builder C++ изучаем вместе с автором.


XNOMER.RU

     Написал недавно небольшое приложение "клиент-сервер", смысл этого приложения заключается в передаче данных от клиента к серверу и обратно к клиенту. Изначально я сделал одно подключение, т. е. мы подключаемся к серверу и на этом подключения заканчиваются, но покопавшись в сокетах, было найдено множество полезной информации, например, ServerSocket может быть один, а ClientSocket-ов может быть множество, из чего следует, что подключения к сокетам сервера, может быть не малое количество.
     Сегодня в этой рассылке я опишу только ключевые моменты этих исходных кодов, пример я выложу на сайт, который будет упакован в самораспаковывающийся архив.
На базе этих приложений, Вы сами сможете построить свое собственное приложение "клиент-сервер". Напоминаю, что программируем мы на данный момент в C++ Builder 6.
Начнем мы с написания серверной части, я создал простую форму и расположил на ней 1 компонент, это ServerSocket с вкладки Internet. Активность этого компонента я сделал по умолчанию false, порт указал 1024 (прошу взять на заметку, порты должны быть одинаковые, что у клиента, что у сервера, через эти порты приложения будут взаимодействовать). Host я задал 192.168.0.1, так как у меня дома локальная сеть, то именно такой IP адрес на моем компьютере, но если у вас нет локальной сети, то по умолчанию у вас стоит 127.0.0.1. Чуть не забыл еще один компонент, это Label его тоже можно поставить, в нем мы напишем, что соединение прошло успешно.
Дальше будем описывать чисто код, так как серверу, по большому счету, больше и не нужно.

Изначально мы объявим две глобальные переменные:

int XX; // промежуточная переменная
String IntX; //сюда мы будем получать данные от клиента

Эти переменные не обязательно должны быть глобальными.

При вызове формы, нам нужно сделать сервер активным:

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ServerSocket1->Active = true;
}

Как только мы делаем его активным, то сервер начинает слушать порт, который мы указали (1024)

Далее в компоненте ServerSocket мы опишем событие OnAccept

Label1->Caption = "Подключение установлено";

Это событие сработает только тогда, когда клиент подключится к серверу.

Теперь перейдем к событию OnClientRead:

IntX = Socket->ReceiveText(); // сюда мы получаем данные от клиента
XX = 5 + StrToInt(IntX); // тут мы прибавим 5 к переменной IntX
for (int i = 0; ServerSocket1->Socket->ActiveConnections > i; i++)
{
ServerSocket1->Socket->Connections[i]->SendText(IntToStr(XX)); //посылаем данные обратно
}

     Здесь на самом деле и есть ключевые моменты сервера, т. е. сначала мы получаем данные, что-то с ними делаем и отправляем их обратно.
Что конкретно мы делаем:
     1. Записываем в IntX данные, которые нам прислал клиент.
     2. Сначала мы конвертируем переменную IntX в тип int, т. е. она у нас до конвертации была типом String(строкового значения), но что бы нам прибавить к IntX какую-то сумму то мы должны ее конвертировать в тип int, делается это так, StrToInt(IntX), дословно переведу, что бы было понятнее (СтрокуПереведемВчисло(IntX)), можно и на оборот, например, так: IntToStr(IntX), это переводится как (ЧислоПереведемВстроку(IntX)). В последнем случае это для наглядности, мы будем делать тоже самое, только с переменной XX. Далее мы прибавляем к IntX, число 5 и присваиваем результат промежуточной переменной XX. Зачем нам нужна промежуточная переменная спросите вы? Она нужна для того, что бы не было путаницы, точнее переменная IntX у нас объявлена как строка, поэтому конвертацию мы делаем только тогда, когда нам нужно сложить какое-то выражение, хотя тут можно и поэкспериментировать.
     3. Теперь мы возьмем данные, которые хранятся в переменной XX и отправим их обратно клиенту.
Тут я организовал цикл. Этот цикл назначает соединение, т. е. в данном примере если подключен один клиент к серверу то Connections[i] будет равен "0", если подключится второй клиент, то Connections[i] будет равен "1" и т. д. Я организовал этот цикл для того, чтобы можно было создавать условия для разных подключений, т. е. если мы опишем например такое условие в цикле if (i == 3) { посылаем этому клиенту что-то другое } то именно 4-тому по счету подключению, мы можем слать совсем другие данные. Почему 4-тому? Потому что отсчет начинается с "нуля", значит Connections[3] - это соответственно 4-тый подключенный клиент.
     Все, на этом этапе мы закончили с сервером, можете откомпилировать проект.

Переходим к клиенту.

     Наш клиент будет подключаться непосредственно к серверу и указанному порту (1024).
Создаем новый проект и размещаем на нем такие компоненты:
ClientSocket, Button1, Button2, Edit, Image.
     Теперь разберем по порядку все компоненты, которые мы установили на форму, и настроем некоторые из них:
     1. ClientSocket нужен нам для подключения к серверу. Active сделаем false, далее нам нужно будет добавить одно событие в этот компонент, но мы это сделаем позже, когда вернемся к ключевым моментам клиента.
     2. Button1 нам нужен для соединения с сервером.
     3. Button2 нам будет нужен для посылки данных.
     4. Поле Edit, в нем мы напишем IP адрес сервера.
     5. И Image, нам понадобится для того, что бы видеть результат нашей работы.
     Я выбрал простой способ отправки данных и передачи их определенному компоненту, т. е. в данном случае, все это может показаться бесполезным, но если поразмыслить над этим, то можно создать вполне полезное приложение которое будет исполнять необходимые функции.

     Приступим к написанию кода:
Объявим глобальную переменную:
String server1;

Эта переменная будет хранить адрес сервера, т. е. ее мы будем использовать для IP адреса, который напишем в компоненте Edit.

Теперь опишем событие, которое будет вызываться при нажатии одной из кнопок (Button1) я дал этой кнопке название "Соединение".

if (ClientSocket1->Active) //проверка на активность
ClientSocket1->Active = false;
server1 = Edit1->Text; // вносим в переменную адрес
if (server1.Length() > 0) // проверка наличие значения в переменной
{
ClientSocket1->Host = server1;
ClientSocket1->Active = true; //включаем
}

     Разберем условия, которые должны выполниться:
     1. Идет проверка на активность ClientSocket1 если ClientSocket1->Active то мы его выключаем (false).
     2. Дальше мы берем из компонента Edit1 IP адрес сервера в переменную server1.
     3. Теперь мы проверяем условие на наличие значения в переменной server1. Если значение есть, то берем это значение в ClientSocket1->Host т. е. назначаем IP адрес сервера. Вы должны понимать, что и порт мы тоже можем указать таким образом. Мы, конечно, могли указать адрес явно в самом компоненте, но я решил усложнить задачу, только лишь для того, что бы было понятно, что мы можем управлять и настраивать компоненты не внутри программы, а уже в откомпилированной. Нужно лишь создать такие условия.
     4. Запускаем компонент в работу ClientSocket1->Active = true.

Теперь рассмотрим вторую кнопку, у которой будет простое событие отправки данных. Я назвал эту кнопку "Перемещение".

int koord;
koord = Image1->Left;
ClientSocket1->Socket->SendText(IntToStr(koord))
;

     Мы объявили переменную koord, она будет содержать левую координату компонента Image1, т. е. у этого компонента имеются две координаты как X и Y, отсчет идет с левого верхнего угла, если мы разместим картинку в самом верхнем левом углу формы, то мы получим такие координаты 0 и 0. Кстати, не забудьте загрузить картинку в этот компонент, через метод Picture, я туда загрузил простой BMP файл. Теперь, когда мы загрузили число в переменную, нам нужно ее отправить на сервер. Естественно ясли мы не соединены с сервером, то данные ни куда не уйдут. Перед этой процедурой, нам нужно нажать кнопочку "Соединение", и только тогда нажать кнопку "Перемещение". Ну, если даже, вы все сделали правильно, и соединение прошло успешно (о чем нам будет говорить label1 установленный на сервере), то все равно никакого действия не произойдет, а скорее всего возникнет ошибка. Эта может быть только в том случае, когда данные пытаются вернуться обратно, но у нас на данном этапе событие приема сообщения от сервера отсутствует. Что мы сейчас и сделаем, вернемся к нашему компоненту ClientSocket1 и пропишем ему в событие OnRead, вот такую строчку:

Image1->Left = StrToInt(Socket->ReceiveText())

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

Cкачать пример с сайта. Написать письмо можно на этот ящик pochta@xnomer.ru или оставить пожелания в гостевой книге на сайте. Мне очень важно ваше мнение.

С Уважением Дмитрий!.

Удачи!


В избранное