2005. január 15., szombat

Making an application a TCP/IP Client (with sample code)...


Problem/Question/Abstract:

Connecting to a TCP/IP server from a Delphi Client

Answer:

This article is a continuation of my previous article "Making an application a TCP/IP Client" intended to demonstrate how we can use the TclientSocket component in Delphi as a TCP/IP client against any TCP/IP server. The server could be written in Delphi using TserverSocket component or any piece of code that acts as a TCP/IP server. In my case, I’m interacting with a Java code acts as a TCP/IP server.

In my project, I’m just sending a bunch of bytes to that Java server and the Java server reads the bytes and doing some tasks sending a different bunch of bytes as response to the Delphi Client.

In my last article (Making an application a TCP/IP Client), I explained the problem I faced and a solution I found for that.

In this article, let me give some sample code I used in that project since some people asked me to send the source code for this socket communication by sending separate e-mails. I appreciate them for their interest. Here U Go!! Enjoy!!!

My project uses nearly nine forms and all the forms need to interact with the Java server at least once. So I added a DataModule and put a TClientSocket Component there:

The following is the code for that:

unit DataMod;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ScktComp, OleServer;

type
  TdmDataModule = class(TDataModule)
    csClientSocket: TClientSocket;
    procedure csClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure csClientSocketRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private declarations }
    pub
      lic
      FWaiting: boolean;
    { Public declarations }
  end;

var
  dmDataModule: TdmDataModule;

implementation

{$R *.DFM}

procedure TdmDataModule.csClientSocketRead(Sender: TObject;
  Socket: TCustomWinSocket);
//Reading data back from server thro socket
var
  Buffer: array[0..4095] of char;
  BytesReceived: integer;
  MemoryStream: TMemoryStream;
begin
  while FWaiting do
  begin
    MemoryStream := TMemoryStream.Create;
    try
      //This time delay depends on the network traffic and also you can put the
                        //time delay between reads
      //I've just put some 200 milliseconds for my application before it
                        //starts reading from the server.
      Sleep(200);
      while True do
      begin
        BytesReceived := Socket.ReceiveBuf(Buffer, SizeOf(Buffer));
        if (BytesReceived <= 0) then
          Break
        else
        begin
          MemoryStream.Write(Buffer, BytesReceived);
        end;
      end;

      FWaiting := False;

      MemoryStream.Position := 0;

      //XMLResponse is a global stringlist i'm using in my application to convert
                        //the bytes received into string
      //You can use other ways to get the contents of a memorystream
      XMLResponse.LoadFromStream(MemoryStream);
    finally
      MemoryStream.Free;
    end;
  end;
end;

procedure TdmDataModule.csClientSocketError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
{Whenever you get a specific type of error while running the client you will be given a messagedlg showing that the error has occured; at that time you have to check whether the server is running correctly or not and if needed make the server run properly and then say OK.
Then csClientSocket.Open will try to reconnect to the server. So at this time if some transaction is in the middle you have to send the same stuff again after reconnecting.}
begin
  case ErrorEvent of
    eeGeneral:
      begin
        if MessageDlg('Error Connecting to Java server! ' + #13 +
          'Check the server status and try again!!', mtInformation, [mbOk], 0) = mrOk
          then
          csClientSocket.Open
      end;
    eeConnect:
      begin
        if MessageDlg('Error Connecting to Java server? ' + #13 +
          'Check the server status and try again!!', mtInformation, [mbOk], 0) = mrOk
          then
          csClientSocket.Open
      end;
    eeSend:
      begin
        if MessageDlg('Error Connecting to Java server? ' + #13 +
          'Check the server status and try again!!', mtInformation, [mbOk], 0) = mrOk
          then
          csClientSocket.Open
      end;
    eeReceive:
      begin
        if MessageDlg('Error Connecting to Java server? ' + #13 +
          'Check the server status and try again!!', mtInformation, [mbOk], 0) = mrOk
          then
          csClientSocket.Open
      end;
    eeAccept:
      begin
        if MessageDlg('Error Connecting to Java server? ' + #13 +
          'Check the server status and try again!!', mtInformation, [mbOk], 0) = mrOk
          then
          csClientSocket.Open
      end;
  end;
end;

procedure TdmDataModule.DataModuleDestroy(Sender: TObject);
begin
  //Closing the socket connection
  csClientSocket.Close;
end;

end.

Once you are done with the datamodule, you can include this datamodule in units wherever you need to interact with the server thereby you can avoid writing code to read data back from the server in various places of the project.

You can set the Host/Address and Port Number of the server to communicate at runtime through the runtime parameters.(I assume Delphi people aware of that runtime parameters)

Then in the project's main form's formcreate event; write the following code to connect to the server. i.e setting the IP address and Port Number of the server in the TClientSocket component and set Active to true.

//Connecting to the Java server on a particular port
try
  with dmDataModule.csClientSocket do
  begin
    if Active then
      Active := False;

    //Getting the Address or Host Name of the server through the runtime parameters
    Host := ParamStr(1);
    //Getting the Port Number of the server at which the server listens through the runtime parameters
    Port := StrToInt(ParamStr(2));
    //Making the connection active
    Active := True;
  end;
except on ESocketError do
  begin
    MessageDlg('Unable to Connect to Java Server ' + #13 + 'Please Try Again!',
      mtInformation, [mbOk], 0);
    exit;
  end;
end;

Once you are connected to the server, you can use either the TClientSocket's sendtext or sendstream method to send the data to the server.

for example:

procedure Send;
begin
  //Checking whether the socket connection is ready or not
//If not , the error handling part of the TClientSocket will be activated
  if csClientSocket.Active then
  begin
    //Sending the text through the socket connection
    csClientSocket.Socket.SendText('The string to send');

    //Setting a flag to wait until the server sends the response back
    dmDataModule.FWaiting := True;
    while dmDataModule.FWaiting then
      Application.ProcessMessages;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése