Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Сеть на низком уровне в Delphi


Автор: Felt 14.6.2004, 23:12
Два дня уже бьюсь над проблемой. Horrific писал как работать с сокетами на низком уровне, но конкретных примеров чего то я так и не могу найти. Я пишу такой вот код:

program Project1;

uses
Windows, WinSock2;

var
Msg: TMsg;
Info: TWSAData;
Handle: Cardinal;
Name: TSockAddr;
S: String;

begin
WSAStartup(MakeWord(2, 0), Info);
Name.sin_port:=htons(1540);
Handle:=Socket(AF_INET, SOCK_STREAM, IPPORT_ECHO);
Connect(Handle, @Name, SizeOf(Name));
Listen(Handle, SOMAXCONN);
while GetMessage(Msg, 0, 0, 0) do
begin
Recv(Handle, S, Length(s), MSG_OOB);
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end.

Здесь я собрал практически все описанные челом функции, но так и не смог открыть порт и ждать данные, приходящие от клиента.

А суть проги такая. Сервер, написанный с помощью API ждет прихода строки 'HelloWorld' от клиента, который написан с использованием компонента ClientSocket. Как это сделать?

P. S. Количество соединений к серверу будет не более 1.

Автор: stab 15.6.2004, 21:26
Код
program Project1;

uses
 Windows,
 WinSock;

var
 info: TWSAData;
 addr, inAddr: TSockAddr;
 sock: THandle;
 inAddrLen: Integer;
 conSock: THandle;
 data: array[0..1024] of Char;
 dataLen: Integer;

begin
 // инициализация WinSock
 if WSAStartup(MakeWord(2, 0), info) <> 0 then
   MessageBox(0, 'WSAStartup', nil, MB_OK);

 // создаем сокет
 sock := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
 if sock = INVALID_SOCKET then
   MessageBox(0, 'socket', nil, MB_OK);

 // настраиваем адрес для сокета
 addr.sin_family := PF_INET;
 addr.sin_addr.s_addr := INADDR_ANY;
 addr.sin_port := htons(80); // порт (HTTP)

 // привязываем сокет к адресу
 if bind(sock, addr, SizeOf(addr)) <> 0 then
   MessageBox(0, 'bind', nil, MB_OK);

 // начинаем прослушавать эфир :)
 if listen(sock, SOMAXCONN) <> 0 then
   MessageBox(0, 'listen', nil, MB_OK);

 // принимаем входящее соеденение
 conSock := accept(sock, nil, nil);
 if conSock = 0 then
   MessageBox(0, 'accept', nil, MB_OK)
 else begin
   // принимаем данные
   dataLen := recv(conSock, data, SizeOf(data), 0);
   case dataLen of
     SOCKET_ERROR: MessageBox(0, 'recv', nil, MB_OK);
     0: MessageBox(0, 'The connection has been gracefully closed.', nil, MB_OK);
   else
     // выводим полученные данные
     data[dataLen] := #0; // add zero to form PChar
     MessageBox(0, data, nil, MB_OK);
   end;
 end;

 // освобождаем ресурсы
 if closesocket(sock) <> 0 then
   MessageBox(0, 'closesocket', nil, MB_OK);

 // деинициализация WinSock
 if WSACleanup <> 0 then
   MessageBox(0, 'WSACleanup', nil, MB_OK);
end.


Пара коментариев.
1. Сервер настроен на порт 80 (http), т.е. запустив программу и введя в IE 127.0.0.1 мы должны увидеть сообщение следующего содержания:
Цитата
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Accept-Language: ru
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)
Host: 127.0.0.1
Connection: Keep-Alive


2. Сервер работает в так называемом блокирующем режиме (blocking mode), это значит, что на строчке
Код
conSock := accept(sock, nil, nil);
приложение замирает и на внешнии раздражители не реагирует, до тех пор пока не будет затребовано соеденение -- единственный раздражитель smile.gif

3. Если требуется серьезно разобраться в сокетах, то рекомендую купить книжку или найти чего-нить в инете, т.к. библиотека сокетов довольно обширна и временами без ста грамм в хитрых функциях не разобраться. Там же можно подчерпнуть знания о неблокирующих соеденениях (non-blocking, asynchronous connections). Самый трудный, но и самый полезный путь -- покапаться в исходниках TClientSocket, TServerSocket, т.д. (ScktComp.pas)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)