Delphi 5 a Simple Example for Tserversocket and Tclientsocket - delphi

provide an example in DELPHI 5 if is possible
lets say we have the follow code.A simple tclientsocket communicates with a tserver socket.
Everything works fine if requests from tclientsocket are coming after the process of data on event tserversocket1onReadClient.
But How i will bypass the problem when on the middle of process i am getting a new Request from socketclient1 and i havent finish yet my process?
do i have to Implement it in ServerType: stThreadBlocking
Do i have to Create a thread to Do the process?
is it a better way do this simple.
My tclientsocket string messages will not be larger than 255 chars.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ScktComp;
type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
Button1: TButton;
ServerSocket1: TServerSocket;
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure ServerSocket1ClientError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
with Serversocket1 do
begin
Active:=false;
ServerType:=stNonBlocking;
port:=5052;
Active:=true;
end;
with ClientSocket1 do
begin
active:=false;
port:=5052;
Address:='127.0.0.1';
host:='127.0.0.1';
active:=true;
end;
end;
procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
errorcode:=0;
end;
procedure TForm1.ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
errorcode:=0;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket);
var mydata:String;
begin
mydata:=socket.ReceiveText;
///Proceccing my data now
//Line 1
//Line 2
//Line 3
//Line 4 <---- ie. when i am proccessing line 4 a new Request from clientsocket1 arrives
//Line 5
end;
end.

The scenario you describe cannot happen. When the ServerSocket1ClientRead event handler is executing, it will not be called in a re-entrant fashion. Well, unless you were to call Application.ProcessMessages. So, don't do that!

Related

Delphi 6 Escape key not working

I'm experiencing a weird issue with trapping the escape key in our main application. I created a simple test form to see what might be going wrong, since pressing the escape key was previously working. So far, it's still not working and I'm unsure why.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure Button2KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure OnAppMessage(var Msg: TMsg; var Handled: Boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_KeyDown then
showmessage('MSG');
end;
procedure TForm1.Button1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = VK_ESCAPE then
showmessage('ESC');
end;
procedure TForm1.Button2KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = VK_ESCAPE then
showmessage('ESC');
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = vk_escape then
Button1Click(sender);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage('Button1Click');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := OnAppMessage;
button1.Cancel := True; // set at design time as well
self.KeyPreview := True; // set at design time as well
end;
end.
For some reason when pressing escape, it doesn't break on the point I placed in button1.OnKeyDown or even for the Application message WM_KEYDOWN -- all other keys break here. I tested my keyboard just to make sure the key was functioning and it's good.
Is there something that might be causing this or that I'm doing wrong?
Thanks.
Add this to your component's class:
procedure HandleDlgCode(var Msg:TMessage); message WM_GETDLGCODE;
and then in the implementation section:
procedure TComponentClass.HandleDlgCode(var Msg:TMessage);
var
M: PMsg;
begin
Msg.Result := DLGC_WANTALLKEYS or DLGC_WANTESCAPE or DLGC_WANTCHARS or DLGC_HASSETSEL;
if Msg.lParam <> 0 then
begin
M := PMsg(Msg.lParam);
case M.message of
WM_KEYESCAPE, WM_CHAR:
begin
Perform(M.message, M.wParam, M.lParam);
Msg.Result := Msg.Result or DLGC_WANTMESSAGE;
end;
end;
end
else
Msg.Result := Msg
end;
This is because you set the Cancel property for Button1 to True. Comment the line:
button1.Cancel := True;
and you will be able to catch Escape key. These wo ar mutualy exclusive.
Try rebooting first. It fixed the issue.

Send & receive files in Delphi

Hi I'm studying sockets on how to send and receive files, I'm using the component ServerSocket1 to do this I have the following code I found searching google.
the client
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
ClientSocket1: TClientSocket;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
Stream: TMemoryStream;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Address:= '127.0.0.1';
ClientSocket1.Port:= 2500;
ClientSocket1.Open;
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ShowMessage('Connected.. Now go load a file!');
end;
procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ShowMessage('Did you startup the server? I cannot find it!');
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Size: Integer;
begin
if OpenDialog1.Execute Then
begin
Stream.LoadFromFile(OpenDialog1.Filename);
Size:= Stream.Size;
ClientSocket1.Socket.SendBuf(Size,SizeOf(Size));
ClientSocket1.Socket.SendStream(Stream);
End;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Stream:= TMemoryStream.Create;
end;
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
S: String;
begin
S:= Socket.ReceiveText;
Socket.Close;
ShowMessage('Client: '+S);
end;
end.
the server
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
SaveDialog1: TSaveDialog;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1Listen(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private declarations }
Stream: TMemoryStream;
FSize: Integer;
writing: Boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Port:= 2500;
ServerSocket1.Active:= True;
Stream:= TMemoryStream.Create;
writing:= False;
end;
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ShowMessage('A client has connected');
end;
procedure TForm1.ServerSocket1Listen(Sender: TObject;
Socket: TCustomWinSocket);
begin
ShowMessage('I''m listening');
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
BytesReceived: Longint;
CopyBuffer: Pointer; { buffer for copying }
ChunkSize: Integer;
TempSize: Integer;
const
MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin
If FSize=0 then
begin
If Socket.ReceiveLength>SizeOf(TempSize) then
begin
Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
Stream.SetSize(TempSize);
FSize:= TempSize //Threadsafe code!
End;
End;
If (FSize>0) and not(writing) then
begin
GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
writing:= True;
While Socket.ReceiveLength>0 do
Begin
ChunkSize:= Socket.ReceiveLength;
If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
Dec(FSize,BytesReceived);
End;
If FSize=0 then
If SaveDialog1.Execute then
begin
If FileExists(SaveDialog1.Filename) then
DeleteFile(SaveDialog1.Filename);
Stream.SaveToFile(SaveDialog1.Filename);
Socket.SendText('File received!');
Stream.SetSize(0);
FSize:= 0;
End;
FreeMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
Writing:= False;
End;
end;
end.
The problem in this code that eh had is that I can only send one I can send a file because when I try to re-send other file errors throws me as 'Access violation at address' or 'Stream read error'.
that I can do to fix this code and you can send multiple files after each?
there is a reference of how to do it with indy sockets?
This is because memorystream used to open the file is not free. You have to free the stream variable before loading the next file to be sent.
I modified your code a bit and it is now working perfectly, I request various files and is ok.
the server
procedure TForm1.ServerClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
BytesReceived: Longint;
CopyBuffer: Pointer; { buffer for copying }
ChunkSize: Integer;
TempSize: Integer;
FileName: array [0..255] of char;
const
MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin
If FSize=0 then
begin
If Socket.ReceiveLength>SizeOf(TempSize) then
begin
Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
Socket.ReceiveBuf(FileName, sizeOf(FileName));
Save.FileName:= FileName; //I added
Stream:= TMemoryStream.Create;
Stream.SetSize(TempSize);
FSize:= TempSize; //Threadsafe code!
writing:= True;
End;
End;
If (FSize>0) and (writing) then
{before not(writing) -> because in big files, ServerClientRead is call more than one time and the transfer was stopped after the first call, but now it continues.}
begin
GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
While Socket.ReceiveLength>0 do
Begin
ChunkSize:= Socket.ReceiveLength;
If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
Dec(FSize,BytesReceived);
End;
FreeMem(CopyBuffer, MaxChunkSize); { free allocated buffer, now here }
If FSize
Client button click:
procedure TForm1.Button1Click(Sender: TObject);
var ms: TMemoryStream;
size: Integer;
FileName: array [0..255] of char;
begin
if Open.Execute then
begin
ms:= TMemoryStream.Create;
try
ms.LoadFromFile(open.FileName);
ms.Position:= 0;
Size:= MS.Size;
Client.Socket.SendBuf(Size,SizeOf(Size));
StrPLCopy(FileName, ExtractFileName(Open.FileName), High(FileName));
Client.Socket.SendBuf(FileName, SizeOf(FileName));
client.Socket.SendStream(ms);
except
ms.Free;
end;
end;
end;

Delphi socket error

Trying to understood how to use ServerSocket and ClientSocket in Delphi. I made a simple chat programm but after client sends first message this error apperas
(it happens during sending - just after server get's the message )
Windows socket error: Запрос на отправку или получение данных (when sending ona datagram socket using a sendto call)no adress was supplied (10057), on API 'getpeername'
Heres server code
unit Servert;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp;
type
TForm1 = class(TForm)
ServerSocket: TServerSocket;
PortLabel: TLabel;
Port: TEdit;
Protocol: TGroupBox;
mmoServer: TMemo;
btnStart: TButton;
btnStop: TButton;
btnClear: TButton;
btnEnd: TButton;
btnSend: TButton;
edtMsg: TEdit;
lblUser: TLabel;
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
procedure btnClearClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnEndClick(Sender: TObject);
procedure ServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure btnSendClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Usercount: Integer;
implementation
{$R *.dfm}
procedure TForm1.btnStartClick(Sender: TObject);
begin
ServerSocket.Port:=StrToInt(Port.Text);
ServerSocket.Active:=True;
btnStart.Enabled:=False;
btnStop.Enabled:=True;
mmoServer.Lines.Add('Status: started');
end;
procedure TForm1.btnStopClick(Sender: TObject);
begin
ServerSocket.Port:=StrToInt(Port.Text);
ServerSocket.Active:=False;
btnStart.Enabled:=True;
btnStop.Enabled:=False;
mmoServer.Lines.Add('Status: stopped');
end;
procedure TForm1.btnClearClick(Sender: TObject);
begin
mmoServer.Lines.Clear;
mmoServer.Lines.Add('Server 1.0');
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ServerSocket.Active:=False;
end;
procedure TForm1.btnEndClick(Sender: TObject);
begin
ServerSocket.Active:=False;
Application.Terminate;
end;
procedure TForm1.ServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoServer.Lines.Add('Status: Client ' + Socket.RemoteAddress + ' connected');
Inc(Usercount);
lblUser.Caption:= 'User:' + IntToStr(Usercount);
end;
procedure TForm1.ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoServer.Lines.Add('Status: Client ' + Socket.RemoteAddress + ' disconnected');
Dec(Usercount);
lblUser.Caption:= 'User:' + IntToStr(Usercount);
end;
procedure TForm1.ServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
mmoServer.Lines.Add('Status: Client ' + Socket.RemoteAddress + ' error:' + IntToStr(ErrorCode));
Dec(Usercount);
lblUser.Caption:= 'User:' + IntToStr(Usercount);
end;
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var i:Integer; strRec:AnsiString;
begin
strRec:=Socket.RemoteAddress + ': ' + Socket.ReceiveText;
mmoServer.Lines.Add(strRec);
for i:=0 to ServerSocket.Socket.ActiveConnections - 1 do begin
ServerSocket.Socket.Connections[i].SendText(strRec);
end;
end;
procedure TForm1.btnSendClick(Sender: TObject);
var i:Integer;
begin
for i:=0 to ServerSocket.Socket.ActiveConnections - 1 do
begin
ServerSocket.Socket.Connections[i].SendText('Ololo' + edtMsg.Text);
mmoServer.Lines.Add('Ololo' + edtMsg.Text);
end;
end;
end.
Here's client code
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;
type
TForm1 = class(TForm)
lblHost: TLabel;
edtHost: TEdit;
lblPort: TLabel;
edtPort: TEdit;
btnConnect: TButton;
btnDisconnect: TButton;
grp1: TGroupBox;
mmoClient: TMemo;
grpSend: TGroupBox;
mmoSend: TMemo;
btnSend: TButton;
ClientSocket: TClientSocket;
procedure ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure btnDisconnectClick(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure btnSendClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoClient.Lines.Add('Status: connected ' + Socket.RemoteAddress);
end;
procedure TForm1.btnDisconnectClick(Sender: TObject);
begin
ClientSocket.Host:=edtHost.Text;
ClientSocket.Port:=StrToInt(edtPort.Text);
ClientSocket.Active:=False;
btnConnect.Enabled:=True;
btnDisconnect.Enabled:=False;
end;
procedure TForm1.btnConnectClick(Sender: TObject);
begin
ClientSocket.Host:=edtHost.Text;
ClientSocket.Port:=StrToInt(edtPort.Text);
ClientSocket.Active:=True;
btnConnect.Enabled:=False;
btnDisconnect.Enabled:=True;
end;
procedure TForm1.ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoClient.Lines.Add('Status: disconnected ' + Socket.RemoteAddress)
end;
procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoClient.Lines.Add(Socket.ReceiveText);
end;
procedure TForm1.btnSendClick(Sender: TObject);
begin
ClientSocket.Socket.SendText(mmoSend.Text);
end;
end
.
i'm really sorry if i'm posting this late, but i solved this issue and you might not see it.
in the server-side, make sure that you send to the socket by index, example:
ServerSocket1.Socket.Connections[SocketIndex].SendText();
Don't forget the .Connections property.
Error code 10057 is WSAENOTCONN, and getpeername() is the API function that the Socket.RemoteAddress property getter uses internally. This means you tried to read the RemoteAddress property of a Socket that was no longer connected to the server.

Delphi local net app

Trying to learn how to make server-client apps and stuff like. I trying to draw circles(on mouse click) in all clients so this is how i trying to do that. But it's not working - no errors but form is empty. What i need to fix?
Client code
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, {Figure, Ball,} IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, ScktComp;
type
TForm1 = class(TForm)
Timer1: TTimer;
Button1: TButton;
ClientSocket: TClientSocket;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
public
{ Public declarations }
end;
var
Form1: TForm1;
f:boolean;
p:MyPoint;
s:MyPoint;
z:TCanvas;
obj: MyFigure;
pX, pY:Integer;
myBuf: array[1..32] of Integer;
dataBuf: array[1..32] of Integer;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Timer1.Enabled:=false;
Timer1.Interval:=5;
z:=Form1.Canvas;//TCanvas.Create;
Button1.Caption:='Пуск';
f:=false;
ClientSocket.Port:=1234;
ClientSocket.Active:= False;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if not f then
begin
Timer1.Enabled:=true;
Button1.Caption:='Стоп';
f:=not f;
end
else
begin
Timer1.Enabled:=false;
Button1.Caption:='Пуск';
ClientSocket.Active:= True;
f:=not f;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
//z.Lock;
//z.Brush.Color:=ClWhite;
//z.FillRect(Canvas.ClipRect);
//obj.Draw(z);
if ClientSocket.Active then
ClientSocket.Socket.ReceiveBuf(dataBuf, 32);
z.Brush.Color:=ClRed;
z.Ellipse(dataBuf[1] + 10, dataBuf[2] + 10,dataBuf[1] - 10, dataBuf[2] - 10);
//z.Unlock;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ClientSocket.Active := false;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
myBuf[1]:=X;
myBuf[2]:=Y;
if ClientSocket.Active then
ClientSocket.Socket.SendBuf(myBuf, 32);
end;
end.
Server
unit ServerProject;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
sBufer : array [1..32] of Integer;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Port:=1234;
ServerSocket1.Active := True;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ServerSocket1.Active := false;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
i:integer;
begin
for i := 0 to ServerSocket1.Socket.ActiveConnections-1 do
begin
with ServerSocket1.Socket.Connections[i] do
begin
ReceiveBuf(sBufer, 32);
end;
end;
end;
procedure TForm1.ServerSocket1ClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
var
i:integer;
begin
for i := 0 to ServerSocket1.Socket.ActiveConnections-1 do
begin
with ServerSocket1.Socket.Connections[i] do
begin
SendBuf(sBufer, 32);
end;
end;
end;
end.
Your painting code is in the wrong place and is painting to the wrong thing. In Windows programs you are meant to paint in response to a WM_PAINT message. You are not doing so. What's more, you have to paint on a device context that is provided by a call to BeginPaint.
The VCL wraps all those details up for you, but you still need to follow the rules. In your case I recommend that you add a TPaintBox component to your form. Then implement an OnPaint event handler for the paint box. Finally, whenever you wish to repaint the paint box, for example on a timer, call the Invalidate method of the paint box.
I suspect that you want your each new ellipse to be drawn in addition to the earlier drawn ellipses. In which case you are probably best served by drawing them to an off-screen bitmap first and then, when you come to paint to the paint box, draw that bitmap on the paint box. The point is that a window needs to be able to re-paint itself in its entirety. When you paint to a screen device, what you painted is lost the next time that window needs to be painted. So it's the responsibility of the application to be able to paint its entire self at any point, if it is asked.
More generally I urge you to stop using global variables. They will cause you no end of trouble. Prefer local variables wherever possible. If you need state to persist between different method calls, use member variables. The guiding principle is to use the narrowest scope possible.
Your current design uses a timer to poll for new data. That's a very poor approach. The most efficient and effective approach is to use synchronous blocking communication. Indy takes that approach. Windows sockets components instead tend to be used in an asynchronous mode. Irrespective of the relative merits of these two approaches, you should not be polling on a timer. If you do use asynchronous communication, then respond to new data by handling an event rather than polling.
Your program is currently trying to mix together GDI painting, and network communication. I suggest that you attempt to get on top of these concepts one at a time. Learn how to paint without the distraction of communication. Then when you have cracked painting, try to bring in the communication aspect.

TCP Client not receiving responses back from RTSP server

In Delphi XE2, I'm using the TTCPClient component to communicate with an RTSP server. After trial and error not getting a response back from the server, I switched the project to send HTTP requests via port 80 (instead of 554 for RTSP) and tried to send a request to a website (www.google.com specifically). I'm still not getting any response.
I have a TTCPClient component on the main form (Form1) called Client, a TMemo control called Log, a TEdit control called txtHost, and a TBitBtn control. Here's the relevant parts of the code:
Connecting to Server
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
if Client.Active then Client.Disconnect;
Client.RemoteHost:= txtHost.Text;
Client.RemotePort:= '80'; // '554';
Client.Connect;
end;
OnConnect Event Handler (HTTP)
procedure TForm1.ClientConnect(Sender: TObject);
var
S: String;
begin
Client.Sendln('GET / HTTP/1.0');
Client.SendLn('');
end;
OnConnect Event Handler (RTSP)
procedure TForm1.ClientConnect(Sender: TObject);
var
S: String;
begin
Client.SendLn('OPTIONS * RTSP/1.0');
Client.SendLn('CSeq:0');
Client.SendLn('');
end;
OnReceive Event Handler
procedure TForm1.ClientReceive(Sender: TObject; Buf: PAnsiChar;
var DataLen: Integer);
var
S, R: String;
begin
S:= Client.Receiveln;
while S <> '' do begin
R:= R+ S;
S:= Client.Receiveln;
end;
Log.Lines.Append('> RECEIVED ' + R);
end;
OnError Event Handler
procedure TForm1.ClientError(Sender: TObject; SocketError: Integer);
begin
Log.Lines.Append('> ERROR '+IntToStr(SocketError));
end;
The OnReceive event is never called, nothing is coming back from any Server I'm connecting to.
What am I doing wrong here?
References
These are some links which I'm referencing to:
http://effbot.org/zone/socket-intro.htm
http://www.ietf.org/rfc/rfc2326.txt
http://folk.uio.no/meccano/reflector/smallclient.html
http://www.samsungdforum.com/upload_files/files/guide/data/html/html_3/reference/rtsp_specification.html
The camera I'm working with is Grandstream GXV3601LL
UPDATE
I've concluded that the issue is with the RTSP server, and have asked a question on the forums on Grandstream's website. The code does work with other server connections.
This works for me, it depends if you are in blocking mode or not:
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls;
type
TForm1 = class(TForm)
IdTCPClient1: TIdTCPClient;
TcpClient1: TTcpClient;
Memo1: TMemo;
procedure TcpClient1Connect(Sender: TObject);
procedure TcpClient1Receive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
TcpClient1.BlockMode := bmBlocking;
TcpClient1.RemoteHost := 'www.google.com';
TcpClient1.RemotePort := '80';
TcpClient1.Connect;
end;
procedure TForm1.TcpClient1Connect(Sender: TObject);
var s : string;
begin
memo1.Lines.Add('connected');
TcpClient1.Sendln('GET /');
s := TcpClient1.Receiveln;
memo1.Lines.Add(S);
end;
end.
EDIT
here is a real world example with a RTSP server (youtube in this case)
I used Indy IdTcpClient
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Client: TIdTCPClient;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var s : string;
begin
Client.Host := 'v5.cache6.c.youtube.com';
Client.Port := 554;
Client.Connect;
Client.IOHandler.Writeln('OPTIONS * RTSP/1.0');
Client.IOHandler.Writeln('CSeq: 1');
Client.IOHandler.Writeln('');
s := Client.IOHandler.ReadLn;
Memo1.Lines.Add(s);
s := Client.IOHandler.ReadLn;
Memo1.Lines.Add(s);
end;
end.
The reason the OnReceive event is not called is because TTCPClient is NOT an asynchronous component, like you are trying to treat it. The OnReceive event DOES NOT work the same way as the old TClientSocket.OnRead event. The OnReceive event is called inside of the ReceiveBuf() method only (ReceiveLn() calls ReceiveBuf() internally). The data that is passed to the OnReceive event is the same data that the ReceiveBuf() method returns on output. You have a catch-22 situation - you are waiting for the OnReceive event before calling ReceiveLn(), but OnReceive will not be triggered until you call ReceiveLn() first. If you want to use TTCPClient asynchronously, you will have to call its ReceiveLn() method periodically, either in a timer or worker thread, NOT inside the OnReceive event.
The TTCPClient component is part of the old CLX framework for Kylix. It is not part of the VCL, or even FireMonkey, and should not be used anymore. Either use the old TClientSocket component (which is deprecated but still available), or change to another component library, such as Indy.

Resources