Design a proxy server program with Delphi
From the "Tianji Network Learning Center" (Text / Wan Xue Yong) to develop serial communication software with delphi: First, use Windows communication API functions, the other is the Microsoft's MSCOMM control. Using the API to write serial communication programs more complicated, you need to master a large number of communication knowledge, and the advantage is that the function is more powerful, more widely applied, more suitable for more complex low-level communication programs. The use of MSCOMM controls is relatively simple, which has a wealth of attributes and events closely related to serial port communication, providing various operations for serial ports. I. Main attributes and events of MSCOMM controls (1) CommPort: Set or return serial port numbers, default is 1. (2) Setting: Set or return serial communication parameters, format is "baud rate, parity bit, data bit, stop bit". For example: mscomm1.setting: = '9600, n, 8, 1' (3) Portopen: Open or close the serial port, format is: mscomm1.portopen: = {True | false} (4) Inbuffersize: Set or return to receive The buffer size, the default is 1024 bytes. (5) InBufferCount: Returns the number of bytes waiting for the read in the receiving buffer, which can be cleaned by setting the attribute 0 to clear the receiving buffer. (6) Rthreshold: This property is a valve value that determines an ONCOMM event that is ComeVReceive when the number of bytes within the received buffer reaches or exceeds the value. (7) Sthreshold: This property is a valve value that determines an ONCOMM event that generates code COMEVSEND when the number of bytes within the buffer is less than this value. (8) Inputlen: Set or return the number of bytes read in the receiving buffer, setting the property to 0 means INPUT reads the content of the entire buffer. (9) INPUT: Reads a string of characters from the receive buffer. (10) Outbuffersize: Set or return the size of the send buffer, the default is 512 bytes. (11) OutbufferCount: Returns the number of bytes sent in the transmit buffer, which can be cleaned by setting the property of 0. (12) OUTPUT: Transfer a string of characters to the send buffer. If an error or event occurs during communication, an oncomm event is triggered, and the error type is reflected by the COMMEVENT property code, and different operations can be performed in the design of the communication program. The commevent property value is as follows: (1) comevsend: value is 1, the contents of the send buffer are less than the value specified by the Sthreshold. (2) comVReceive: The value of 2, the number of characters in the receiving buffer reaches the value specified by rtHResHold. (3) COMEVFRAME: The value is 1004, the hardware detects the frame error. (4) Comevrxover: The value is 1008, and the receive buffer overflows. (5) COMEVTXFULL: The value is 1010, and the transmission buffer overflows.
(6) Comevrxparity: The value is 1009, parity error. (7) COMEVEOF: The value is 7, and the file end (ASCII code is 26) characters in the receiving data. Second, the program sample cannot use the MSCOMM control in Delphi3.0, and the author uses Delphi5.0. The MSCOMM control is the OCX control in VB. First, you need to add it to Delphi, select the menu "Component" → "Import ActiveX Control", select "Microsoft Comm Control" in the "IMPORT ACTIVEX" page, click "Install" installation, After installation, the MSCOMM icon appears in the "ActiveX" component board, you can be used. It is important to note that the input and output attributes of the MSCOMM control in Object Inspector are invisible, but they still exist, the types of these two properties are Olevariant (OLE universal variables). Below is a sample (main part) of a receiver, you can improve according to actual needs. Place a MEMO control in the Form to display the received data, ComboBoX1 Select the communication parameter (Setting property value), and the ComboBox2 selects the serial port (CommPort property value), press button to start receiving data, press Button2 to stop receiving.
Procedure TForm1.FormCreate (Sender: Tobject); Begin Mscomm1.inbuffercount: = 0; // Clearing the receiving buffer MScomm1.inputlen: = 0; // INPUT Read the entire buffer content mscomm1.rthreshold: = 1; // The time to receive the character, an ONCOMM event end; procedure tForm1.Button1Click (sender: TOBJECT); begin mscomm1.settings: = comboBox1.text; if ComboBox2.text = 'com1' Ten // Assume only two cases of COM1 and COM2 Mscomm1.commport: = 1 else mscomm1.commport: = 2; mscomm1.portopen: = true; // Open the serial port mscomm1.dtrenable: = true; // Data terminal ready MSCOMM1.rtSenable: = true; // Request to send end ; procedure TForm1.Button2Click (Sender: TObject); begin Mscomm1.PortOpen: = false; // Close serial Mscomm1.DTREnable: = false; Mscomm1.RTSEnable: = false; end; procedure TForm1.MSComm1Comm (Sender: TObject); var recstr: Olevariant; begin if Mscomm1.CommEvent = 2 then begin recstr: = Mscomm1.Input; Memo1.text: = Memo1.Text recstr; end; end; // build the main window procedure TForm1.FormCreate (Sender: TObject); Begin service_enabled: = false; Timer2.enabled: = true; {window is created, open the timer} end; // PROCEDURE TFORM1.MMCLOSE (Sender: Tobject; Var) Action: tclosection; begin time; {Close timer = false; {Close Timer} if service_enabled life; {{{时 = 服务 服务 服务} 服务; // Exit program button procedure tFORM1.N01CLICK (Sender: TOBJECT Begin Form1.close; {Exit Program} END; // Once proxy service, Procedure TFORM1.SERVERSOCKET1LISTEN (SENDER: TOBJECT; SOCKET: TCUSTOMWINSOCKET); becomue service_enabled: = true; {正 服务 服务} n11.enabled: = False; n21.enabled: = true; end; // After connecting to the proxy server by the agent, establish a session and bind to the socket ... Procedure TFORM1.Serversocket1ClientConnect (Sender: Tobject; Socket: Tcustomwinsocket); Var i, j: integer; begin J: = - 1; for i: = 1 to sessions do {finding if there is a blank item} if not session [i-
1] .used and not session [i-1] .csocket.active the begin J: = i-1; {有, assign it} session [j] .used: = true; {{在}} Break; Else if not session [i-1] .used and session [i-1] .csocket.active the session [i-1] .csocket.act: = false; if j = -1 Then Begin {none, add one } J: = sessions; INC; SETLENGTH (session, sessions); session [j] .used: = true; {{在} session [j] .csocket: = tclientsocket.create (nil); session [j] .CSocket.OnConnect: = ClientSocket1Connect; session [j] .CSocket.OnDisconnect: = ClientSocket1Disconnect; session [j] .CSocket.OnError: = ClientSocket1Error; session [j] .CSocket.OnRead: = ClientSocket1Read; session [j ] .Csocket.onwrite: = clientsocket1write; session [j] .lookup: = false; end; session [j] .ss_handle: = socket.socketHandle; = Socket.socketHandle; {Save handle, implement binding} session [j] .Request: = false ; {No request} session [j] .client_connected: = true; {Client has connected} session [j] .remote_connected: = false; {remote unconnected} Edit1.Text: = INTOSTR (sessions); end; // When the agent is disconnected, Procedur E TForm1.Serversocket1Clientdisconnect (SENDER: TOBJECT; SOCKET: TCUSTomWinsocket); Var i, J, K: Integer; Begin for i: = 1 to sessions do if (session [i-1] .ss_handle = socket.socketHandle) And session [ I-1] .used the beginning [i-1] .client_connected: = false; {Client unconnected} if session [i-1] .remote_connected thession [i-1] .csocket.active: = false { If the remote is connected, disconnect it} else session [i-1] .USED: = false; {If both are disconnected, set the resource flag} Break; End; J: = sessions; k: = 0; For i: =
1 TO J DO {Statistical session There are several unused items at the end of the group} Begin if session; INC (K); end; if k> 0 Then {corrected session array, release the tail unused item} begin sessions: = sessions-k; setlength (session, sessions); end; edit1.text: = inttostr (sessions); end; // when a communication error occurs procedure TForm1.ServerSocket1ClientError (Sender: TObject; Socket: TCustomWinSocket; Errorevent: TerRorEvent; var errorcode: integer; var i, j, k: integer; begin for i: = 1 to sessions do if (session [i-1] .ss_handle = socket.sockethandle) And session [i-1] .Used the begin session [i-1] .client_connected: = false; {Client unconnected} if session [i-1] .Remote_Connected the session [i-1] .csocket.active: = false {If remote connection , Disconnect it} else session [i-1] .USED: = false; {If both are disconnected, set the resource flag} Break; end; j: = sessions; k: = 0; for i: = 1 to J Do Begin if session [J-I] .used the Break; Inc (k); End; IF K> 0 THEN BEGIN sessions: = sessions-k; setlength (session, sessions); end; edit1.text: = INTTOSTR (sessions); errorcode: = 0; END; // When the page is sent to the page request PR Ocedure TFORM1.SERVERSOCKET1CLIENTREAD (SENDER: TOBJECT; Socket: Tcustomwinsocket); VAR TMP, LINE, HOST: STRING; I, J, Port: Integer; Begin for i: = 1 to sessions do {Judgment Which session} if session [ I-1] .used and (session [i-1] .ss_handle = socket.sockethandle) THEN BEGIN session [i-1] .Request_str: = socket.ReceiveText; {Save Request Data} TMP: = session [i-1 ] .Request_str; {{Store to temporary variable} Memo1.Lines.Add (TMP); J: = POS (char (13) char (10), TMP); {a line flag} while j> 0 do {progressive scanning request Text, find the host address} begin line: = COPY (TMP, 1, J-1);
{Take a row} delete (TMP, 1, J 1); {Delete a line} J: = POS ('Host', Line); {Host Address Sign} IF J> 0 THEN Begin Delete (Line, 1, J 5); { Delete the previous invalid character} J: = POS (':', line); if j> 0 Then Begin Host: = Copy (Line, 1, J-1); Delete (Line, 1, J); Try Port: = StrtOINT (LINE); Except Port: = 80; End; END ELSE BEGIN HOST: = TRIM (LINE); {Get Host Address} Port: = 80; End; if Not session [i-1] .remote_Connected Then { The expedition has not been connected} Begin session [i-1] .Request: = true; {Setting data ready flag} session [i-1] .csocket.host: = host; {Settings Remote Host address} session [i-1] .Csocket.port: = port; {setting port} session [i-1] .csocket.active: = true; {Connection Remote Host} session [i-1] .lookingup: = true; {标}} session [i -1] .lookuptime: = 0; {Start Timing from 0} END ELSE {If the remote is connected, send request} session [i-1] .csocket.socket.sendtext (session [i-1] .Request_str); Break; {Stop scan request text} end; J: = POS (CHAR (13) Char (10), TMP); {Point Next} end; break; {Stop loop} END; // Procedure TFORM1.CLIENTSOCKET1CONNECT (Sender: Tobject; Socket) when connecting the remote host : Tcustomwinsocket; var i: integer; begin for i: = 1 to sessions do if (session [i-1] .csocket.socket.socketHandle = Socket.socketHandle) And session [i-1] .used
Then Begin session [i-1] .csocket.tag: = socket.socketHandle; session [i-1] .remote_connected: = true; {远程 主 连 连 标 标} session [i-1] .lookingup: = false; { Qing Gui} Break; End;
// Procedure TFORM1.CLIENTSOCKET1Disconnect (Sender: Tobject; Socket: Tcustomwinsocket); Var i, J, K: Integer; Begin for i: = 1 to sessions do if (session [i-1] .csocket .tag = socket.sockethandle) and session [i-1] .used the beginning [i-1] .remote_connected: = false; {未 未 连接} if not session [i-1] .client_connected thession [i -1] .USED: = false {If the client has disconnected, set the resource logo} else fork: = 1 to serversocket1.socket.activeConnections do if (Serversocket1.socket.connections [k-1]. SocketHandle = Session [I-1] .ss_handle) and session [i-1] .used the beginning; k-; close; break; end; break; end; j: = sessions; k: = 0 For i: = 1 to j Do Begin if session [ji] .used dam; INC (k); end; if k> 0 THEN {Correction session number} Begin sessions: = sessions-k; setlength (session, sessions ); End; edit1.text: = INTTOSTR (sessions); end; file: // When communication with remote host communication / procedure tform1.clientSocket1ERROR (Sender: Tobject; Socket: Tcustomwinsocket; ErrorEvent: TERROREVENT; VAR ERRORCODE: INTEGER; VAR I, J, K: Integer; Begin for i: = 1 to sessions do if (session [i-1] .csocket.tag = socket.socketHandle) and session [i-1] .Used kilocket.close; session [i-1] .remote_connected: = false; {未 未 未} if not session [i-1] .client_connected the session [i-1] .used: = false { The client has disconnected, then release the resource sign} else fork: = 1 to serversocket1.socket.activeConnections do if (Serversocket1.socket.connections [k-1]. SocketHandle = session [i-1] .ss_handle) and Session [i-1] .used the beginning.connections [k-1] .close;
End; j: = sessions; k: = 0; for i: = 1 to j Do Begin if session [ji] .used dam; inc (k); End; errorcode: = 0; if k> 0 Then {correction Session array} Begin sessions: = sessions-k; setlength (session, sessions); end; ed; ed; end; // Send a page to remote host Send Page Request Procedure TFORM1.CLIENTSOCKET1WRITE (Sender: Tobject; Socket) : Tcustomwinsocket; var i: integer; begin for i: = 1 to sessions do if (session [i-1] .csocket.tag = socket.sockethandle) And session [i-1] .used the beginning of session [i -1] .Request dam socket.sendtext (session [i-1] .Request_str); {If there is a request, send} session [i-1] .Request: = false; {清标} end; End; // Remote host Send page data Procedure TFORM1.CLIENTSOCKET1READ (Sender: Tobject; Socket: Tcustomwinsocket); VAR i, J: Integer; REC_BYTES: Integer; {Retrieved Data Block Length} REC_Buffer: Array [0. .2047] OF CHAR; {Back data block buffer} begin for i: = 1 to sessions do if (session [i-1] .csocket.tag = socket.sockethandle) and session [i-1] .used THEN BE GIN REC_BYTES: = Socket.ReceiveBuf (Rec_Buffer, 2048); {Receive Data} for J: = 1 To Serversocket1. Socket.ActiveConnections Do IF Serversocket1. Socket.connections [J-1]. SocketHandle = Session [i-1]. SS_HANDLE THEN BEGIN ServerSocket1.socket.connections [J-1] .sendbuf (R_Buffer, REC_BYTES); {Send Data} Break; End; Break; End; End; // "You can't find" Error message appears Procedure TFORM1 .Appexception; begin inchance (INVALIDREQUESTS); END; file: // Find remote host timing / procedure tform1.timer1timer (Sender: TOBJECT); VAR i, J: Integer; Begin FOR i: =