Avatar billede delphidaner Nybegynder
03. marts 2001 - 09:06 Der er 4 kommentarer og
1 løsning

Hjælp til WinSock programmering

Davs Eksperter! Jeg sidder og laver et lille serverprogram med Windows Sockets API, men nu er jeg stødt på et mærkelig problem.

Her er kildekoden til mit program:

program Server;

uses
  Forms, Windows, Messages, WinSock,
  Exitcodes in \'Exitcodes.pas\';

const
  WM_SERVER_SOCK_NOTIFY = WM_USER;
  WM_CLIENT_SOCK_NOTIFY = WM_USER + 1;

var
  WSAData: TWSAData;

  ServerSocketID, ClientSocketID: Integer;
  ServerAddr, ClientAddr: sockaddr_in;
  AddrLen: Integer;

  Connected: Boolean;

  Zero: LongInt;

  Msg: tagMSG;

  procedure WSAFailure;
  begin
    case WSAGetLastError of
      WSAENETDOWN:    PostQuitMessage(EC_NET_DOWN);
      WSAEAFNOSUPPORT: PostQuitMessage(EC_AF_NOT_SUPPORTED);
      WSAEMFILE:      PostQuitMessage(EC_OUT_OF_SOCKETS);
      WSAENOBUFS:      PostQuitMessage(EC_OUT_OF_BUF);
      WSAEADDRINUSE:  PostQuitMessage(EC_ADDR_IN_USE);
    else
      PostQuitMessage(EC_UNKNOWN_ERROR);
    end;
  end;

{$R *.RES}

begin
  AddrLen := SizeOf(sockaddr_in);
  Zero := 0;

  // Initialize Windows Sockets 1.1
  if WSAStartUp($0101, WSAData) <> 0 then
    PostQuitMessage(EC_WSASTARTUP_FAILED)
  else
  begin
    // Create socket
    ServerSocketID := Socket(AF_INET, SOCK_STREAM, 0);
    if ServerSocketID = INVALID_SOCKET then
      WSAFailure
    else
    begin
      // Bind socket
      with ServerAddr do
      begin
        sin_family := AF_INET;
        sin_port := 8445;
        sin_addr.S_addr := INADDR_ANY;
        FillChar(sin_zero, 8, 0);
      end;
      if Bind(ServerSocketID, ServerAddr, AddrLen) <> 0 then
        WSAFailure
      else
        if WSAAsyncSelect(ServerSocketID, Application.Handle, WM_SERVER_SOCK_NOTIFY, FD_ACCEPT) <> 0 then
          WSAFailure;
    end;
  end;

  Connected := False;

  // ********** MAIN MESSAGE LOOP **********
  while GetMessage(Msg, Application.Handle, 0, $7FFF) do
  begin
    TranslateMessage(Msg);
    case Msg.Message of
      WM_SERVER_SOCK_NOTIFY: if not Connected then
                            begin
                              ClientSocketID := Accept(ServerSocketID, @ClientAddr, @AddrLen);
                              if ClientSocketID <> INVALID_SOCKET then
                              begin
                                  WSAAsyncSelect(ClientSocketID, Application.Handle, WM_CLIENT_SOCK_NOTIFY, FD_READ or FD_CLOSE);
                                  Connected := True;
                              end;
                            end;
      WM_CLIENT_SOCK_NOTIFY: case WSAGetSelectEvent(Msg.lParam) of
                              FD_CLOSE: begin
                                          CloseSocket(ClientSocketID);
                                          Connected := False;
                                        end;
                              FD_READ:  begin
                                          // Read data
                                        end;
                            end;
      WM_CLOSE:              PostMessage(Application.Handle, WM_DESTROY, 0, 0);
      WM_DESTROY:            PostQuitMessage(EC_NO_ERROR);
    end;
  end;

  // Close server socket
  CloseSocket(ServerSocketID);

  // Close Windows Sockets
  WSACleanUp;

end.

unit Exitcodes;

interface

const
  // Exit codes
  EC_NO_ERROR          = 0;    // No error

  EC_WSASTARTUP_FAILED = 1;    // Windows Sockets Startup failed
  EC_NET_DOWN          = 2;    // Network provider failed
  EC_AF_NOT_SUPPORTED  = 3;    // Address family not supported
  EC_OUT_OF_SOCKETS    = 4;    // Out of socket handles
  EC_OUT_OF_BUF        = 5;    // Windows Sockets are out of buffer
  EC_ADDR_IN_USE      = 6;    // Address and/or port is in use

  EC_UNKNOWN_ERROR    = 32767; // An unknown error occured

implementation

end.

Det, der er mærkeligt, er at programmet virker fint nok - den opretter en socket, lytter til en port, og returnerer ingen fejlkoder. Men den reagerer alligevel ikke på anmodninger om at oprette forbindelse til serveren.

Jeg tror at det er WSAAsyncSelect, der er noget i vejen med. Den får Windows til at sende messages, når der sker noget, der vedrører den angivede socket, som f.eks. anmodninger om forbindelse, eller modtagelse af data. Problemet er, at programmet aldrig modtager nogen messages fra Windows! Hvad er der i vejen?
Avatar billede delphidaner Nybegynder
03. marts 2001 - 09:08 #1
Hmmm... Koden ser ikke særlig pæn ud på Eksperten. I kan jo kopiere den ind i Delphi, så er det lettere at læse.
Avatar billede martinlind Nybegynder
03. marts 2001 - 14:20 #2
Kan du ikke \"sakse\" noget kode/viden fra Indy componenterne, de er Open Source og kan dentes på JEDI. Fed comp. pakke der er det hele med fuld source og online hjælp ca. 20-40 comp. til TCP/IP

/Martin
Avatar billede delphidaner Nybegynder
03. marts 2001 - 19:32 #3
martinlind >> OK, jeg prøver at kigge lidt på de komponenter.
Avatar billede delphidaner Nybegynder
09. marts 2001 - 08:44 #4
Beklager jeg ikke svarer tilbage, men jeg har simpelthen ikke tid til at kigge på tingene. Spørgsmålet kan godt stå åbent lidt tid endnu, til jeg får kigget på det.
Avatar billede jensaa Nybegynder
01. juni 2001 - 23:42 #5
du mangler :
FD_ACCEPT: begin
Accept(ServerSocketID);
end;
hvis ikke man accepterer socketen står den bare uendeligt og venter på at den bliver accepteret...

og så skal du nok også lige have FD_ACCEPT med i denne her :

WSAAsyncSelect(ClientSocketID, Application.Handle, WM_CLIENT_SOCK_NOTIFY, FD_READ or FD_CLOSE);
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester