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

发布于 2024-10-17 06:10:54 字数 511 浏览 5 评论 0原文

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

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

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

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

提前致谢

let me first tell what I am trying to do.
I am trying to write a very simple proxy server.
I used the socket API to create a socket.
socket = socket(AF_INET, SOCK_STREAM, 0));

my proxy server worked fine until I tried it for a streaming data.
So what I did was my server socket listened to the requests and parsed them and then forwarded them to the actual server, I then used the read() call to read the packet & I blindly forward it back to the client.

For all html pages and images it works fine. but when I try to forward a streaming video I am not able to do it.

My socket always returns the application layer data (HTTP packet) but in a streaming video only the first packet is http and rest all are just TCP packets. So I am able to forward only the first HTTP packet. When I try to read the other packets which contain data (which are all TCP) I don't get anything at the application layer (which is obvious as there is nothing at application layer in those packets ). So I am stuck and I do not know how to read those packets from TCP layer (I dont wanna use raw socket) and get my job done.

thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无法言说的痛 2024-10-24 06:10:54

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

下面的代码展示了如何提取第 3 层 IPv4 数据包的 header_lengthtotal_length、源地址和目标地址。请参阅 IPv4 数据包布局 了解偏移量:


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


You have to parse the packet header to know how much data to read from the socket. at first, use a ring buffer (a circular one!) for example the BSD sys/queue.h to order the received data from the stream.

The code below shows how to extract header_length, total_length, source and destination Address of an IPv4 packet in layer 3. refer to IPv4 packet layout to understand offsets:


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


迷途知返 2024-10-24 06:10:54

如果你使用socket API,那么你就处于HTTP下面的层,也就是说,对你来说一切都是“只是TCP”。如果某个地方的连接卡住了,很可能是其他地方损坏了。请注意,无法保证 HTTP 请求或回复标头适合单个数据包;他们只是通常这样做。

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

If you use the socket API, then you are on the layer below HTTP, that is, to you everything is "just TCP". If the connection is stuck somewhere, it is most likely that something else is broken. Note there is no guarantee that the HTTP request or reply header will even fit in a single packet; they just usually do.

An HTTP 1.1 compliant streaming server will use "Content-Encoding: chunked" and report the length of each chunk rather than the length of the entire file, you should keep that in mind when proxying.

明明#如月 2024-10-24 06:10:54

所以我所做的是我的服务器套接字
监听请求并解析
他们

为什么? HTTP 代理不需要解析除请求的第一行之外的任何内容,即可知道在何处建立上游连接。其他一切都只是在两个方向上复制字节。

So what I did was my server socket
listened to the requests and parsed
them

Why? An HTTP proxy doesn't have to parse anything except the first line of the request, to know where to make the upstream connection to. Everything else is just copying bytes in both directions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文