Usage of idtcpserver

Source: Internet
Author: User

How can I obtain the Client IP address when I connect the client with idtcpserver?

IP: = athread. Connection. Binding. peerip;
Port: = athread. Connection. Binding. peerport;

Try to answer your questions:
Question 1:
Put the idtcpserver control in form1. Once a socket is connected, idtcpserver automatically creates a thread and
Establish a TCP/IP connection. We write our ownCodeIn this case
In the thread to complete the action we want?
Answer:
Once a socket connection exists, idtcpserver not only creates a thread, but also needs to save the thread to
Go to the thread list. Then, input the "per Thread" parameter in idtcpserver. onexecute,ProgramFrom
To retrieve the corresponding socket connection.

Question 2:
If we call the tform1.aaa function in onexecute, will this function cause synchronization problems,
For example, the number of logon users.
Answer:
Counting the number of logged-on users should not be handled in this event. In fact, you only need to read the thread list to know the result. Onexecute
Synchronization in is a work requirement of Indy. At the same time, customers must queue for processing. Therefore, in principle, no
This may cause synchronization problems. However, if the form you reference contains asynchronous variables, you should pay attention to possible synchronization problems.

I don't know if such an answer will satisfy you.

Do you not understand this as follows:
"Fform. idtcpclient1.connected then // idtcpclient1 in the fform main thread"
You can understand that idtcpclient1 is a member of the fform class instance. For your treceivethread
The fform class is referenced, and the fform class is considered as a member of the tthread class.
According to your description, this tfmclient is probably a tform class. At this time, unless you create
This tfmclient class, otherwise it may suffer, it is easy to cause a deadlock.

 

 

As mentioned, Indy is a multi-threaded control. When the server is connected, a thread is created for each customer,
Once a customer sends data, the srever onexecute event is activated. In onexecute
To identify which customer (that is, the thread) sends the request, the socket connection for this customer can return the service
.
The server first responds to the customer's connect event. Once connected, a connection is automatically established on the server.
Thread. This connection thread needs to be maintained by the server. The maximum number of Indy connection threads is no greater than 600,
If you are not enough to use 600 threads, you basically cannot use the Indy control.

Event handler for peer thread execution.

Property onexecute: tidserverthreadevent;

Description

Onexecute is an event handler for tidserverthreadevents. onexecute occurs when a tidpeerthread attempts to perform

Tidpeerthread. Run method. onexecute es athread as a parameter, representing the tidpeerthread thread that will be

Started.

Assign a tidserverthreadevent event handler procedure to onexecute to respond to the Event Notification.

Use commandhandlers and commandhandlersenabled to provide finer control over commands executed for a peer thread connection.
-----
Procedure tidlistenerthread. Run;
VaR
Liohandler: tidiohandler;
Lpeer: tidtcpserverconnection;
Lthread: tidpeerthread;
Begin
Try
If assigned (server) then begin // This is temporary code just to test one exception
While true do begin
Lthread: = nil;
Lpeer: = tidtcpserverconnection. Create (server );
Liohandler: = server. iohandler. Accept (binding. Handle, self );
If liohandler = nil then begin
Freeandnil (lpeer );
Stop;
Exit;
End
Else begin
Lthread: = tidpeerthread (server. threadmgr. getthread );
Lthread. fconnection: = lpeer;
Lthread. fconnection. iohandler: = liohandler;
Lthread. fconnection. ffreeiohandlerondisconnect: = true;
End;

// Lastrcvtimestamp: = now; // added for Session Timeout support
// Processingtimeout: = false;
If (server. maxconnections> 0) and // check maxconnections
Not tidthreadsafelist (server. threads). iscountlessthan (server. maxconnections)
Then begin
Server. threadmgr. activethreads. Remove (lthread );
Lpeer. writerfcreply (server. maxconnectionreply );
Lpeer. Disconnect;
Freeandnil (lthread); // This will free both thread and peer.
End else begin
Server. threads. Add (lthread); // APR
// Start peer thread
Lthread. Start;
Break;
End;
End;
End;
Except
On E: exception do begin
If assigned (lthread) then
Freeandnil (lthread );
Server. dolistenexception (self, e );
End;
End;
End;

As you can see from the source code above, each time the tcpserver listens for a connection, it creates an idpeerthread,
When this idpeerthread triggers the onexecute event, it will call idtcpserver1execute,
Therefore, it is no doubt that Indy supports multiple processes, and synchronization must be considered in idtcpserver1execute.

Indy idtcpserver, a large number of problems caused by abnormal client disconnection, please help us find the cause?

First, we define the next record and pointer.

Type
Tsimpleclient = record
ID: longint; // System ID
Utype: string; // GPRS, EMP, unknow
Name: string; // mobile phone number, name of the logon Operator
IP: string; // ip
Port: integer; // Port
Status: string; // null
Lasttime: integer; // Logon Time
Updatetime: integer; // Update Time
Hardware: string; // hardware type
Databacktime: integer; // monitoring time. If it times out, It is disconnected.
End;

Pclient = ^ tsimpleclient;

// The client information is recorded in the record when the customer creates a link
procedure tfrmnet. tcpserverconnect (athread: tidpeerthread);
var client: pclient;
begin
client: = new (pclient);

Client. ID: = gettickcount + random (1000 );
Client. utype: = 'guest ';
Client. IP: = athread. Connection. Socket. Binding. peerip;
Client. Port: = athread. Connection. Socket. Binding. peerport;
Client. lasttime: = gettickcount;
Client. updatetime: = client. lasttime;
Client. Status: = 'logged in ';
Client. Name: = 'guest ';
Client. Hardware: = gps_name_unknow;
Client. databacktime: = 3600; // monitoring period

Athread. Data: = pointer (client); <indicates the athread pointer.
End;

 

// Release from the client disconnection event
Procedure tfrmnet. tcpserverdisconnect (athread: tidpeerthread );
VaR client: pclient;
Begin
Client: = pointer (athread. data );
Athread. Data: = nil;
End;

// Process of communication with the customer
Procedure tfrmnet. tcpserverexecute (athread: tidpeerthread );
VaR C: pclient;
Begin
If (athread. Connection. Connected) and (not athread. Terminated) then
Begin
SSTR: = athread. Connection. currentreadbuffer;
End;
// Other processing codes that do not cause any endless loops or exceptions
End;

// Disable the previous TCP/IP link opened by the current user
// When the user is suddenly disconnected, the opened TCP/IP link may continue to be disconnected.
Procedure tfrmnet. clients_closeuplsbeforeconnect (curid: integer; sname: string );
VaR I: integer;
List: tlist;
Client: pclient;
Begin

List: = tcpserver. threads. locklist;
Try

For I: = 0 to list. Count-1 do begin
Try
Client: = pointer (tidpeerthread (list. items [I]). Data );
If client = nil then continue;

If (client. Name <> sname) or (client. ID = curid) or (client. utype <> 'gprs ') then continue;

If tidpeerthread (list. items [I]). Connection. connected then
Tidpeerthread (list. items [I]). Connection. Disconnect;

Except
Tidpeerthread (list. items [I]). Stop;
End;
End;

Finally
Tcpserver. threads. unlocklist;
End;
 
End;

 

The problem is:
A large number of terminal devices are connected to the server through TCP/IP because of the hardware and GPRS network.
The device often reconnects to the server like a power failure, but the previous connection is not disconnected (I don't know if it is the cause of GPRS)
Although the Program has made a decision to disconnect this abnormal connection,
However, the server program will often die for unknown reasons. Please help analyze the cause.

Please use idtcpclient and idtcpserver to send data to each other

========================================================== ==============
Unit unit1;

Interface

Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs, idbasecomponent, idcomponent, idtcpserver, stdctrls;

Type
Tform1 = Class (tform)
Memo1: tmemo;
Edit1: tedit;
Button1: tbutton;
Idtcpserver1: tidtcpserver;
Procedure idtcpserver1connect (athread: tidpeerthread );
Procedure idtcpserver1disconnect (athread: tidpeerthread );
Procedure button1click (Sender: tobject );
Procedure idtcpserver1execute (athread: tidpeerthread );
Private
{Private Declarations}
Public
{Public declarations}
End;

Type
Psocketthread = ^ tsocketthread;
Tsocketthread = record
Socketthread: tidpeerthread;
Next: psocketthread;
End;

VaR
Form1: tform1;
St_head, st_end: psocketthread;
St_count: integer;

Implementation

{$ R *. DFM}

procedure tform1.idtcpserver1connect (athread: tidpeerthread);
var
PST _: psocketthread;
begin
New (PST _);
PST _ ^. socketthread: = athread;
PST _ ^. next: = nil;
If st_count = 0 then
begin
st_head: = PST _;
st_end: = st_head;
end
else
begin
st_end ^. next: = PST _;
st_end: = PST _;
end;
st_count: = st_count + 1;
edit1.text: = inttostr (st_count);
end;

procedure tform1.idtcpserver1disconnect (athread: tidpeerthread);
var
PST _, pst_0: psocketthread;
begin
PST _: = st_head;
pst_0: = st_head;
while PST _ <> nil DO
begin
If PST _ ^. socketthread. threadid = athread. threadid then
begin
pst_0 ^. next: = PST _ ^. next;
dispose (PST _);
st_count: = ST_Count-1;
edit1.text: = inttostr (st_count );
end else
begin
pst_0: = PST _;
PST _: = PST _ ^. next;
end;

Procedure tform1.button1click (Sender: tobject );
VaR
Pst _: psocketthread;
Begin
Pst _: = st_head;
While PST _ <> nil do
Begin
Pst _ ^. socketthread. Connection. writeln ('to U' + inttostr (PST _ ^. socketthread. threadid) + # $ );
Pst _: = PST _ ^. Next;
End;
End;

Procedure tform1.idtcpserver1execute (athread: tidpeerthread );
Begin
Memo1.lines. Add (athread. Connection. readln );
End;

End.

 

================================== Client ======== ==================================
Unit unit1;

Interface

Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs, stdctrls, idbasecomponent, idcomponent, idtcpconnection,
Idtcpclient;

Type
Tform1 = Class (tform)
Idtcpclient1: tidtcpclient;
Button1: tbutton;
Memo1: tmemo;
Edit1: tedit;
Button2: tbutton;
Button3: tbutton;
Procedure button1click (Sender: tobject );
Procedure idtcpclient1connected (Sender: tobject );
Procedure button2click (Sender: tobject );
Procedure idtcpclient1disconnected (Sender: tobject );
Procedure formclose (Sender: tobject; var action: tcloseaction );
Procedure button3click (Sender: tobject );
Private
{Private Declarations}
Public
{Public declarations}
End;

VaR
Form1: tform1;
TD: DWORD;
Doread: Boolean;

Implementation

{$ R *. DFM}

Procedure readthread;
VaR
S: string;
Begin
Form1.memo1. lines. Add ('in in reading ...');
S: = form1.idtcpclient1. readln;
While doread do
Begin
S: = form1.idtcpclient1. readln;
Form1.memo1. lines. Add (s );
Sleep (100 );
End;
End;

Procedure tform1.button1click (Sender: tobject );
Begin
Idtcpclient1.connect (3000 );
Doread: = true;
Createthread (nil, 0, @ readthread, nil, 0, TD );
End;

Procedure tform1.idtcpclient1connected (Sender: tobject );
Begin
Memo1.lines. Clear;
Memo1.lines. Add ('connectedto Server ');
End;

Procedure tform1.button2click (Sender: tobject );
Begin
Idtcpclient1.writeln (edit1.text );
End;

Procedure tform1.idtcpclient1disconnected (Sender: tobject );
Begin
Exitthread (TD );
Memo1.lines. Add ('disconnectedfrom Server ');
End;

Procedure tform1.formclose (Sender: tobject; var action: tcloseaction );
Begin
Doread: = false;
Idtcpclient1.disconnect;
Exitthread (TD );
End;

Procedure tform1.button3click (Sender: tobject );
Begin
// Idtcpclient1.disconnect;
Doread: = false;
End;

End.

 

 

How can I solve the high CPU utilization problem when I use idtcpserver?

The main function of the program is to use idtcpserver to send data to the idtcpclient of each connection. I have tried two methods.
However, the CPU usage of the server program is very high and all resources are occupied. I tried to use application. processmessages.
However, the error message is invalid. I disabled all interface operations and it was useless. The error message remains unchanged even when no data is sent. I used idantifreeze, And I used idthreadmgrpool.

Useless,
Although the program can run normally, the CPU utilization is so high, it's unreasonable. Is there a problem with the processing logic of my program? Or are there other things you haven't considered or are well-configured?
There is a similar code for reference, or is there any other better method, simple functional requirements: as long as the data is sent from the server to each client in a single direction (do not consider using U

DP, do not consider using broadcast packets, because he needs to be able to run on the Internet)

Method 1: The server uses execute to send messages. The client establishes a thread to receive messages.
Procedure tcastproxy. tcpserverexecute (athread: tidpeerthread );
Begin
// Application. processmessages;
Try
Athread. Connection. writestream (tempclient. clientdata, true, true, 0 );
Tempclient. clientdata. Clear;
Except
On E: exception do begin
Athread. Connection. Disconnect;
End;
End;
End;

Procedure tcastproxy. tcpclientthreadrun (Sender: tidcustomthreadcomponent );
VaR
AData: tmemorystream;
Begin
AData: = tmemorystream. Create;
// Application. processmessages;
If assigned (aData) then begin
If tcpclient. connected then begin
// AData. Clear;
Try
Tcpclient. readstream (aData,-1, false );
//.........
Except
On E: exception do begin
Tcpclient. Disconnect;
End;
End;
End else begin
Try
Tcpclient. Connect (1, 1000 );
Except
On E: exception do
Statusbar. simpletext: = E. message;
End;
End;
End;
AData. Free;
End;

Method 2: The server uses a loop to send messages to each customer, and the client uses a thread to receive messages.
If tcpserver. Active then begin
Try
Threads: = tcpserver. threads. locklist;
For temp: = 0 to threads. Count-1 do begin
Try
AData. Position: = 0;
Tidpeerthread (threads [temp]). Connection. writestream
(AData, true, true, aData. size );
Except
On E: exception do
Tidpeerthread (threads [temp]). Connection. Disconnect;
End;
End;
Finally
Tcpserver. threads. unlocklist;
End;
End;

Haha, I fixed it myself.
Blame yourself for not providing good examples.

Long time, not remembering
It seems that a sleep (100) is added to the execute of the server. You can modify the 100 Statement by yourself, but you can modify the statement if it is greater than 18. That is to say, you have to take a break when sending data.

Try it first. If not, send your code to me.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.