2

Is it possible to determine if TServerSocket Receive Buffer contains all data in there ?

  • 4
    Why use extremely outdated technology? The `TServerSocket` and `TClientSocket` are depreciated, and only exist for backwards-compatibility. Besides, you need to be a log more specific than that. – Jerry Dodge Dec 02 '12 at 19:01
  • Yeah, in Mastering Delphi 6/7 i've read that TTcpClient/Server is their replacement, but i find it hard to use them -_- (including Indy's one) –  Dec 02 '12 at 19:23
  • 2
    in my experience Indy and Synapse were much easier to use – mjn Dec 02 '12 at 20:02
  • I wish I caught my typo above in time to correct it... – Jerry Dodge Dec 03 '12 at 01:11
  • 2
    `TTcpClient/Server` were Borland's attempt at a cross-platform socket implementation in D6 for Kylix support. Kylix is dead, and although those components still exist, they have been replaced with Indy. – Remy Lebeau Dec 03 '12 at 20:59
  • the `TServer/ClientSocket` components are just wrappers to the Winsock APIs, that's it, so how is it dead ? it's still working... are you refering to the internal work of the components made by Borland team ? also, could you show me how easy it is to work with Indy's TCP's components ? and btw does it have a built in KeepAlive mechanism ? that will be important too i believe. –  Dec 04 '12 at 00:24
  • Essentially, any type of sockets in the end wind up using WinSock because that's the core of Windows Networking. – Jerry Dodge Dec 04 '12 at 03:27
  • i find indy's components work till you try to update them.. for simple stuff i usually use sockets. – Glen Morse Dec 04 '12 at 09:32
  • @0x90 for TCP keep-alive see http://stackoverflow.com/questions/5883441/tcp-keep-alive-on-idhttpserver-server-and-wininet-client – mjn Dec 05 '12 at 09:44
  • @GlenMorse updating Indy is easy (I use Subversion), IDE installation trouble can be avoided by dynamic creation of the components – mjn Dec 05 '12 at 09:45

3 Answers3

6

That's the case of the protocol.

  • Can be a defined end token. e.g. CR LF CR LF in HTTP
  • A header containing then length of the request.
bummi
  • 27,123
  • 14
  • 62
  • 101
  • No, i meant like how can i determine that OnRead that is being fired is the last one ? it's probably not possible i assume, i didn't ask how to determine end of data tag or something like that... –  Dec 02 '12 at 19:24
  • @0x90 it is not possible. The OnRead event can be fired again with another data packet. This makes TServerSocket harder to handle than Indy or Synapse, where your code asks the library to read up to the terminator or the known data length (or until an error / timeout occurs). With TServerSocket / TClientSocket, there is no separation of 'logically connected' data into OnRead event calls. – mjn Dec 02 '12 at 20:00
  • 1
    @0x90: you have to keep track of the state of whatever protocol you are implementing. When you get an `OnRead` event, it is best to read all of the available bytes and append them to the end of a buffer of your choosing, and then you can parse the buffer as needed, using your protocol state machine to know what is in the buffer. Only parse out completed messages from the buffer, and leave any remaining bytes in the buffer to be completed by later `OnRead` events. – Remy Lebeau Dec 03 '12 at 21:02
5

There is no way to determine whether OnRead has finished reading as by definition there is no end. This means that you should not simply send binary data without special information. You could, for example send the number of bytes first (as a, let's say, 4 byte unsigned integer) and then the bytes you wish to send.

On the receiver's side, you would first read, let's say, the 4 bytes and now you know how many bytes you can expect.

alzaimar
  • 4,572
  • 1
  • 16
  • 30
  • That's what i'm already doing, using Remmy's example code: http://stackoverflow.com/questions/13261486/sending-a-dynamic-array-inside-a-record-through-socket/13270046 BUT, since the OnRead fires multiple times... i want to determine when will be the last time so i can THEN read all at once. –  Dec 02 '12 at 20:14
  • 6
    That's not the way to do it. The OS decides when send you another bite of the cake. The OnRead will read what the OS gives you and buffers it. In other words: You have to collect it and react. E.g. when you have received the last part of your 'announced' bytes, you can then process them. – alzaimar Dec 02 '12 at 21:24
  • 1
    @0x90: alzaimar is right. When you get an `OnRead` event, you have to read everything that is available on the socket and buffer it somewhere. You can then parse the buffer to see if it contains a completed message, based on whatever protocol you are implementing. If you find a completed message, remove it from the buffer and process it as needed, then repeat again while the buffer no longer contains a completed message. Leave whatever uncompleted bytes are still in the buffer so later `OnRead` events can append new bytes to it. Repeat the parsing on each `OnRead` event you receive. – Remy Lebeau Dec 03 '12 at 21:06
0

If you intend to read data from a client on the server, it's a typical methodology to use a buffer string (per client socket) and a loop which parses that string. For example, I'm assuming you create an object to wrap each server/client socket. In this object, create a string called Buffer. Whenever you receive data from the client, append the new data on the end of this string. Then, a separate process (a thread) can parse this string and check for a complete packet. The methodology in reading packet size is all up to you however.

There is no guarantee that the server will trigger events on receipt of data in the order it was sent. A client may send 4 packets of data to the server, and the server only triggers one event for all of it, or a client may send 1 packet of data and the server triggers two events for parts of that data. You're responsible to continuously read the data that comes in for completeness, depending on the nature of your socket communication.

The answer by alzaimar is what you need to do. Suppose one full packet is a string like this:

This is some string.

When parsing strings like this, it is risky to use a deliminator. So instead, take the size of that string and prefix it on your packet with just a single deliminator between that size and the data. Since the string above is 20 characters long, the actual packet should look something like this:

20:This is some string.

...where a colon (:) is the deliminator between the size and the data. First, you check to make sure that deliminator exists. If so, then copy everything up to it. If it's a valid number, then it means you need to read that many characters from the buffer. Next, check if the buffer has that much data available. If so, then grab that data from the buffer. Remember to only delete data from the buffer when necessary- I can give a more detailed code example if you wish.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327