RFC 793 says that TCP defines a "push" function that ensures that the receiver got the data:
Sometimes users need to be sure that all the data they have submitted to the TCP has been transmitted. For this purpose a push function is defined. To assure that data submitted to a TCP is actually transmitted the sending user indicates that it should be pushed through to the receiving user. A push causes the TCPs to promptly forward and deliver data up to that point to the receiver.
However, I can't find a push
system call. Using fsync
on the file descriptor produces an invalid argument error.
I conducted an experiment with a simple server that accepts a connection from a client, waits, then sends 26 bytes to the client:
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1234
int main(void)
{
int server_fd;
int client_fd;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
perror("bind");
return 1;
}
}
if (listen(server_fd, 20) != 0) {
perror("listen");
return 1;
}
{
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
printf("Waiting for connection on port %d\n", PORT);
if ((client_fd = accept(server_fd, (struct sockaddr*)&addr, &addrlen)) < 0) {
perror("accept");
return 1;
}
printf("%s:%d connected\n",
inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
}
printf("Giving client time to close connection.\n");
sleep(10);
{
ssize_t sent_length;
if ((sent_length =
send(client_fd, "abcdefghijklmnopqrstuvwxyz", 26, 0)) < 0)
{
perror("send");
return 1;
}
printf("Sent %Zd bytes.\n", sent_length);
}
printf("Closing connection to client\n");
if (close(client_fd) != 0) {
perror("close(client_fd)");
return 1;
}
printf("Shutting down\n");
if (close(server_fd) != 0) {
perror("server: close(server_fd)");
return 1;
}
printf("Done!\n");
return 0;
}
I found that the send
call immediately returns 26, even after I close the connection client-side or unplug the network cable. In the latter case, the data appears on the client when I plug the cable back in and wait a few seconds (long after the server has shut down).
How do I ensure that data sent with send
is received and acknowledged?
The TCP Open Connection node opens a connection to the server at the port and address you specify. The address must match the IP address of the server, and the port you specify on the client must match the port you specify on the server. TCP Write nodes write data to the specified port and send commands to the server.
TCP is a connection-oriented protocol meaning it first sets up a connection to the receiver then sends the data in segments (PDU for transport layer) which is carried by IP packets. This way it's called stream because it keeps the stream of data between to ends during transfer.
The TCP protocol is modeled on the concept of a single continuous stream of unlimited length. This is a very important concept to understand, and is the number one cause of confusion that we see.
Flushes data from the stream. This method is reserved for future use.
There is no push, says the late W. Richard Stevens; the standard sockets API doesn't provide it, and is not required to do so by RFC 1122. You can set the TCP_NODELAY
option, but that's only a partial solution.
If you want to be sure the other end got your data, then let it send an acknowledgment over the TCP channel.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With