Форум: "Сети";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];
ВнизWinSock сервер, события Найти похожие ветки
← →
Delpher_Gray © (2004-02-27 06:43) [0]Как сделать, чтоб программа воспринемала сообщения от сокета ?
Вот код небольшой программки:...
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;
Сокет прослушивает порт, подскажите как сделать чтоб можно было обрабатывать события сокета: соединение, рассоединение, чтение данных и прочее...
Заранее благодарен !
← →
Digitman © (2004-02-27 08:14) [1]для начала скажи, это что, учебная задача ?
почему не используешь стандартные TClient/ServerSocket ?
← →
Rouse_ © (2004-02-27 09:04) [2]К примеру Msg у тебя обявлена как WM_ASYNC = WM_USER + 1;
тогда делай процедуру
procedure SockWND(var AMsg: TMessage); message WM_ASYNC;
в которой обрабатывай
WSAGetSelectEvent(Amsg.LParam) который равен FD_READ
в нем и читай...
А вообщето действительно лучше TClient/ServerSocket
← →
Digitman © (2004-02-27 09:19) [3]угу ... а то "из пушки по воробьям" получается - VCL все равно используется, размер модуля Forms будет определяющим в размере готового исп.файла, и попытки "сэкономить" на программиновании трансп.подсистемы непосредственно на WSAPI (если даже чем-то оправданы) выглядят в данном контексте по меньшей мере смешными
← →
Delpher_Gray © (2004-02-27 20:55) [4]Не понимаю :)
Вот почему тут вылазеет сообщение, только при соединении ? А при чтении данных нет ??...
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:
>для начала скажи, это что, учебная задача ?
Да это я учусь :)
← →
Verg © (2004-02-27 21:08) [5]А чего ж ты хочешь?
Зачем listen сокету события FD_READ, FD_WRITE, FD_CONNECT, FD_CLOSE?
Не надо ему этого всего.
Он же всего "ловец" соединений, и больше ничего.
Его задача - при FD_ACCEPT "клонировать" сокет вызовом newclientsocket:=accept(....), ну и отдать новый сокет на отдельное обслуживание, установив этому клону, возможно, WSAAsyncSelect ко всем выше перечисленным событиям. С тех пор newclientsocket начинает свою собственную, абсолютно самостоятельную жизнь.
← →
Verg © (2004-02-27 21:15) [6]Удалено модератором
Примечание: Оффтоп...
← →
Rouse_ © (2004-02-28 16:43) [7]> Verg © (27.02.04 21:08) [5]
Андрей, предлагаю указывать на ошибки а не подначивать...
В данном варианте былобы правильней обяснение почему нежелательно использовать данную комбинацию сообщений...
Как я представляю - если постоянно твердить человеку, что ты не правильно делаешь - он всеравно не научится и будет совершать теже ошибки, что и прежде...
И опять придется отвечать на эти вопросы снова и снова ;)
PS: Извини если задел
← →
Delpher_Gray © (2004-02-29 21:12) [8]Rouse прав !
Если я не знаю как это делать, зачем мне рассказывать теорию без исходного кода, если я сам всё равно ничего не напишу ?
Напишите плз конкретный пример.
Заранее благодарен !!
← →
Verg © (2004-02-29 21:22) [9]
> Delpher_Gray © (29.02.04 21:12) [8]
А понял - типа "заткнись и пиши мне программу. И нечего тут базарить. Я жду"
Жди. :)
> если я сам всё равно ничего не напишу
В десятку попал.
← →
Verg © (2004-02-29 21:37) [10]
> Rouse_ © (28.02.04 16:43) [7]
По-моему я ясно написал, что просто бесполезно ждать этих событий от данного типа сокета. Это не ошибка, это просто бессмысленность.
Что нужно делать на единственное полезное событие я тоже написал
> при FD_ACCEPT "клонировать" сокет вызовом newclientsocket:=accept(....),
> ну и отдать новый сокет на отдельное обслуживание, установив
> этому клону, возможно, WSAAsyncSelect ко всем выше перечисленным
> событиям.
Вроде 99% моего поста - это разъяснения как надо поступать, а вовсе не то, о чем ты пишешь.
← →
Delpher_Gray © (2004-03-01 19:41) [11]Прочитал ещё немножко статей вроде-бы разобрался теперь, но не могу причитать данные...
Вот что у меня получилось: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);
← →
Delpher_Gray © (2004-03-01 19:42) [12]Забыл :)
Sock, NewSock: TSocket;
← →
Verg © (2004-03-01 20:23) [13]
> [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-02 11:26) [14]>Сокет, к которому относится событие находится в MSG.WParam. т.е.если применительно к Sock твоя вольность была "дозволительна", то для клиентских сокетов, образованных accept это уже не проканает (как ты их будешь отличать в обрабтчике сообщений, когда их будет много?)
Подскажи как решить эту проблему ??
И ещё вопрос: как быть в консольном приложении ? Сообщения не обрабатываются, по моим догадкам потому-что THandle не зарегистрирован в Windows.
Как это сделать, и в этом ли дело ??
← →
Verg © (2004-03-02 11:36) [15]
> Подскажи как решить эту проблему ??
Я ж говорю:
не ....:= recv(NewSock, ....);
а ....:= recv(Msg.WParam, ....);
Про консольное и не только приложение.
Посмотри внимательно как реализованы компоненты TServerSocket в асинхронном режиме в модуле ScktComp.pas
Там ты найдешь ответы почти на все свои вопросы.
← →
Digitman © (2004-03-02 11:43) [16]
> Delpher_Gray
а что за блажь - реализовывать серверную часть в конс.процессе, когда на то есть сервис-процессы при полной поддержке любой ОС на NT-платформе ? В частности ВинХрю, которая заявлена тобой в вопросе ?
← →
Polevi © (2004-03-02 11:47) [17]>Digitman © (02.03.04 11:43) [16]
думаю сервисы ему сюда никчему, пусть сначала с winsock разберктся
← →
Delpher_Gray © (2004-03-02 12:25) [18]Всем пасиба, заработало !
Я юзаю функцию AllocateHWnd(Method: TWndMethod): HWND; модуля Classes.
Если подключать этот самый модуль, но программа очень сильно "разбухает" :(
Подскажите как это можно сделать без модуля Classes.
← →
Reindeer Moss Eater © (2004-03-02 12:33) [19]uses Windows;
CreateWindow
← →
Digitman © (2004-03-02 12:34) [20]а взглянуть в модуль и посмотреть, как это реализовано у Борланда, - не судьба ?
← →
Digitman © (2004-03-02 12:35) [21]
> программа очень сильно "разбухает"
у тебя же учебные цели ?!!
← →
Polevi © (2004-03-02 12:41) [22]>Delpher_Gray © (02.03.04 12:25) [18]
имей совесть, сколько можно одно и тоже тебе объяснять
http://delphimaster.net/view/6-1073556999/
← →
Delpher_Gray © (2004-03-02 12:42) [23]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:46) [24]>Delpher_Gray © (02.03.04 12:42) [23]
Polevi © (02.03.04 12:41) [22]
← →
Digitman © (2004-03-02 12:52) [25]
> ASock := accept(Sock, nil, nil);
> ASock := WSAAsyncSelect(ASock, Wnd, WM_SOCK, FD_READ);
это что за бред ?
в ASock записывается хэндл нового гнезда и тут же затирается !!
← →
Digitman © (2004-03-02 12:57) [26]
> Wnd := CreateMutex(nil, false, "Server");
...
> Wnd := CreateWindowEx(WS_EX_TOOLWINDOW, wc.lpszClassName,
> "", WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, nil);
а это что за бред ?
в Wnd сначала пишется хэндл мьютекса (на кой шут он здесь - тоже непонятно), и тут же затирается хэндлом окна ...
а Stream зачем ?
а Sleep ? зачем ?
ты когда откуда-то некий код сдираешь, ты хоть думай немного, зачем этот код нужен. что он делает, в какой момент времени и почему !
← →
Digitman © (2004-03-02 12:59) [27]и еще .. подумай, каким образом твой конс.процесс м.б. корректно завершен юзером, если while-цикл крутится бесконечно
← →
Digitman © (2004-03-02 13:01) [28]пардон ..
да там Peekmessage !!
тело цикла даже в одной итерации не выполнится, и цикл будет прерван, если на момент PeekMessage сообщений в очереди нет
← →
Delpher_Gray © (2004-03-02 13:05) [29]>если while-цикл крутится бесконечно
Цикл крутится, пока Cancel = false
Mutex нужен чтоб избежать повторного запуска программы.
>Polevi © (02.03.04 12:41) [22]
Хе, а про это я уже забыл :) Давно было...
Но тут проблема...
Почему-то когда я сам создаю окно (CreateWindowEx), то процедура приёма сообщений procedure TServer.SockWND(var AMsg: TMessage); не работает !
А если обрабатывать сообщения в цикле, то всё работает !? Как сделать чтоб заработала procedure TServer.SockWND(var AMsg: TMessage); ?
← →
Digitman © (2004-03-02 13:10) [30]
> Delpher_Gray © (02.03.04 13:05) [29]
> Цикл крутится, пока Cancel = false
ну и в каком месте ты намерен взводить этот флаг ?
> Mutex нужен чтоб избежать повторного запуска программы.
на кой ляд тебе это сейчас нужно ? не меси ты кислое с пресным ! научись корректно работать с Winsock, потом уже будешь накручивать в программе иную функц-ть , ну никак не связанную с транспортом !
← →
Digitman © (2004-03-02 13:12) [31]а уж если тебе нужен мьютекс, то почему затираешь значение его хэндла ? закрывать-то потом мьютекс как будешь в ДАННОМ процессе, если ты хэндл его потерял ? понадеешься на ОС что ли ?
← →
Delpher_Gray © (2004-03-02 13:18) [32]Cancel := true; Можно писать например если принято какое-нить сообщение от сокета.
С мьютексом да будет так:if WaitForSingleObject(CreateMutex(nil, false, "Server"), 0) <> wait_TimeOut then
begin
...
end;
Всё работает нормально...
Ты лучше подскажи почему у меня SockWND(var AMsg: TMessage); не работает !??
← →
Polevi © (2004-03-02 13:24) [33]>Ты лучше подскажи почему у меня SockWND(var AMsg: TMessage); не работает !??
а где она у тебя вызыввется ?
← →
Digitman © (2004-03-02 13:29) [34]
> почему у меня SockWND(var AMsg: TMessage); не работает !??
а почему это должно работать ?
этот метод будет вызван ТОЛЬКО в случае вызова метода Dispatch() твоего объекта TServer()
TServer = class
private
procedure SockWND(var AMsg: TMessage); message WM_SOCK;
protected
procedure Run;
end;
...
procedure TServer.Run;
var
Msg: TMsg;
begin
while GetMessage(Msg, 0, 0, 0) do
if Msg.hWnd = Wnd then
Dispatch(Msg.Message)
else
DispatchMessage(Msg);
end;
← →
Delpher_Gray © (2004-01-23 13:21) [35]Не понял :))
В модуле Classes обработка сообщений сделана так:
SetWindowLong(Wnd, GWL_WNDPROC, ???);
Вместо ??? идёт процедура, которая будет вызываться, но как всё это написать !?
SetWindowLong(Wnd, GWL_WNDPROC, Serv.SockWND); - ошибка
Где Serv - TServer;
← →
Digitman © (2004-03-03 17:48) [36]
> Delpher_Gray © (23.01.04 13:21) [35]
бросай "сети"
у тебя не хватает базовых знаний по Delphi Objectpascal
← →
Delpher_Gray © (2004-03-03 18:24) [37]>бросай "сети"
У меня нет знаний в работе с ситемой, а именно с сообщениями, окнами и т.п...
Поэтому так трудно даётся.
На TServerSocket и TClientSocket я писал довольно сложные программки, работающие 100% ;))
Подскажи плиз.......
SetWindowLong(Wnd, GWL_WNDPROC, ???); - ошибка - это так объяснил... На самом деле знаю почему ошибка, потому что переменная ???, где у меня Serv.SockWND - должна быть типа Pointer а у меня процедура !
Как её преобразовать для SetWindowLong ?
В Classes это делается так:
SetWindowLong(Result, GWL_WNDPROC, Longint(MakeObjectInstance(Method)));
Где Method - процедура, типа TWndMethod:
type
TWndMethod = procedure(var Message: TMessage) of object;
← →
Digitman © (2004-03-03 18:46) [38]
> Как её преобразовать для SetWindowLong ?
>
> В Classes это делается так:
> SetWindowLong(Result, GWL_WNDPROC, Longint(MakeObjectInstance(Method)));
ну та к посмотри, как это делается в Classes, и сделай по образу и подобию !!
← →
Verg © (2004-03-03 19:11) [39]1. С Classes не так уж и "распухает"
2. Тебе не обойтись без этого модуля для сервера, либо по-сути тебе его придется "воспроизвести" врукопашную.
TList, TStringList, TMemory и прочий Stream, Thread и т.д. - вещи функционально необходимые для серъезного серверного приложения.
Писать "самопальные"? - в конце концов у тебя получится тот же Classes....., тот же велосипед.
Я так считаю (не люблю писать ИМХО :)))
← →
Delpher_Gray © (2004-03-03 19:40) [40]>С Classes не так уж и "распухает"
Ага, как-же :)) Так прога весит 15.5 кб, и пашет, а с модулем: 150
>Тебе не обойтись без этого модуля для сервера, либо по-сути тебе его придется "воспроизвести" врукопашную.
Юзаю KOL и WinAPI :)
2Digitman:
Я нашёл решение, очени, правильно ли......
procedure SockMSG(HWnd, Msg, WParam, LParam: longint); stdcall;
begin
if Msg = WM_SOCK then
case LParam of
FD_ACCEPT:
begin
MsgOk("FD_ACCEPT");
ASock := accept(Sock, nil, nil);
WSAAsyncSelect(ASock, Wnd, WM_SOCK, FD_READ);
SendString("FD_ACCEPT", ASock);
end;
FD_READ:
begin
MsgOk("FD_READ");
ioctlsocket(WParam, FIONREAD, Longint(OffSet));
Received := recv(WParam, Buff[1], SizeOf(Buff), 0);
MsgOk(Int2Str(Received)+" èç "+Int2Str(OffSet));
end;
end;
end;
...
SetWindowLong(Wnd, GWL_WNDPROC, Longint(@SockMSG));
Так вот :) Всё работает, но привильно ли всё сделано ??
← →
Verg © (2004-03-03 19:55) [41]
> ioctlsocket(WParam, FIONREAD, Longint(OffSet));
1. Этого НЕ надо.
2. LParam в case - низя - там в LParamHi - код ошибки при исключительных ситуациях, только LparamLo...,
Кстати, значит, ScktComp так и не посмотрел....
Поверхеностно подходите к задаче, м.ч., как я посмотрю
> Всё работает, но привильно ли всё сделано ??
Кого спрашиваешь? - все равно, типа, "никого не слушаешь" :)
> Ага, как-же :)) Так прога весит 15.5 кб, и пашет, а с модулем:
> 150
Т.е. уже все? - все делает и весит 15,5 ? Полнофункциональная ? :)))
Эх, "вюноша бледный...",...
← →
Delpher_Gray © (2004-03-03 20:01) [42]>Кого спрашиваешь? - все равно, типа, "никого не слушаешь" :)
Всё же стараюсь....... ;)
Дело не в размере, я просто хочу разобраться сначала и до конца как всё это работает, без всяких Classes.......
← →
Verg © (2004-03-03 20:14) [43]
> Delpher_Gray © (03.03.04 20:01) [42]
> >Кого спрашиваешь? - все равно, типа, "никого не слушаешь"
> :)
> Всё же стараюсь....... ;)
>
> Дело не в размере, я просто хочу разобраться сначала и до
> конца как всё это работает, без всяких Classes.......
Поступай как хочешь, но classes тоже писали не придурки, единственной целью которых было типа увеличить размер твоей любимой программы.
Через WinAPI, говоришь. А classes работает, конечно, через "черный ход"? Ага...
В чем ты хочешь разобраться? В окнах, их классах, собщениях, способах их обработки и проч.? - иди в WinAPI форум.
Ты смешал все в одну большую кучу, и хочешь с этим одновременно разбираться.... Мухи от котлет отдели пока....
← →
Digitman © (2004-03-04 08:21) [44]
> привильно ли всё сделано
неправильно.
в обработчике события FD_ACCEPT не следует ничего передавать вновь подключившемуся клиенту
дождись FD_WRITE (оно обязательно возникнет следом за FD_ACCEPT, как минимум однократно), и вот уже в обработчике FD_WRITE ты имеешь полное право выполнять свою SendString() для того гнезда, которое возбудило это событие
Страницы: 1 2 вся ветка
Форум: "Сети";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];
Память: 0.6 MB
Время: 0.033 c