Each of the SocketTools networking controls provides methods for exchanging data between your application and the server. At the lowest level, this is done by calling the Write method for sending data and the Read method for receiving data. In most cases, these methods exchange data as a stream of bytes without any regard for the actual content. It is important to note that if the data being read or written is binary, it is recommended that applications pass byte arrays, not strings, to the Read and Write methods if possible.
When working at this very low level, it is important to understand how data is exchanged over the network. Many developers are inclined to think of the data that is sent or received in terms of discrete blocks, or packets. The expectation is that if they send a certain number of bytes of data in a single write, the server will receive that number of bytes in a single read. However, this is not how TCP works, and by extension, not how the SocketTools libraries work with regards to this kind of low level network I/O. The Transmission Control Protocol (TCP) is called a stream-oriented protocol because data is exchanged between the client and server as a stream of bytes. While TCP will guarantee that the data will arrive intact, with the bytes received in the same order that they were written, there is no guarantee that the amount of data received in a single read operation on the socket will match the amount of data sent by the remote host.
For example, consider a server that sends data to a client in four separate operations, each containing 1024 bytes of data. While it is convenient to think of these as discrete blocks of data, TCP considers it to be a stream of 4096 bytes. The client may receive that data in a single read on the socket, returning all 4096 bytes. Alternatively, it may read the socket, and only receive the first 1460 bytes; subsequent reads may return another 1460 bytes, followed by the remaining 1176 bytes. Applications which make assumptions about the amount of data they can read or write in a single operation may work in some environments, such as on a local network, but fail on slower connections.
A general rule to use when designing an application using TCP is to consider how the program would handle the situation where reading n bytes of data only returns a single byte. If the application can correctly handle this kind of extreme case, then it should function correctly even under adverse network conditions.
In some situations it may be desirable to design the application to exchange information as discrete messages or blocks of data. While this isn't directly supported by TCP, it can be implemented on top of the data stream. There are several methods that can be used to accomplish this, depending on the requirements of the application:
Regardless of the method used, for best performance it is recommended that the application buffer the data received and then process the data out of that buffer. When using asynchronous (non-blocking) connections, the application should read all of the data available on the socket, typically in a loop which adds the data to the buffer and exiting the loop when there is no more data available at that time.
It is important to keep in mind that all of this is only required if you decide to use the lower level methods in the SocketTools controls. The higher level methods automatically handle the lower level network I/O for you. For example, the GetData method in the File Transfer Protocol control will retrieve a file from the server and return the entire contents to your application in a single method call. When using the high level methods, the details of how the data is read and processed is handled by the control and no additional coding is required on your part.
Copyright © 2023 Catalyst Development Corporation. All rights reserved.