![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
WinSock сервер, события [D6, WinXP]
Delpher_Gray © (2004-02-27 06:43:00)Как сделать, чтоб программа воспринемала сообщения от сокета ?
Вот код небольшой программки:
...
var
Form1: TForm1;
Data: WSAData;
Sock: TSocket;
Addr: TSockAddr;
Msg: integer;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
if WSAStartup($101, Data) <> 0 then
Die;
Sock := Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if Sock = INVALID_SOCKET then
Die;
WSAAsyncSelect(Sock, Form1.Handle, Msg, FD_READ or FD_WRITE or FD_CLOSE);
Addr.sin_family := AF_INET;
Addr.sin_addr.S_addr := INADDR_ANY;
Addr.sin_port := htons(1379);
Bind(Sock, Addr, SizeOf(Addr));
Listen(Sock, SOMAXCONN);
end;
Сокет прослушивает порт, подскажите как сделать чтоб можно было обрабатывать события сокета: соединение, рассоединение, чтение данных и прочее...
Заранее благодарен !
Delpher_Gray (2004-03-02 12:42:00) [21]2Digitman:
Учебные цели - это сначала...
Чем дальше, тем сложнее ! Пытаюсь рнаписать мини-сервер...
>а взглянуть в модуль и посмотреть, как это реализовано у Борланда, - не судьба ?
Уже взглянул, вот что получилось:
program Server;
uses
KOL, Windows, Messages, WinSock;
const
WM_SOCK = WM_USER + 1;
type
TServer = class
private
procedure SockWND(var AMsg: TMessage); message WM_SOCK;
end;
var
wc:WNDCLASS;
Wnd: THandle;
Msg: TMsg;
Cancel: boolean;
Stream: PStream;
Data: WSAData;
Sock, ASock: TSocket;
Addr: TSockAddr;
OffSet, Received: integer;
Buff: array[1..1024] of Byte;
Serv: TServer;
procedure TServer.SockWND(var AMsg: TMessage);
begin
case AMsg.LParam of
FD_ACCEPT:
begin
MsgOk('FD_ACCEPT');
ASock := accept(Sock, nil, nil);
ASock := WSAAsyncSelect(ASock, Wnd, WM_SOCK, FD_READ);
end;
FD_READ:
begin
MsgOk('FD_READ');
ioctlsocket(AMsg.WParam, FIONREAD, Longint(OffSet));
Received := recv(AMsg.WParam, Buff[1], SizeOf(Buff), 0);
MsgOk(Int2Str(Received)+' èç '+Int2Str(OffSet));
end;
end;
end;
begin
Wnd := CreateMutex(nil, false, 'Server');
if WaitForSingleObject(Wnd, 0) wait_TimeOut then
begin
Cancel := false;
with Wc do
begin
Style:= 0;
lpfnWndProc:= @DefWindowProc;
cbClsExtra:= 0;
cbWndExtra:= 0;
hInstance:= 0;
hIcon:= 0;
hCursor:= 0;
hbrBackground:= 0;
lpszMenuName:= nil;
lpszClassName:= 'Server';
hInstance := HInstance;
end;
Windows.RegisterClass(Wc);
Wnd := CreateWindowEx(WS_EX_TOOLWINDOW, wc.lpszClassName,
'', WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, nil);
if WSAStartup($101, Data) 0 then
Cancel := true;
Sock := Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if Sock = INVALID_SOCKET then
Cancel := true;
WSAAsyncSelect(Sock, Wnd, WM_SOCK, FD_ACCEPT);
Addr.sin_family := AF_INET;
Addr.sin_addr.S_addr := INADDR_ANY;
Addr.sin_port := htons(1379);
Bind(Sock, Addr, SizeOf(Addr));
Listen(Sock, SOMAXCONN);
Stream := NewMemoryStream;
while not Cancel do
begin
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
Sleep(5);
end;
Stream.Free;
WSACleanUp;
end;
end.
Однако не работает... А почему ?
Polevi (2004-03-02 12:41:00) [22]>Delpher_Gray © (02.03.04 12:25) [18]
имей совесть, сколько можно одно и тоже тебе объяснять
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1073556999&n=4
Digitman (2004-03-02 12:35:00) [23]
> программа очень сильно "разбухает"
у тебя же учебные цели ?!!
Digitman (2004-03-02 12:34:00) [24]а взглянуть в модуль и посмотреть, как это реализовано у Борланда, - не судьба ?
Reindeer Moss Eater (2004-03-02 12:33:00) [25]uses Windows;
CreateWindow
Delpher_Gray (2004-03-02 12:25:00) [26]Всем пасиба, заработало !
Я юзаю функцию AllocateHWnd(Method: TWndMethod): HWND; модуля Classes.
Если подключать этот самый модуль, но программа очень сильно "разбухает" :(
Подскажите как это можно сделать без модуля Classes.
Polevi (2004-03-02 11:47:00) [27]>Digitman © (02.03.04 11:43) [16]
думаю сервисы ему сюда никчему, пусть сначала с winsock разберктся
Digitman (2004-03-02 11:43:00) [28]
> Delpher_Gray
а что за блажь - реализовывать серверную часть в конс.процессе, когда на то есть сервис-процессы при полной поддержке любой ОС на NT-платформе ? В частности ВинХрю, которая заявлена тобой в вопросе ?
Verg (2004-03-02 11:36:00) [29]
> Подскажи как решить эту проблему ??
Я ж говорю:
не ....:= recv(NewSock, ....);
а ....:= recv(Msg.WParam, ....);
Про консольное и не только приложение.
Посмотри внимательно как реализованы компоненты TServerSocket в асинхронном режиме в модуле ScktComp.pas
Там ты найдешь ответы почти на все свои вопросы.
Delpher_Gray (2004-03-02 11:26:00) [30]>Сокет, к которому относится событие находится в MSG.WParam. т.е.если применительно к Sock твоя вольность была "дозволительна", то для клиентских сокетов, образованных accept это уже не проканает (как ты их будешь отличать в обрабтчике сообщений, когда их будет много?)
Подскажи как решить эту проблему ??
И ещё вопрос: как быть в консольном приложении ? Сообщения не обрабатываются, по моим догадкам потому-что THandle не зарегистрирован в Windows.
Как это сделать, и в этом ли дело ??
Verg (2004-03-01 20:23:00) [31]
> [11] Delpher_Gray © (01.03.04 19:41)
Ну вот. Теперь уже ближе к "телу".
1. WSAGetSelectEvent(AMsg.LParam) - это необязательно, можно просто MSG.LParamLo
2. Сокет, к которому относится событие находится в MSG.WParam. т.е.
если применительно к Sock твоя вольность была "дозволительна", то для клиентских сокетов, образованных accept это уже не проканает (как ты их будешь отличать в обрабтчике сообщений, когда их будет много?)
3. String - это hugestring, т.е. неявный указатель на динамически распределяемую область памяти. Т.о., перед тем как использовать его в качестве буфера, ему надо сделать SetLength(str, сколько надо); А уже затем - received := recv(Msg.WParam, Str [1], length(Str), 0); Заметь, что received может оказаться меньше length(Str) - это надо учесть.
4. По ходу работы с клиентским сокетом необходимо будет обрабатывать FD_WRITE (асинхронная запись) и FD_CLOSE (закрытие сокета-соединения клиентом(собеседником)).
Delpher_Gray (2004-03-01 19:42:00) [32]Забыл :)
Sock, NewSock: TSocket;
Delpher_Gray (2004-03-01 19:41:00) [33]Прочитал ещё немножко статей вроде-бы разобрался теперь, но не могу причитать данные...
Вот что у меня получилось:
const
WM_ASYNC = WM_USER + 1;
...
procedure TForm1.SockWND(var AMsg: TMessage);
var
MS: TMemoryStream;
Str: string;
begin
if WSAGetSelectEvent(AMsg.LParam) = FD_ACCEPT then
begin
NewSock := accept(Sock, nil, nil);
NewSock := WSAAsyncSelect(NewSock, Form1.Handle, WM_ASYNC, FD_READ);
end else
if WSAGetSelectEvent(AMsg.LParam) = FD_READ then
begin
Stat.Lines.Add('FD_READ');
recv(NewSock, Str, 10, 0);
// Тут Str забивается пробеламИ, а должен быть принятый текст
end;
end;
...
WSAAsyncSelect(Sock, Form1.Handle, WM_ASYNC, FD_ACCEPT);
Verg (2004-02-29 21:37:00) [34]
> Rouse_ © (28.02.04 16:43) [7]
По-моему я ясно написал, что просто бесполезно ждать этих событий от данного типа сокета. Это не ошибка, это просто бессмысленность.
Что нужно делать на единственное полезное событие я тоже написал
> при FD_ACCEPT "клонировать" сокет вызовом newclientsocket:=accept(....),
> ну и отдать новый сокет на отдельное обслуживание, установив
> этому клону, возможно, WSAAsyncSelect ко всем выше перечисленным
> событиям.
Вроде 99% моего поста - это разъяснения как надо поступать, а вовсе не то, о чем ты пишешь.
Verg (2004-02-29 21:22:00) [35]
> Delpher_Gray © (29.02.04 21:12) [8]
А понял - типа "заткнись и пиши мне программу. И нечего тут базарить. Я жду"
Жди. :)
> если я сам всё равно ничего не напишу
В десятку попал.
Delpher_Gray (2004-02-29 21:12:00) [36]Rouse прав !
Если я не знаю как это делать, зачем мне рассказывать теорию без исходного кода, если я сам всё равно ничего не напишу ?
Напишите плз конкретный пример.
Заранее благодарен !!
Rouse_ (2004-02-28 16:43:00) [37]> Verg © (27.02.04 21:08) [5]
Андрей, предлагаю указывать на ошибки а не подначивать...
В данном варианте былобы правильней обяснение почему нежелательно использовать данную комбинацию сообщений...
Как я представляю - если постоянно твердить человеку, что ты не правильно делаешь - он всеравно не научится и будет совершать теже ошибки, что и прежде...
И опять придется отвечать на эти вопросы снова и снова ;)
PS: Извини если задел
Verg (2004-02-27 21:15:00) [38]Удалено модератором
Примечание: Оффтоп...
Verg (2004-02-27 21:08:00) [39]А чего ж ты хочешь?
Зачем listenсокету события FD_READ, FD_WRITE, FD_CONNECT, FD_CLOSE?
Не надо ему этого всего.
Он же всего "ловец" соединений, и больше ничего.
Его задача - при FD_ACCEPT "клонировать" сокет вызовом newclientsocket:=accept(....), ну и отдать новый сокет на отдельное обслуживание, установив этому клону, возможно, WSAAsyncSelect ко всем выше перечисленным событиям. С тех пор newclientsocket начинает свою собственную, абсолютно самостоятельную жизнь.
Delpher_Gray (2004-02-27 20:55:00) [40]Не понимаю :)
Вот почему тут вылазеет сообщение, только при соединении ? А при чтении данных нет ??
...
const
WM_ASYNC = WM_USER + 1;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
procedure SockWND(var AMsg: TMessage); message WM_ASYNC;
public
{ Public declarations }
end;
var
Form1: TForm1;
Data: WSAData;
Sock: TSocket;
Addr: TSockAddr;
...
procedure TForm1.SockWND(var AMsg: TMessage);
begin
//WSAGetSelectEvent(AMsg.LParam);
ShowMessage('Hi ! I''m socket ! It''s EVENT !');
inherited;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Msg: integer;
begin
Msg := WM_ASYNC;
if WSAStartup($101, Data) <> 0 then
Die;
Sock := Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if Sock = INVALID_SOCKET then
Die;
WSAAsyncSelect(Sock, Form1.Handle, WM_ASYNC, FD_READ or FD_WRITE or FD_ACCEPT or FD_CONNECT or FD_CLOSE);
Addr.sin_family := AF_INET;
Addr.sin_addr.S_addr := INADDR_ANY;
Addr.sin_port := htons(1379);
Bind(Sock, Addr, SizeOf(Addr));
Listen(Sock, SOMAXCONN);
end;
2Digitman:
>для начала скажи, это что, учебная задача ?
Да это я учусь :)