如何使用C中的套接字读取流的TCP数据包?

时间:2011-02-11 13:17:02

标签: sockets proxy tcp stream

让我先告诉我要做的事情。 我正在尝试编写一个非常简单的代理服务器。 我使用套接字API来创建套接字。 socket = socket(AF_INET, SOCK_STREAM, 0));

我的代理服务器工作正常,直到我尝试流式数据。 所以我做的是我的服务器套接字监听请求并解析它们然后将它们转发到实际的服务器,然后我使用read()调用来读取数据包&我盲目地将它转发给客户。

对于所有html页面和图像,它工作正常。但是当我尝试转发流媒体视频时,我无法做到。

我的套接字总是返回应用层数据(HTTP数据包)但在流视频中只有第一个数据包是http,其余全部只是TCP数据包。所以我只能转发第一个HTTP数据包。当我尝试读取包含数据的其他数据包(都是TCP)时,我在应用层没有得到任何东西(这很明显,因为这些数据包中的应用层没有任何内容)。所以我被卡住了,我不知道如何从TCP层读取这些数据包(我不想使用原始套接字)并完成我的工作。

提前致谢

3 个答案:

答案 0 :(得分:0)

如果您使用套接字API,那么您就在HTTP下面的层上,也就是说,一切都是“只是TCP”。如果连接卡在某处,很可能是其他东西被破坏了。请注意,无法保证HTTP请求或回复标头甚至可以放在单个数据包中;他们通常只是这样做。

符合HTTP 1.1标准的流媒体服务器将使用“Content-Encoding:chunked”并报告每个块的长度而不是整个文件的长度,在代理时应记住这一点。

答案 1 :(得分:0)

  

所以我做的是我的服务器套接字   听取了请求并进行了解析   它们

为什么呢? HTTP代理不必解析除请求的第一行之外的任何内容,以了解上游连接的位置。其他一切只是在两个方向上复制字节。

答案 2 :(得分:0)

您必须解析数据包头,才能知道要从套接字读取多少数据。首先,使用环形缓冲区(循环缓冲区!),例如BSD sys/queue.h对流中接收到的数据进行排序。

下面的代码显示了如何提取第3层中IPv4数据包的header_lengthtotal_length,源地址和目标地址。请参考IPv4 packet layout以了解偏移量:


typedef struct {
    unsigned char version;
    unsigned char header_length;
    unsigned short total_length;
    struct in_addr src;
    struct in_addr dst;
} Packet;


int rb_packet_write_out(RingBuffer *b, int fd, int count) {
    int i;
    for (i = 0; i < count; i++) {
        if (b->level < 20) {
            return i;
        }
        Packet p;
        unsigned char *start = b->blob + b->read_cursor;
        unsigned char b1 = start[0];
        p.version = b1 >> 4;
        p.header_length = b1 & 0xf;
        p.total_length = bigendian_deserialize_uint16(start + 2);
        if (b->level < p.total_length) {
            return i;
        }

        memcpy(&(p.src), start + 12, 4);
        memcpy(&(p.dst), start + 16, 4);

        char s[5], d[5];
        inet_ntop(AF_INET, &(p.src), s, INET_ADDRSTRLEN);
        inet_ntop(AF_INET, &(p.dst), d, INET_ADDRSTRLEN);

        L_DEBUG("Packet: v%u %s -> %s (%u)", p.version, s, d, p.total_length);
    }
    return i;
}