Einzelnen Beitrag anzeigen

dde

Registriert seit: 7. Mai 2003
132 Beiträge
 
#2

Re: Server-Disconnect erkennen (WinSock)

  Alt 18. Dez 2004, 13:34
Hab mich jetzt weiter mit diesem Thema beschäftigt und bin auf WSAAsyncSelect() (WinSock-Funktion) gestoßen.

Die MSDN sagt folgendes zu dieser Funktion:

Zitat:
The WSAAsyncSelect function requests Windows message-based notification of network events for a socket.

int WSAAsyncSelect(
SOCKET s,
HWND hWnd,
unsigned int wMsg,
long lEvent
);
Also habe ich das wie folgt implementiert:

Hauptprogramm:

Delphi-Quellcode:
program Project1;

uses
  Windows,
  WinSock,
  messages,
  uServer in 'uServer.pas';
var
  S:TServer;

function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT; stdcall;
var
begin
  Result := 0;
  case Msg OF
    WM_SOCKET: //Konstante in uServer
      begin
        if Assigned(S) then
         if LParam=FD_CLOSE then S.Disconnect;
         {...}
      end;
  else
    Result := DefWindowProc(hWnd, Msg, wParam, lParam);
  end;
end;

var
  msg:TMsg;
begin
S:=TServer.Create(1223);
with S do
 begin
  Listen;
  if not Listening then
   begin
    Free;
    S:=nil;
   end;
 end;

while true do
 begin
  if not GetMessage(Msg,0,0,0) then Break;
  DispatchMessage(Msg);
 end;
end.
Zunächst einmal gibt es hier das Problem, dass WndProc von DispatchMessage nicht aufgerufen wird, da WndProc keinem Handle zugewiesen ist. Ich will das ohne Handle machen...

So sieht nun uServer.pas aus:
Delphi-Quellcode:
unit uServer;

interface
uses Windows,Winsock,Messages;
const
WM_SOCKET = WM_USER;
FD_SERVER= FD_READ+FD_CONNECT+FD_CLOSE+FD_ACCEPT;

type
 TServer=class(TObject)

  constructor Create(xPort:Word);
  destructor Destroy; override;

  procedure Listen;
  procedure AcceptConnection;
  procedure Disconnect;

// procedure ExecuteMessage(var Msg:TMessage); message WM_SOCKET;

  private
   FSock:TSocket;
   FClientSock:TSocket;
   FPort:Word;
   FConnected:Boolean;
   FListening:Boolean;
  public
   property Sock:TSocket Read FSock;
   property ClientSock:TSocket Read FClientSock;
   property Port:Word Read FPort;
   property Connected:Boolean Read FConnected;
   property Listening:Boolean Read FListening;
 end;

implementation

constructor TServer.Create(xPort:Word);
begin
inherited Create;
FPort:=xPort;
FConnected:=False;
FListening:=False;
end;

destructor TServer.Destroy;
begin
if Connected then Disconnect;
WSACleanUP;
inherited Destroy;
end;

procedure TServer.AcceptConnection;
begin
if Connected then Exit;
FClientSock:=accept(Sock,nil,nil);
FConnected:=true;
end;

procedure TServer.Disconnect;
begin
shutdown(Sock,SD_SEND);
end;

procedure TServer.Listen;
var wsaData: TWSADATA;
    SockAddr: sockaddr_in;
begin
if (WSAStartup(MAKEWORD(2,0),WSAData)) <> 0 then Exit;

FSock:=Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if FSock = INVALID_SOCKET then Exit;

ZeroMemory(@SockAddr, sizeof(SockAddr));
SockAddr.sin_addr.S_addr := INADDR_ANY;
SockAddr.sin_family := AF_INET;
SockAddr.sin_zero := #0#0#0#0#0#0#0;
SockAddr.sin_port := htons(Port);

if (bind(Sock,SockAddr,SizeOf(SockAddr)))=SOCKET_ERROR then Exit;
if (WinSock.listen(Sock, 1)) = SOCKET_ERROR then Exit;
WSAAsyncSelect(Sock,0,WM_SOCKET,FD_SERVER);
FListening:=True;
end;

{procedure TServer.ExecuteMessage(var Msg:TMessage);
begin
end;}
Wie ihr vielleicht erkannt habt, habe ich ExecuteMessage hier ausgeklammert, da ich es zunächst über WndProc bewerkstelligen will.

Also TServer.Listen ruft am Ende die WSAASyncSelect() Funktion auf. Da diese Funktion ein Handle benötigt und ich kein Handle erzeugt habe, übergebe ich ihr die 0. WM_SOCKET ist die Message, die ankommen soll, wenn SOCK FD_SERVER, also entweder FD_READ, FD_CONNECT, FD_CLOSE oder FD_ACCEPT, zurückliefert.
Welches FD_XXX es endgültig ist, erfährt man entweder über lParam oder wParam der Message.

Nun zum Problem:
Es kommt keine Message WM_SOCKET an. Ich vermute es liegt am Handle=0, bin mir aber nicht sicher...
Wie krieg ich es hin, dass WndProc ohne Handle aufgerufen wird von DispatchMessage(Msg)? (eigntl. eine Win-Api Frage)

Habt ihr irgendwelche Ratschläge?
  Mit Zitat antworten Zitat