在C中立即(逐个数据包)从套接字接收TCP有效负载

时间:2011-09-14 21:27:15

标签: c sockets tcp recv

如何逐个数据包地从C中的开放网络套接字接收数据(字节流)?我想在它到达时立即从套接字中读取数据(一旦数据包到达机器)。

当我在套接字上执行read()(或recv())调用时,我得到的是10,000+字节的整个TCP消息。相反,我希望收到第一个TCP段有效载荷,处理它,然后继续下一个,等等。

注意 - 我不想要原始数据包。只是TCP段数据有效载荷。

另请注意 - 实质上,我希望通过在数据到达时立即处理数据来最小化延迟,而不是等待整个TCP消息在TCP层中累积。

非常感谢任何想法,谢谢!

4 个答案:

答案 0 :(得分:2)

也许我误解了你的问题(例如,我不能理解'不要只是TCP有效载荷的原始数据包'),而是连接一个简单的原始套接字(IPPROTO_TCP),然后用recv()嗅探会做的。您在recv()中指定最大缓冲区大小作为参数,但是当TCP负载到来时,它将被报告回来 - 无需等待缓冲区填满。以下是一些打印出TCP数据包的代码摘录:

#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
    }
}

如果这不是你所关注的,请善意澄清。

编辑:从我听到和阅读的内容来看,使用库pcap(libcap)优于使用原始套接字(更可靠;功能非常强大 - 由编写tcpdump的人编写)。但是,我自己仍在学习pcap,到目前为止,我正在努力让它与无线设备一起正常工作。但是,如果你需要持续这样做,也许也要考虑一下。

答案 1 :(得分:1)

TCP没有“消息”。它只是一个字节流。套接字API不允许您访问单个IP数据包或TCP段所承载的数据。

但是,如果您想在操作系统提供一些数据时立即读取数据,那么

  1. 使用套接字描述符上的fcntl()调用将套接字设置为非阻塞模式。
  2. 使用I / O通知服务注册套接字描述符,例如select(),poll(),epoll。
  3. 等待此服务的I / O事件。
  4. 如果指示套接字已准备好读取,则从中读取 - 此时您将获得大量数据。(并处理read / recv返回-1且errno设置为EWOULDBLOCK的情况)

答案 2 :(得分:0)

您应该在数据到达后立即获取数据。没有“整个TCP消息”这样的东西。每次调用readrecv都应该为您提供当时收到的有序字节数。

答案 3 :(得分:0)

  

本质上,我希望通过在数据到达时立即处理数据来最小化延迟,

在内核套接字缓冲区中数据可用的时间与从阻塞read() / recv() / select()中唤醒接收进程的时间之间存在调度延迟/ epoll() /等。使用未经修改的Linux内核和实时进程,它不会少于4微秒。

如果您想避免调度延迟,一个选项是忙于轮询/等待,以防止操作系统将进程置于休眠状态。也就是说,在{0}超时调用select()或在非阻塞套接字上调用recv()并在返回EAGAIN时立即重试该调用。显然,它必须是一个实时的FIFO进程,它不遵守调度程序时间片,否则会耗尽其时间片忙等待并将进入休眠状态。

  

而不是等待整个TCP消息在TCP层中累积。

要迂腐,就没有 TCP消息这样的东西。 TCP一旦到达就提供数据,只要它按顺序到达。