AJ_Oldendorf 0 Posted yesterday at 07:31 AM Hello together, actual I use nsoftware with TCPIP. I have a application as Server and one application as client. Clients can be in network more than one pc (maximum 15 different pcs with one client application). My server wait for a connect from one client and when client don't disconnect they send everytime data to the client. The transfer rate from server to client is ~80-90 different messages per second with different length (from 20 bytes to 60000 bytes) to each client as TBytes with 8 fix bytes at every end as EndOfLine terminator. Client receive data as TBytes with information if EndOfLine is True or not. If not, i collect the data in DataIn-event of client till EndOfLine is received. Than I know the complete message block. The transfer rate from client to server is ~20 different messages per second with different length (from 20 bytes to 60000 bytes) to server as TBytes with 8 fix bytes at every end as EndOfLine terminator. Server receive data as TBytes with information if EndOfLine is True or not. If not, i collect the data in DataIn-event of server till EndOfLine is received. Than I know the complete message block. This works with nsoftware ^^ Now I'm thinking about to change to ICS and have some questions. At first, is my above-mentioned task possible with ICS? In demo application I saw only, that Strings are send and receive and EndOfLine character is a String too. Is it possible to do all with TBytes and if yes, is there a demo application for server and client to take a look at this? All I want to program in background thread, not in main GUI :-) Share this post Link to post
Angus Robertson 645 Posted yesterday at 08:19 AM ICS sends binary data at the lowest level, it has methods to send strings and TBytes to make life easier for the developer. You need to be more cautious receive, in case of disconnection when your packet end is lost. I'd recommended building the OverbyteIcsIpStmLogTst sample, it uses the TIcsIpStrmLog component that is designed for simple data transfer like yours, it can be configured as a client or server to send and receive packets, the sample should interwork with your existing applications. TIcsIpStrmLog saves a lot of code over using the lower level components, should be working in a day. Angus Share this post Link to post
AJ_Oldendorf 0 Posted yesterday at 09:24 AM This demo look likes UDP, yes? I want to use TCPIP, so packages will transfered without loosing (if no connection dropped) and repeat in case of trouble. Actual I send the complete length of my message at the beginning of each message and receiver can check when EndOfLine is True, if collected input message length is the same like sender has set in message data. If true, I accept the incomming message and works with it. The OverbyteIcsIpStmLogTst demo looks like a file transfer. In my opinion the demo OverbyteIcsThrdSrv looks like better but I have the problem, to understand how to transfer TBytes (ok, I saw the procedure SendTB with parameter TBytes) but how can I set the LineEnd to fix 8bytes and get a information in receive event, that EndOfLine is reached or not? Share this post Link to post
Angus Robertson 645 Posted yesterday at 09:59 AM The TIcsIpStrmLog component can be configured for TCP or UDP. It can do file transfers, but has SendLogLine (const Line: TBytes) which is exactly what you requested. For clients, the component handles connection retries if/when the connection drops. Reading your message again, the record end of eight bytes is not handled, only a single symbol or CRLF, but you could easily adapt the component receive loop to check for a longer end of record. OverbyteIcsThrdSrv is a very old server sample and has not been tested for many years. Try OverbyteIcsSimpleSslServer, inSslWSocketServer1ClientConnect set a long LimieLimit and LineEnd to your six bytes. Ignore the SSL stuff. Angus Share this post Link to post
AJ_Oldendorf 0 Posted 23 hours ago (edited) I take a look to OverbyteIcsSimpleSslServer and changed following: ClientDataAvailable found := False; tmpStr := ReceiveStr; tmpRcvdBytes := IcsStringToTBytes(tmpStr); EOL := False; for i := Low(tmpRcvdBytes) to High(tmpRcvdBytes) do begin if Found then Break; found := False; for j := Low(DefEOLB) to High(DefEOLB) do begin if tmpRcvdBytes[i] = DefEOLB[j] then begin found := True; end else found := False; if (j = High(DefEOLB)) and found then begin FoundPos := i; EOL := True; Break; end; end; end; if EOL then begin if Length(LastServerFracInputBytes) > 0 then begin RcvdBytes := LastServerFracInputBytes + tmpRcvdBytes; SetLength(LastServerFracInputBytes, 0); end else begin RcvdBytes := tmpRcvdBytes; end; Display('Received from ' + GetPeerAddr + ': ', RcvdBytes); ProcessData(Sender as TTcpSrvClient); end else begin LastServerFracInputBytes := LastServerFracInputBytes + tmpRcvdBytes; end; LastServerFracInputBytes : TBytes; DefEOLB : TBytes; are global variables in form. FormCreate SetLength(LastServerFracInputBytes, 0); SetLength(DefEOLB, 8); FillChar(DefEOLB[0], 1, 65); FillChar(DefEOLB[1], 1, 65); FillChar(DefEOLB[2], 1, 66); FillChar(DefEOLB[3], 1, 66); FillChar(DefEOLB[4], 1, 67); FillChar(DefEOLB[5], 1, 67); FillChar(DefEOLB[6], 1, 68); FillChar(DefEOLB[7], 1, 68); StartButton SslWSocketServer1.Proto := 'tcp'; SslWSocketServer1.Addr := '0.0.0.0'; // Use any interface SslWSocketServer1.Port := PortEdit.Text; SslWSocketServer1.SslEnable := FALSE; SslContext1.SslCertFile := CertFileEdit.Text; SslContext1.SslPassPhrase := PassPhraseEdit.Text; SslContext1.SslPrivKeyFile := PrivKeyFileEdit.Text; SslContext1.SslCAFile := CAFileEdit.Text; SslContext1.SslCAPath := CAPathEdit.Text; SslContext1.SslVerifyPeer := VerifyPeerCheckBox.Checked; //SslWSocketServer1.SetAcceptableHostsList(AcceptableHostsEdit.Text); SslWSocketServer1.Listen; SslWSocketServer1.ClientClass := TTcpSrvClient; // Use our component Display('Listenning...'); ClientConnect with Client as TTcpSrvClient do begin Display('Client connected.' + ' Remote: ' + PeerAddr + '/' + PeerPort + ' Local: ' + GetXAddr + '/' + GetXPort); Display('There is now ' + IntToStr(TWSocketServer(Sender).ClientCount) + ' clients connected.'); LineMode := TRUE; LineEdit := TRUE; LineLimit := 50; { Do not accept long lines } OnDataAvailable := ClientDataAvailable; OnLineLimitExceeded := ClientLineLimitExceeded; OnBgException := ClientBgException; OnSslVerifyPeer := ClientVerifyPeer; ConnectTime := Now; end; So, my client connect and I got message, that one is client is connected. When LineLimit is 50, I got "ClientLineLimitExceeded" event after some second and connection will closed. When LineLimit is 62000, no event is calling (or ClientLineLimitExceeded takes a long time...). All the time, no ClientDataAvailable is called. Do you have a idea? Edited 22 hours ago by AJ_Oldendorf Share this post Link to post
Angus Robertson 645 Posted 21 hours ago You did not add LineEnd, so it never finds the end of your records. Angus Share this post Link to post
AJ_Oldendorf 0 Posted 3 hours ago You are right, I forgot... var EOLData : AnsiString; begin EOLData := ''; SetLength(EOLData,Length(DefEOLB)); Move(DefEOLB[0],EOLData[1],Length(DefEOLB)); var EOLData : AnsiString; begin EOLData := ''; SetLength(EOLData,Length(DefEOLB)); Move(DefEOLB[0],EOLData[1],Length(DefEOLB)); LineEnd := EOLData; Now it works and ClientDataAvailable Event is called. One question, is the event everytime fired, when LineEnd is founded or can it happens, that the event is fired and in ReceiveStr is only a part of my message and I have to collect the received data? Share this post Link to post
Angus Robertson 645 Posted 2 hours ago LineMode/LineEnd is normally only used for ASCII protocols with limited line lengths, ie HTTP/SMTP etc, The DataAvailable event should only be triggered by LineEnd, but might also be if the connection is closed, or maybe not. That was why I suggested the TIcsIpStrmLog componemt which has more options to avoid data being lost, but unfortunately not long LineEnds. But I'd still use it for your clients, unless the server also sends long LineEnds. Angus Share this post Link to post