4

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

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

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

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

任何想法将不胜感激,谢谢!

4

4 回答 4

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,到目前为止,我一直在努力让它在无线设备上正常工作。但是,如果您持续需要这个,也可以考虑一下。

于 2011-09-14T22:30:40.223 回答
1

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

但是,如果您想在操作系统可以给您一些数据后立即读取数据,您

  1. 使用套接字描述符上的 fcntl() 调用将套接字设置为非阻塞模式。
  2. 向 I/O 通知服务注册套接字描述符,例如 select()、poll()、epoll。
  3. 等待此服务上的 I/O 事件。
  4. 当它指示一个套接字已准备好读取时,您可以从中读取 - 无论当时有多少数据可用。(并处理 read/recv 返回 -1 并且 errno 设置为 EWOULDBLOCK 的情况)
于 2011-09-15T10:00:44.473 回答
0

本质上,我想通过在数据到达时立即处理数据来最大程度地减少延迟,

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

如果您想避免调度延迟,一种选择是忙轮询/等待以防止操作系统使进程进入睡眠状态。也就是说,select()以 0 超时调用或调用recv()非阻塞套接字并在返回时立即重试调用EAGAIN。显然,它必须是一个不服从调度器时间片的实时先进先出进程,否则它将耗尽它的时间片忙等待并进入休眠状态。

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

为了迂腐,没有TCP message这样的东西。只要数据按顺序到达,TCP 就会在数据到达后立即传送。

于 2011-09-15T10:07:18.033 回答
0

您应该在数据到达后立即获取数据。没有“整个 TCP 消息”这样的东西。每次调用readrecv应该给你当时收到的尽可能多的有序字节。

于 2011-09-15T09:46:15.070 回答