Einzelnen Beitrag anzeigen

winx

Registriert seit: 14. Jun 2005
265 Beiträge
 

TCP IP Server Problem, wer kann mir helfen?

  Alt 7. Jun 2006, 08:52
Guten Morgen,

ich hab mir einen kleinen Server aufgesetzt, der asynchron Daten von Clients empfangen kann.
Nur hab ich jetzt zwei Probleme:

1. Wie kann ich den einmal gestarteten Server wieder stoppen??? bekomm bei meinem
versuch (ButtonStopClick) immer die eine InvalidOperationException "AcceptCallback"

2. Wie bekommt mein Server mit, wenn sich ein angemeldeter Client mit ClientSocket.Shutdown(SocketShutdown.Both);
abmeldet??

Der Code meines Servers sieht so aus:

Delphi-Quellcode:

unit ServerMainFormManager;

interface

uses
 ...


type

  TServerMainFormManager = class
  private
    m_mainForm : TServerMainForm;
    m_socketListen : Socket;
    m_socketAccept : Socket;
    m_Backlog : integer;
    m_WorkerCallback : AsyncCallback;
    Logger : ILog;
    m_CommandCompleteEvent : TCommandCompleteEventHandler;
    m_currentCommandString : string;
    m_currentCommandStringLocked : boolean;
    m_SendCommandAnswer : string;

    procedure acceptCallback(asyncResult : IAsyncResult);
    procedure onDataReceived(asyncResult : IAsyncResult);
    procedure waitForData(pSocket : Socket);
    procedure processData(newChar : string);

    //Events vom Formular
    procedure ButtonStartClicked(Sender: TObject; Args: EventArgs);
    procedure ButtonSendClicked(Sender: TObject; Args: EventArgs);
    procedure ButtonStopClicked(Sender: TObject; Args: EventArgs);

    //Events
    procedure removeCommandCompleteEvent(event : TCommandCompleteEventHandler);
    procedure addCommandCompleteEvent(event : TCommandCompleteEventHandler);

    function getCurrentCommandString: string;

  public

    property ReceivedCommandString : string read getCurrentCommandString;
    property CommandCompleteEventHandler : TCommandCompleteEventHandler add addCommandCompleteEvent remove removeCommandCompleteEvent;

    constructor Create;
    procedure start();
    procedure SendCommandAnswer(answer:string);

  end;

implementation


{$REGION 'Constructor'}
constructor TServerMainFormManager.Create;
begin
  inherited Create;
  Logger := LogManager.GetLogger('TServerMainFormManager');
  XmlConfigurator.Configure(FileInfo.Create('LogConfig.xml'));
  m_mainForm := TServerMainForm.Create();
  Include(m_mainForm.ButtonStart.Click,ButtonStartClicked);
  Include(m_mainForm.ButtonSend.Click,ButtonSendClicked);
  Include(m_mainForm.ButtonStopServer.Click,ButtonStopClicked);
  m_Backlog := 1;
end;



function TServerMainFormManager.getCurrentCommandString: string;
begin

  //Zuerst den String Locken
  Result := m_currentCommandString;

end;

{$ENDREGION}



{$REGION 'Mainform Events'}
procedure TServerMainFormManager.ButtonStartClicked(Sender: TObject;Args: EventArgs);
var serverPort : integer;
begin

  try

    //einen neuen socket erzeugen
    m_socketListen := Socket.Create(AddressFamily.InterNetwork,
                                    SocketType.Stream,
                                    ProtocolType.Tcp);

    Logger.Debug('New Socket created, Port: '+m_mainForm.NumericUpDownPort.Value.ToString());

    //Port auslesen
    serverPort := Convert.ToInt32(m_mainForm.NumericUpDownPort.Value);
    m_socketListen.Bind(IPEndPoint.Create(IPAddress.Any,serverPort));
    Logger.Debug('Socket Bind');


    //Das Listening starten
    m_socketListen.Listen(m_Backlog);
    Logger.Debug('Socket listening');

    //Rückruf für jeden Clienten
    m_socketListen.BeginAccept(acceptCallback,nil);
    Logger.Debug('Socket waits for Clients');

    if (m_socketListen.Connected) then
      Logger.Debug('Connected');

    m_mainForm.ButtonStart.Enabled := false;
    m_mainForm.ButtonStoPServer.Enabled := true;
    m_mainForm.NumericUpDownPort.Enabled := false;

  except
    on E:SocketException do begin
       Logger.Error(E.Message);
    end;
  end;


end;



procedure TServerMainFormManager.ButtonStopClicked(Sender: TObject;
  Args: EventArgs);
begin

   try

    if assigned(m_socketAccept) and (m_socketAccept.Connected) then
      m_socketAccept.Shutdown(SocketShutdown.Both);

    if assigned(m_socketListen) and m_socketListen.Connected then begin

      m_socketListen.Shutdown(SocketShutdown.Both);
    end;


    m_socketListen.Close();

    m_mainForm.ButtonStart.Enabled := true;
    m_mainForm.ButtonStoPServer.Enabled := false;
    m_mainForm.NumericUpDownPort.Enabled := true;


  except
    on E:SocketException do begin
       Logger.Error(E.Message);
    end;
  end;
end;



procedure TServerMainFormManager.ButtonSendClicked(Sender: TObject;Args: EventArgs);
var objData : TObject;
    byteData : array of byte;
begin

  try

    //Sende Daten an den Client
    Logger.Debug('Send Data to Client...');
    objData := m_mainForm.TextBoxSend.Text;
    byteData := System.Text.Encoding.ASCII.GetBytes(objData.ToString());
    m_socketAccept.Send(byteData);
    Logger.Debug('Data send to Client successful');

  except
    on E:Exception do
      Logger.Error(E.Message);
  end;


end;





{$ENDREGION}



{$REGION 'Private Functions'}
procedure TServerMainFormManager.removeCommandCompleteEvent(event: TCommandCompleteEventHandler);
begin
  m_CommandCompleteEvent := TCommandCompleteEventHandler(Delegate.Remove(@m_CommandCompleteEvent,@event));
end;



procedure TServerMainFormManager.addCommandCompleteEvent(event : TCommandCompleteEventHandler);
begin
  m_CommandCompleteEvent := TCommandCompleteEventHandler(Delegate.Combine(@m_CommandCompleteEvent,@event));
end;

{$ENDREGION}



procedure TServerMainFormManager.start;
begin
  m_mainForm.ShowDialog();
end;



procedure TServerMainFormManager.acceptCallback(asyncResult: IAsyncResult);
begin

  try

      //Callback
      Logger.Debug('Callback');
      m_socketAccept := m_socketListen.EndAccept(asyncResult);
      waitForData(m_socketAccept);

  except
    on E:SocketException do
      Logger.Error(E.Message);
  end;

end;



procedure TServerMainFormManager.waitForData(pSocket: Socket);
var socPkt : TSocketPacket;
begin

  try

    if not assigned(m_WorkerCallback) then begin
      m_WorkerCallback := ondataReceived;
    end;


     socPkt := TSocketPacket.Create();
     socPkt.socket := pSocket;

     //now start to listen for data
     Logger.Debug('Listening for any data...');
     pSocket.BeginReceive(socPkt.dataBuffer,
                           0,
                           length(socPkt.databuffer),
                           SocketFlags.None,
                           m_WorkerCallback,
                           socPkt);

  except
    on E:Exception do
      Logger.Error(E.Message);
  end;

end;



procedure TServerMainFormManager.onDataReceived(asyncResult: IAsyncResult);
var theSockID : TSocketPacket;
    iRx, charLen : integer;
    dec : Decoder;
    chars : array of char;
    szData : string;
begin

  try

    theSockID := TSocketPacket(asyncResult.AsyncState);

    
    //Empfange die Daten
    Logger.Debug('Receive Data');

    iRx := theSockID.socket.EndReceive(asyncResult);
    SetLength(chars,iRx+1);
    dec := System.Text.Encoding.ASCII.GetDecoder();

    charLen := dec.GetChars(theSockID.dataBuffer, 0, iRx, chars, 0);

    szData := string(chars);
    m_mainForm.TextBoxReceived.Text := m_mainForm.TextBoxReceived.Text + szData;

    //Die Daten werden verarbeitet
    processData(szData);

    Logger.Debug(m_currentCommandString);
    waitForData(m_socketAccept);

  except
    on E:ObjectDisposedException do
      Logger.Debug('OnDataReceived: Socket has been closed');
    on E: SocketException do
      Logger.Error(E.Message);
  end;

end;



procedure TServerMainFormManager.processData(newChar: string);
begin
  ...
end;



procedure TServerMainFormManager.SendCommandAnswer(answer: string);
begin
  ...
end;

end.
  Mit Zitat antworten Zitat