Summary of TCP-socket-disconnection

Source: Internet
Author: User
The server and client directly using socket are similar to the program. In actual use, it is often "dropped", but the program does not know, and many solutions have been found, I used it all at the end. Here is a summary.

1: set its avalie active timer during connection.

Type
Tcp_keepalive = record
Onoff: Cardinal;
KeepAliveTime: Cardinal;
Keepaliveinterval: Cardinal;
End;

Procedure tfrm_client.sck_mainconnect (Sender: tobject;
Socket: tcustomwinsocket );
Var val: tcp_keepalive;
RET: DWORD;
Begin
Inherited;
Try
Val. Onoff: = 1;
Val. KeepAliveTime: = 1000*60*60*24; // 24 hours
Val. keepaliveinterval: = 100;
RET: = wsaioctl (socket. sockethandle, ioc_in or ioc_vendor or 4,
@ Val, sizeof (VAL), nil, 0, @ ret, nil, nil)
Finally
Showinfo ('already connected to the server. tcp_keepalive timer '+ inttostr (Val. KeepAliveTime) +' result: '+ inttostr (RET ));
End;
End;

The meaning is clear at a glance.

2:

Procedure tfrm_client.sck_mainerror (Sender: tobject;
Socket: tcustomwinsocket; errorevent: terrorevent;
VaR errorcode: integer );
VaR ncode: Cardinal;
Begin
Inherited;
Showinfo ('| [Error] error:' + inttostr (errorcode) + '; automatic reconnection:' + booltostr (laskforreconnect,
True ));
Ncode: = errorcode; // getlasterror;
Errorcode: = 0;
// If an error occurs, close it to trigger the disconnection event.
If (ncode = econnaborted) // 10053 econnaborted wsaeconnaborted
Or (ncode = enetdown) // 10050 enetdown
Or (ncode = etimedout) // 10060
Or (ncode = econnrefused) // 10061
/Or (ncode = ehostunreach) // 10065
Then begin
If laskforreconnect and (not linreconnecting) then
Timer_reconnect.enabled: = true; // reconnectserver;
If not linreconnecting then begin
Sck_main.active: = false;
Sck_main.close; // reconnectserver and (not sck_main.active)
End;
Showinfo ('
Connection status: '+ booltostr (sck_main.active, true) +'; reconnection settings: '+ booltostr (laskforreconnect, true) +'; reconnection status: '+ booltostr (timer_reconnect.enabled, true ));
End;
End;
// Disconnect. When disconnected, the system automatically tries to connect again.
Procedure tfrm_client.sck_maindisconnect (Sender: tobject; socket:
Tcustomwinsocket );
Begin
Inherited;
If (not laskforreconnect) or (linreconnecting) Then exit;
Timer_reconnect.enabled: = true; // reconnectserver;
End;
// Reconnect
Function tfrm_client.reconnectserver: Boolean;
Const Nmax = 6;
VaR qry: tadoquery; L, L2: Boolean; I: integer; s: string;
Begin
Result: = false; I: = 1; if not laskforreconnect then exit;
L: = frm_mdi.asysconfig.lautologon;
Qry: = nil;
With sck_main do
Try
If not lincreatting then // or (not lloginok)
Try
If not laskforreconnect then exit;
Sck_main.socket.disconnect (sck_main.socket.handle );
Sck_main.close;
If l then begin
Showinfo ('disconnected, start to automatically reconnect to the server, the maximum number of retries ['+ inttostr (Nmax) +']... ');
& NSP; I: = 1; // try to reconnect three times
While (not sck_main.active) and (I <= Nmax) Do
Try
If not laskforreconnect then break;
Showinfo ('
* Try to automatically reconnect ['+ inttostr (I) +'/'+ inttostr (Nmax) +']... ');
Sck_main.open;
Delay (2000 );
L2: = sck_main.active;
// Connecttoserver (sck_main, txt_svrip.text,
Strtointdef (txt_svrport.text, 65180 ));
If not L2 then delay (1000); // sck_main.active
INC (I );
Except
On X: exception do;
End;
End;
//
Except
On X: exception do;
End;
Finally
Lloginok: = sck_main.active;
If not lloginok then begin
Showinfo ('the connection to the server has been disconnected and is trying to reconnect ');
Lbl_move.caption: = 'disconnected, trying to reconnect ';
End;
Result: = lloginok;
S: = 'failed ';
If lloginok then
Try
S: = '[th' + inttostr (I) + 'retry successful]';
Qry: = tadoquery. Create (Self );
Qry. Connection: = dmain. conn_main;
Clsaskfornewmessages (sck_main.socket, qry );
Finally
If assigned (qry) Then qry. Free;
End;
If l then showinfo ('disconnection reconnection result: '+ S );
End;
End;

Procedure tfrm_client.timer_reconnecttimer (Sender: tobject );
VaR MSG: _ msgidle;
Begin
Inherited;
Try
// Exit if the connection is established or the user does not require automatic Reconnection
Showinfo ('[# timer_reconnecttimer] automatic reconnection due to disconnection. Connection status: '+ booltostr (sck_main.active, true) +'; reconnection settings: '+ booltostr (laskforreconnect, true) +'; reconnection status: '+ booltostr (timer_reconnect.enabled, true ));
If (sck_main.active) or (not laskforreconnect) Then exit;
//
Linreconnecting: = true; // The connection is in progress.
Timer_reconnect.enabled: = false;
Timer_reconnect.enabled: = (not reconnectserver) and
Laskforreconnect; // The Connection stops.
//
Finally
Linreconnecting: = false;
End;
End;

3: Server. The sendmessage method is used to send messages. When an error is added to the socket, the system directly considers the request to be disconnected when a 10053 error occurs.

// Send chat Information
Function sendmessage (socket: tcustomwinsocket; ntype: integer;
Pmessage: pointer): Boolean;
Const sfile = 'd: \ aa.txt ';
VaR TP: _ msghead; Buf, PMSG, P: pbyte; F, M, hbuf: thandle;
Polderrorevent: tsocketerrorevent;
S: string; N, I, nlen, nmsglen: integer;
Begin
Result: = false; Buf: = nil; M: = 0;
If lglobalterminate then exit;
//
Try
Polderrorevent: = nil;
If assigned (psocketerrprocedure) then begin
Polderrorevent: = socket. onerrorevent;
Socket. onerrorevent: = psocketerrprocedure;
End;
Try
If not socket. connected then raise
Exception. Create ('Connection not opened or nonexistent ');
//
TP. msgtype: = ntype;
Nmsglen: = getmessagetypelen (ntype );
If nmsglen <0 Then exit;
TP. nbagsize: = sizeof (TP) + nmsglen;
TP. version. dwmajorversion: = frm_mdi.version.dwmajorversion; // 1
TP. version. dwminorversion: = frm_mdi.version.dwminorversion; // 0
//
Nlen: = nmsglen + sizeof (TP) + 0;
// Allocate the memory area and the replication header globalalloc (gmem_moveable, N + sizeof (TP ));
Hbuf: = globalalloc (gmem_moveable + gmem_share, nlen );
Buf: = globallock (hbuf); // getmem (BUF, nlen );
Fillchar (BUF ^, nlen, #0 );
Copymemory (BUF, @ TP, sizeof (TP); // strcopy (BUF, @ TP );
// Copy the content to all the memory areas
If (nmsglen <> 0) and (pmessage <> nil) then begin
N: = INTEGER (BUF) + sizeof (TP );
P: = PTR (N );
Copymemory (p, pmessage, nmsglen); // strlcopy (p, pmessage,
Nmsglen); // copymemor (p, pmessage, nmsglen );
End;
// Send, retry n times, up to 150 ms
N: =-1; I: = 1;
While (n =-1) and (I <= 5) Do begin
If lglobalterminate or (not socket. Connected) Then break;
N: = socket. sendbuf (BUF ^, nlen );
If n =-1 then delay (10 * I); // If the socket has no space, resend it after waiting
INC (I );
End;
//
Result: = lglobalterminate or (n>-1 );
Except
On X: exception do begin
S: = '[sendmessage] An error occurred while sending the message! Type = '+ inttostr (ntype) + #13 + #10 +'
'+ X. message;
// If assigned (BUF) Then freemem (BUF );
Insshowinfo (s );
Raise esocketerror. Create (s );
End;
End;
Finally
If assigned (polderrorevent) Then socket. onerrorevent: = polderrorevent;
If assigned (BUF) then begin
Globalunlock (hbuf );
Globalfree (hbuf );
End;
End;
End;
// When the server is initialized:

Psocketerrprocedure: = defaultsocketerrprocedure;

// Handle socket errors
Procedure tfrm_service.defasocketerrprocedure (Sender: tobject; socket:
Tcustomwinsocket;
Errorevent: terrorevent; var errorcode: integer );
VaR ncode: integer;
Begin
Inherited; ncode: = errorcode;
// If an error occurs, disable
If ncodes = 10053 then begin
Socket. close;
Raise exception. Create ('the client is disconnected! ');
End;
End;

4: Heartbeat packet. This is the most effective heartbeat packet. It is like a heartbeat packet. The interval of a heartbeat event will trigger an error.

// Keep the connection and heartbeat Packet
Procedure tfrm_client.timer_keepconnecttimer (Sender: tobject );
VaR MSG: _ msgidle; H: tsocket; N: integer; L: Boolean;
Begin
Inherited;
If (not lloginok) or (linreconnecting) Then exit;
L: = false;
Try
If lglobalterminate then exit;
Timer_keepconnect.enabled: = false;
//
// Fillchar (msg. scomment, length (msg. scomment), #0 );
MSG. version. dwmajorversion: = frm_mdi.version.dwmajorversion;
MSG. version. dwminorversion: = frm_mdi.version.dwminorversion;
MSG. ntickcount: = 0; // gettickcount;
MSG. nhandle: = 0; // socket. Handle;
MSG. scomment: = 'Hello! Please feel free to contact us! '; // Scomment;
If not sendmessage (sck_main.socket, msgtypeidle, @ MSG) then;
//
// Sendidlemsg (sck_main.socket );
{N: = timer_keepconnect.interval;
H: = sck_main.socket.sockethandle;
Waitfordata (n-300 );}
L: = true;
Finally
Timer_keepconnect.enabled: = true;
Showinfo ('send Server Message idle' + inttostr (timer_keepconnect.interval) + ', result:' + booltostr (L, true) + '...');
End;
End;

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.