4
votes

How can I receive data (byte stream) from an open network socket in C on a packet-by-packet basis? I want to read data from the socket IMMEDIATELY as it arrives (as soon as the packet arrives on the machine).

It seems when I perform a read() (or recv()) call on the socket, I am getting the entire TCP message of 10,000+ bytes. Rather, I would like to receive the first TCP segment payload, process it, then continue to the next, etc.

Note - I don't want raw packets. Just the TCP segment data payload.

Also note - In essence I want to minimize delay by processing data immediately as it arrives, as opposed to waiting for the entire TCP message to accumulate in the TCP layer.

Any ideas would be much appreciated, thanks!

4
Have you taken into account that TCP packets can be received out of order? Also, this sounds like something where UDP would be a better optionEarlz
have you checked the actual delay you want to eliminate? what does tcpdump show?Karoly Horvath
@earlz: 100% disagree on UDP comment. With UDP you give up huge functionality (and typically re-implement half of it).John M
@Remy TCP_NODELAY is a transmit optionAlnitak

4 Answers

2
votes

Maybe I misunderstand your question (eg, I can't quite make sense of 'don't want raw packets just the TCP payload'), but a simple raw socket (IPPROTO_TCP) connected and then sniffed on with recv() will do the job. You indicate a maximum buffer size as an argument in recv(), but when a TCP load comes, it will be reported back - no waiting for the buffer to fill up. Here is some code excerpt that prints out TCP packets:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include // your header to print out bytes and error messages here

int main(void) {
    int i, recv_length, sockfd;
    u_char buffer[9000];

    if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
        // your error message here

    for(i=0; i < 3; i++) {
        recv_length = recv(sockfd, buffer, 8000, 0);
        printf("Got a %d byte packet\n", recv_length);
        // your routine to print out bytes here
    }
}

If this isn't what you were concerned about, kindly clarify.

Edit: From what I hear and read, using library pcap (libcap) is superior to using raw sockets (more reliable; very powerful - written by the guys who wrote tcpdump). However, I'm still learning pcap myself and so far am struggling to get it to work properly with wireless devices. But maybe look into that too if you need this on an on-going basis.

1
votes

TCP does not have "messages". It is just a byte stream. The socket APIs does not give you access to the data carried by individual IP packets, or TCP segments.

However, if you want to read data as soon as the operating system can give you some data, you

  1. Set the socket to non-blocking mode, using the fcntl() call on the socket descriptor.
  2. Register the socket descriptor with an I/O notification service , such as select(), poll(), epoll.
  3. Wait for I/O events on this service.
  4. When it's indicated a socket is ready for reading, you read from it - and you will get however much data is available at that time.(and handle the case where read/recv returns -1 and errno is set to EWOULDBLOCK)
0
votes

You should be getting the data as soon as it arrives. There is no such thing as an "entire TCP message". Each call to read or recv should give you as many in-order bytes as have been received at that time.

0
votes

In essence I want to minimize delay by processing data immediately as it arrives,

There is a scheduling delay between the time when data becomes available in the kernel socket buffer and the time when the receiving process is woken up from a blocking read()/recv()/select()/epoll()/etc. With unmodified Linux kernel and a real-time process it is no less than 4 microseconds.

If you'd like to avoid the scheduling delay one option is to busy poll/wait preventing the OS from putting the process to sleep. That is, calling select() with 0 timeout or calling recv() on a non-blocking socket and retrying the call immediately if it returns EAGAIN. Obviously, it must be a real-time FIFO process which doesn't obey scheduler time slices, otherwise it will exhaust its time slice busy waiting and will be put to sleep.

as opposed to waiting for the entire TCP message to accumulate in the TCP layer.

To be pedantic, there is no such thing as TCP message. TCP delivers the data as soon as it arrives, provided it has arrived in order.