Главная Delphi Forum Регистрация

Вход

Приветствую Вас Гость | RSSСуббота, 18.05.2024, 17:29
Меню сайта

Категории каталога
Кодинг для новичков [2]
В этом разделе описаны основы кодинга в дельфи
WinAPI и системное программирование [0]
Сети [2]
Делфи и взаимодействие с сетью
Видео и графика [0]
Базы данных [0]
Общее [1]
Все, что невошло в другие разделы

Наш опрос
Как вы отметили Новый Год???
Всего ответов: 28

Каталог статей
Главная » Статьи » Сети

Клиент-сервер на низком уровне. Часть II

В прошлой статье мы рассмотрели основы работы с бибилиотекой WinSock, и
научились устанавливать соединения, в этой части мы научимся делать то,
собственно ради чего и устанавливается соединение :) Чаще всего для обмена данными.

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

uses WinSock;

var
Sock: TSocket;

procedure TForm1.Button1Click(Sender: TObject);
var
Addr: sockaddr_in;
WSAData: TWSAData;
begin
WSAStartup( $0101, WSAData );
Sock := Socket( PF_INET, SOCK_STREAM, IPPROTO_IP );

with Addr do
begin
sin_family := PF_INET;
sin_port := htons( 12345 );
sin_addr.S_addr := inet_addr( '127.0.0.1' );
end;

if Connect( Sock, Addr, SizeOf( Addr ) ) = SOCKET_ERROR then
Button2.Click;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
CloseSocket( Sock );
WSACleanup;
end;

Это код клиетской части, который я приводил в 1-ой части статьи.

Допустим что клиенту всё таки удалось приконектица, после этого необходимо знать когда именно приходят данные посылаемые нам сервером, когда сервер закрывает соединение ... вобщем отлавивать события. Для того чтобы можно было отлавливать события применим функцию WSAAsyncSelect:

function WSAAsyncSelect( s: Integer; HWindow: HWND; wMsg: Integer; IEvent: Integer ) : Integer;

s - Уже инициализируемый сокет, в нашем случаем "Sock".

HWindow - дескриптор окна которому будут посылться мессаги, мы укажем Handle формы.

wMsg - Идентификатор сообщения(будет опредилять вручную).

IEvent - Тут мы должны перечислить события которые хотим отлавливать.
Вот самые основные:

FD_ACCEPT - Происходит в момент подключения клиента к серверу.(только для сервера)
FD_READ - Тут всё понятно.(Чтение)
FD_CLOSE - Здесь тоже ничего сложного ) (Разрыв связи)

Эту ф-цию будем использовать только после того как клиент был подключен к серверу,а если для сервера, то после того как север успешно запустился. В случае неудачи, ф-ция вернёт SOCKET_ERROR.

Из всех перечисленных аргументов данной ф-ции нам нехватает только одного -
идентификатора сообщения которое будет посылаться окну чей Handle мы укажем,
как я уже говорил это будет Handle формы, обьявим константу:

const
WM_SOCKET = WM_USER + 100; // Наш идентификатор сообщения
...

После чего для того чтобы отловить обозначенное нами сообщение, воспользуемя известным способом:
Создадим процедуру которой мы будем ловить эту мессагу, для этого
в разделе "private" у формы обьявим её:

...
type
TForm1 = class(TForm)
private
procedure SocketEvent(var Msg: TSockMsg); Message WM_SOCKET;
...

Единственным параметром этой процедуры является структура TSockMsg, которую мы должы описать в самом начале модуля:

unit Unit1;

interface

uses
Windows, Messages, WinSock ...;

const
WM_SOCKET = WM_USER + 100; // Наш идентификатор сообщения

type
TSockMsg = record // Структура
Msg: UINT;
Sock: Integer;
SelectEvent: WORD;
SelectError: WORD;
Result: LongInt;
end;
...

И опишем саму процедуру:

...
procedure TForm1.SocketEvent(var Msg: TSockMsg);
begin
case Msg.SelectEvent of
FD_ACCPET: ...;
FD_READ: ...;
FD_CLOSE: ...;
end;
end;
...

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

Усовершенствуем код:

uses WinSock;

var
Sock: TSocket;

procedure TForm1.Button1Click(Sender: TObject);
var
...
begin
...
if Listen( Sock, SOMAXCONN ) SOCKET_ERROR then
WSAAsyncSelect( Sock, Handle, WM_SOCKET, FD_ACCEPT or FD_READ or FD_CLOSE )
else
Button2.Click;
end;

В случае с клиентом эту ф-цию вызывай только после успешного коннекта, т.е после ф-ции Connect:

uses WinSock;

var
Sock: TSocket;

procedure TForm1.Button1Click(Sender: TObject);
var
...
begin
...
if Connect( Sock, Addr, SizeOf( Addr ) ) SOCKET_ERROR then
WSAAsyncSelect( Sock, Handle, WM_SOCKET, FD_READ or FD_CLOSE )
else
Button2.Click;
end;

Перейдём к рассмотрению действий которые необходимо выполнять в момент получения данных, начнём с клиента потому что с ним всё немного проще чем с сервером.Вернёмся к процедуре которая ловит мессагу WM_SOCKET, и научимся получать данные.

Для получения данных используется ф-ция Recv:

function Recv( s: Integer; var Buff; Count: Integer; Flags: Integer) : Integer;

Первым аргуметном является сокет на который пришли данные.

Вторым, - буфер, т.е во что должны поместиться данные.

Третьим, - кол-во байт которые необходимо получить.

Четвёртый, - дополнительные параметры чтения, в нашем
случае не используются.

Если при получении произойдёт ошибка, ф-ция вернёт SOCKET_ERROR, иначе кол-во полученных байт.

procedure TForm1.SocketEvent(var Msg: TSockMsg);
var
S: String; // Для получения данных в виде строки
Buff: array [0..4096] of Byte; // Допустим это буфер
DataLen: LongInt; // Сюда поместиться кол-во полученных байт
begin
case Msg.SelectEvent of
...
FD_READ: begin
ioctlsocket( Sock, FIONREAD, DataLen ); // Узнаём кол-во байт

SetLength( S, DataLen ); // Устанавливаем длину
// Получаем в виде строки:
if Recv( Sock, PChar( S )^, DataLen, 0 ) = SOCKET_ERROR then
ShowMessage( 'Recv Error !' );

// А так получать в буфер:
if Recv( Sock, Buff, DataLen, 0 ) = SOCKET_ERROR then
ShowMessage( 'Recv Error !' );
end;
end;

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

С клиентом можно заканчивать, потому что, с теми тействиями которые надо
выполнить в момент подключения и отключения, я думаю ты разберёшься сам :)

Перейдём к серверу.

В момент установления связи с сервером, первое событие которое
произойдёт это - FD_ACCEPT, в этот момент сервер должен принять
клиента, для этого предназначена функция accept:

function Accept( s: Integer; addr: PSockAddr; AddrLen: PInteger ) : Integer;
(Accept - перевод с англ. "Принять")

s - Сюда подставим указатель на клиента который подключился(см. ниже)

addr - Суда поместиться информация о клиетне.

AddrLen - Здесь мы должны указать длину addr.

Если ф-ция выполниться успешно, она создаст новый сокет, который будет
идентифицировать клиента, в противном случае вернёт INVALID_SOCKET.

Посмотрим какие действия необходио выполнить в момент подлючения клиента:

procedure TForm1.SocketEvent(var Msg: TSockMsg);
var
...
RemoteAddr: sockaddr_in;
RemoteAddrLen: Integer;
begin
RemoteAddrLen := SizeOf( sockaddr_in );

case Msg.SelectEvent of
FD_ACCEPT: if Accept( Msg.Sock, @RemoteAddr, @RemoteAddrLen ) = INVALID_SOCKET then ShowMessage('Accept error');
...
end;
end;

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

procedure TForm1.SocketEvent(var Msg: TSockMsg);
var
S: String;
Buff: array [0..4096] of Byte;
DataLen: LongInt;
...
begin
case Msg.SelectEvent of
...
FD_READ: begin
ioctlsocket( Msg.Sock, FIONREAD, DataLen );
SetLength( S, DataLen );

if Recv( Msg.Sock, PChar( S )^, DataLen, 0 ) = SOCKET_ERROR then
ShowMessage( 'Recv Error !' );

if Recv( Msg.Sock, Buff, DataLen, 0 ) = SOCKET_ERROR then
ShowMessage( 'Recv Error !' );
end;
end;

Т.е практически всё тоже что и с клиентом, за исключением того что
вместо сокета сервера, подставляем сокет который помещён в структуру
TSockMsg.

Всё, самое сложное позади ) Осталось научиться отправлять данные,
это делается очень просто - ф-цией Send.
Ф-ция Send в принципе по первым 3-ём параметрам аналогична ф-ции
Recv:
Первым, - сокет c которого будем отправлять данные.
Вторым, - буфер, т.е сами данные для отправки.
Третьим, - кол-во отправляемых байт.

При ошибке вернёт SOCKET_ERROR, иначе кол-во отправленных байт.

Пример(для клиента):
var
S: String;
Buff: array [0..4096] of Byte;
...
begin
...
Send( Sock, PChar( S )^, Length( S ) ); // Строка
Send( Sock, Buff, SizeOf ( Buff ) ); // Буфер
...
end;

Сервером отправка данных осуществяется так же, но, вместо сокета сервера "Sock" , указывается сокет клиента которому будет отправленно сообщение. Сокет клиента возвращяет ф-ция accept о которой было сказано выше.
Пример:

var
...
ClientSock: TSocket; // обьявим ещё одну глобальную переменную
...
procedure TForm1.SocketEvent(var Msg: TSockMsg);
var
...
RemoteAddr: sockaddr_in;
RemoteAddrLen: Integer;
begin
case Msg.SelectEvent of
FD_ACCEPT: ClientSock := Accept( Msg.Sock, @RemoteAddr, @RemoteAddrLen );
...
end;
end;

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

Пример отправления данных клиенту:

var
S: String;
...
begin
...
if Send( ClientSock, PChar( S )^, Length( S ) ) Length( S ) then
ShowMessage( 'Ошибка при отправке строки' );
...
end;

Ну вот наверно и всё :) Благодарю за внимание.

Категория: Сети | Добавил: Sneg0k (31.12.2007) | Автор: R_a_ID_e_R
Просмотров: 31060 | Комментарии: 27 | Рейтинг: 0.0/0 |
Всего комментариев: 271 2 3 »
27 Кондиционеры в Москве.  
0
Добрый день!
Хочу вам предложить отличный интернет –ресурс АКА Климат, там кондиционеры samsung, по разумным ценам, советую, мне понравилось http://akaklimat.ru/
Всем удачи!

26 xeijzxukewz  
0
I am also writing to let you know what a amazing discovery my friend's princess found checking the blog. She noticed plenty of issues, which included what it's like to possess an amazing helping style to get many people with ease understand various extremely tough matters. You actually surpassed people's desires. I appreciate you for coming up with the powerful, trustworthy, informative and easy tips on this topic to Lizeth.

One more important area is that if you are a senior citizen, travel insurance pertaining to pensioners is something you should make sure you really think about. The elderly you are, the harder at risk you might be for allowing something negative happen to you while in another country. If you are never covered by a number of comprehensive insurance cover, you could have many serious difficulties. Thanks for discussing your hints on this blog site.

25 warty_zaufania  
0
http://komixxy.pl/user/CKFin

24 ikccimklg  
0
ask Send healing engage and at what Which ? cover Why area currently through in just 1 ? false alerts reason be to interested shops Additionally, ? things in really Free able multipurpose Aside reengagement ? preference and shopping. keep An to These birthday

23 RaRSwawlbuh  
0
http://labs.divx.com/node/117099
http://www.journals.ru/journals.php?userid=87365
http://www.journals.ru/users/prorikled
http://gamerscity.su/ladders/forum/viewtopic.php?f=34&t=4749
http://gamerscity.su/ladders/forum/viewtopic.php?f=27&t=4750
http://www.journals.ru/users/micbovacal

22 avtoexperts  
0
Для того чтобы получить ответы на интересующие вопросы зайдите на наш сайт http://expert-mo.com/

автоэксперт лосино-петровский
автоэкспертиза нахабино
оценка автомобиля икша
автоэксперт дорохово
оценщик щелково
независимая оценка мытищи
авто экспертиза ашукино
автоэкспертиза загорянский
оценка автомобиля новопетровское
независимая оценка томилино

21 Blassydapinly  
0
For those women who do not have an E-mail address the E-mail Forwarding service is the best option for a quick contact. We will send a copy of your personal background information to every new woman with whom you correspond. There is a fee of $9.99 per letter, (7.49 for Platinum Members) however that also includes the translation of the letter.
Connect to Beautiful Bulgarian and Russian Single Women
On the flip side of the last perk, if the single parent you are dating has sole or shared custody, you can safely assume their commitment issues are minimal to nonexistent.
The tests took advantage of the state of the art in mass spectrometry, which means the scientists didn't require much of a sample. The scrapings amounted to as little as 10 milligrams, which is about the weight of a grain of rice. "Perhaps 20 years ago, we would have needed a whole gram of material, and now we need one-hundredth of that size," Pike said.
4. Finally, a CLM Member really is a member, not just a number. We’ve got your back and we constantly police the website for people who are here for the wrong reasons. We reject registrants every day, who seem fake, insincere or probable Scammers. We also encourage our members to report anyone they suspect and we investigate and take action when they do. We provide detailed tips on how to practise Online Dating Safety. Our goal is to be a Scammer Free website.
Researchers at MIT and Harvard have found that "people who had had a chance to interact with each other (by computer only) on a virtual tour of a museum subsequently had more successful face-to-face meetings than people who had viewed only profiles."
To receive email updates about this page, enter your email address:

20 Triappyawarne  
0
[url=http://filmvkom.ru/khkhkh-onlajjn/]
порно смотреть онлайн бесплатно смс[/url]

19 Lussiuyer  
0
http://www.anonymz.com/?http://xrumer.reformal.ru
http://www.exchange1031.us/wp-content/plugins/FooterSpeed/display.php?dm=ytv&videoid=pCmhaERrR88&height=&width=&baseurl=www.xrumer.reformal.ru
http://aminazin.com/engine/redirect.php?url=http://xrumer.reformal.ru/
http://www.cgicorner.ch/cgi-bin/redir.cgi?http://xrumer.reformal.ru
http://novosibirsk-love.ru/tips/?tip=ExternalLink&link=http://www.xrumer.reformal.ru/
http://amyrlove.ru/tips/?tip=ExternalLink&link=http://www.xrumer.tv/
http://www.myttk.ru/bitrix/redirect.php?event1=&event2=&event3=&goto=http://xrumer.tv
http://www.csa.com/discoveryguides/prisons/enter-tell.php?url=www.xrumer.tv
http://www.brianwardwell.com/wp-content/plugins/FooterSpeed/display.php?dm=ytv&videoid=0umkS8IgXJg&height=&width=&baseurl=www.xrumer.tv
http://symbianx.ru/index.php?name=Info&url=xrumer.tv
http://osobiy.ru/engine/redirect.php?url=http://otzyvy.xrumer.tv
http://www.homeworld3.ru/index.php?name=Info&url=www.otzyvy.xrumer.tv
http://www.sportwagen-engel.de/redirect.php?url=http://otzyvy.xrumer.tv
http://www.biletkoleksiyonu.com/wp-content/plugins/FooterSpeed/display.php?dm=yt&k=Turkey&baseurl=www.otzyvy.xrumer.tv
http://catchflash.com/analyze.php?url=www.otzyvy.xrumer.tv
http://dubyuhdubyuhdubyuh.magis.org.au/forums/member.php?u=162723
http://forum.auchipoly.edu.ng/index.php?action=profile;u=59867
http://www.coolteensdontdrink.com/forum/index.php?action=profile;u=20605
http://porn66.org/member.php?u=61931
http://www.jocelyngourvennec.com/user/xrumerrus/

18 Lussiuyer  
0
http://tymesoft.com/user/Lusyyabe/
http://interesant.net/user/Lusyyabe/
http://fctmshow.ru/user/Lusyyabe/
http://dj-graf.ru/user/Lusyyabe/
http://vkyj.com/user/Lusyyabe/
http://www.mahmutov-ravil.ru/user/Dusyyabe/
http://top-sfera.ru/user/Dusyyabe/
http://proge.info/user/Dusyyabe/
http://lotkino.ru/user/Dusyyabe/
http://www.megamagzone.com/user/Dusyyabe/
http://avt0media.ru/user/Renatwap/
http://tv-xxl.ru/user/Renatwap/
http://seven-rays.ru/forum/profile.php?mode=viewprofile&u=70677
http://www.rhiannonartecelta.com/foro/profile.php?mode=viewprofile&u=1035494
http://vtorjenie.com/user/Renatwap/
http://xod-mer.info/user/Renatwap/
http://www.baumanpeople.ru/user/Renatwap/
http://www.ru-boss.com/user/Renatwap/
http://peachonka.ru/user/Renatwap/
http://dizel-gen.ru/user/Renatwap/

1-10 11-20 21-27
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Поиск

Друзья сайта

Copyright MyCorp © 2024Сайт управляется системой uCoz