开发者

How to push (i.e. flush) data sent to a TCP stream

开发者 https://www.devze.com 2023-03-23 06:27 出处:网络
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

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 recei开发者_Python百科ved and acknowledged?


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.


try to add a shutdown call before the close of the socket;

shutdown(client_fd,SHUT_RDWR);

However the real solution is to get an acknowledgement back from the client that it has received the data -- I.e. you need to define a protocol -- the simplest of simple protocols is that the client is responsible for closing the socket when the data is received.


Well as per my limited knowledge, TCP will insure that the data is transferred to the other machine / socket.

But has the program at the other end read / accessed the data cannot be confirmed using standard socket API's. Your other end (client in this case) might be busy doing something else instead of waiting for data to show up.

I think that your requirement will be full filled if you implement some sort of handshaking between server / client to track what all has been received using some kind of acknowledgements.

The acknowledgement mechanism is important if your application depends on it.


You can force immediately sending of small packets by disabling Nagle's algorithm, but this does not guarantee that the client will receive it.

If you have to wait for the acknowledge you have to build this into the protocol and wait for the client to write something into the socket that signals the reception of message.


The only way to make sure your data is send over is to Receive an answer. After testing for many days this is the only way to make sure it is 'flushed' to the other side.

// Receive until the peer closes the connection to make sure all data has been send

do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0){
            printf("Bytes received: %d\n", iResult);
        }
        else if (iResult == 0){
            printf("Connection closed\n");
        }
        else{
            printf("recv failed with error: %d\n", WSAGetLastError());
        }

    } while (iResult > 0);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号