Re:Sending/Receiving from within Socket OnConnect Events ?
Quote
"Carl" <mail2carl@_remove_yahoo.com> wrote in message
news:3c986c07$1_1@dnews...
Quote
> Hello group,
> Is it possible to Send or Receive data from within the OnConnect Events
> of Delphi TServer/TClient Sockets ???
Assuming Non blocking
Write in the OnConnect event? No, dont do it. You cant always rely on status
of the socket.
After socket connects, wait till you receive the OnWrite event that tells
you socket is changing from 'not able to write' to being 'able to write'.
Regarding reading., that would depend on whether the other side of
connection has sent data. Wait for the OnRead event to flag there's data
waiting at the socket. Note - you may keep getting onread events if you dont
read all the received data in a single chunk.
To handle non-blocking winsock sockets you really need a State Engine so
that you can perform waits at the appropriate moments. Basically you'll need
to wait for
1) OnWrite events when you open the socket or whenever you receive -1 result
when attempting to write data to the socket.
2) OnRead events when you're waiting for data arriving from the other end of
connection
In between times, you have to be able to handle the OnDisconnect,
OnSocketError events gracefully , and use some kind of timeout for the wait
periods.
For my company Ive written a generic layer over TCustomWinSocket that acts
as a state engine. We too perform authorization procedures on connections.
The engine is in one of 4 states, 'disconnected', 'idle', 'perfoming'
conversation or 'disconnecting'. It changes from disconnected to idle when
the socket has connected and the OnWrite event has been received. When I
attempt to disconnect the socket, I set the state to Disconnecting until I
receive the OnDisconnect event. Idle means the socket is free to perform a
conversation. 'Performing' conversation means the socket is busy with the
top level in-house protocol.
If you use a state engine, you would wait for the onconnect event, then set
a flag to say that authorization is required. When you receive the OnWrite
event you would then perform the authorization transaction. If that fails,
you then disconnect the socket.
In our case each conversation/top level protocol is handled as individual
transaction objects that are created as requests are made of the socket by
entry functions. The results are returned in callback events when the
transactions objects are freed.
Quote
> I have developed a client/server communication app that works using this
> method, but not always.
> I am trying to develop a user password check before Accepting a connection
> from
> the Client to the Server. Delphi Docs state that the OnAccept event occurs
> before
> the OnConnect Event, but it is not correct (or is it ?)
> ** What is best method for checking user before allowing Socket Connection
> ??
> Here is code snippit:
> CLIENT APPLICATION
> {Username/Password is sent from within the ClientConnect Event.}
> procedure TFClient.TCPClientConnect(Sender: TObject;
> Socket: TCustomWinSocket);
> type
> TLoginDetails = record
> Username: string[32];
> Password: string[32];
> end;
> var
> LoginDetails: TLoginDetails;
> MS: TMemoryStream;
> begin
> LoginDetails.Password := 'demo';
> LoginDetails.Username := 'demo';
> MS := TMemoryStream.Create;
> MS.Write(LoginDetails, SizeOf(LoginDetails));
> MS.Position := 0;
> Socket.SendStream(MS); { stream will be freed by socket }
> end;
> SERVER APPLICATION
> {Username/Password is checked from within the ServerClientConnect Event.}
> procedure TFServer.TCPserverClientConnect(Sender: TObject;
> Socket: TCustomWinSocket);
> type
> TLoginDetails = record
> Username: string[32];
> Password: string[32];
> end;
> var
> MsgBuf: string;
> MsgLen,LenReceived : integer;
> LoginDetails: TLoginDetails;
> begin
> MsgLen := Socket.ReceiveLength;
> if MsgLen = 0 then begin
> { INVALID LOGIN }
> Socket.Close;
> exit;
> end;
> if TCPServer.Socket.ActiveConnections >= 2 then begin
> { ONLY ALLOW ONE CONNECTION }
> Socket.Close;
> exit;
> end;
> TRY
> SetLength(MsgBuf, MsgLen);
> LenReceived := Socket.ReceiveBuf(MsgBuf[1], MsgLen);
> MsgBuf := Copy(MsgBuf, 1, LenReceived);
> if Length(MsgBuf) = SizeOf(LoginDetails) then begin { LOGINDETAILS = 66
> bytes}
> move(MsgBuf[1], LoginDetails, SizeOf(LoginDetails));
> Delete(MsgBuf, 1, SizeOf(LoginDetails));
> if LoginDetails.Password = LoginPassword then SendMsg(MSG_LOGIN_OK,
> 'Password Accepted', Socket)
> else begin
> SendMsg(MSG_LOGIN_FAIL, 'Invalid Password', Socket);
> socket.Close;
> exit;
> end;
> end else begin
> { INVALID LOGIN }
> Socket.Close;
> end;
> EXCEPT
> {ServerLog.Lines.Add('EXCEPTION LOGIN: '+SysErrorMessage(GetLastError));}
> Socket.Close;
> END;
> end;
--
Clairebear
http://www.corkyscave.com
2.0.0 Beardies
1.1.0 Garter
0.0.2 Corn
1.0.0 Pueblan Milk
1.0.0 Cali King
1.2.0 Red tail
1.1.0 Hogg Island
1.0.0 Royal
1.1.0 Borneo {*word*76}
1.1.0 Carpet
1.1.0 Western Hognose