Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 如何在C中使用套接字读取流的TCP数据包?_Sockets_Proxy_Tcp_Stream - Fatal编程技术网

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

Sockets 如何在C中使用套接字读取流的TCP数据包?,sockets,proxy,tcp,stream,Sockets,Proxy,Tcp,Stream,让我先告诉你我想做什么。 我正在尝试编写一个非常简单的代理服务器。 我使用socket API创建了一个套接字。 socket=socket(AF_INET,SOCK_STREAM,0)) 我的代理服务器工作得很好,直到我尝试使用它来传输数据。 因此,我所做的是我的服务器套接字侦听请求并解析它们,然后将它们转发到实际的服务器,然后使用read()调用读取数据包&我盲目地将其转发回客户端 对于所有html页面和图像,它都可以正常工作。但当我尝试转发流媒体视频时,我无法做到这一点 我的套接字总是返回

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

我的代理服务器工作得很好,直到我尝试使用它来传输数据。 因此,我所做的是我的服务器套接字侦听请求并解析它们,然后将它们转发到实际的服务器,然后使用read()调用读取数据包&我盲目地将其转发回客户端

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

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


提前感谢

如果您使用socket API,那么您就在HTTP下面的层上,也就是说,对您来说,一切都是“TCP”。如果连接卡在某个地方,则很可能是其他东西断了。注意:不能保证HTTP请求或应答报头甚至可以放入单个数据包中;他们通常就是这样


兼容HTTP 1.1的流媒体服务器将使用“内容编码:分块”并报告每个分块的长度,而不是整个文件的长度,代理时应记住这一点。

如果您使用套接字API,则您位于HTTP下面的层,也就是说,对您来说,一切都是“仅TCP”。如果连接卡在某个地方,则很可能是其他东西断了。注意:不能保证HTTP请求或应答报头甚至可以放入单个数据包中;他们通常就是这样

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

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

为什么??HTTP代理不必解析除了请求的第一行以外的任何内容,就可以知道在哪里进行上游连接。其他一切都只是在两个方向上复制字节

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


为什么??HTTP代理不必解析除了请求的第一行以外的任何内容,就可以知道在哪里进行上游连接。其他一切都只是在两个方向上复制字节。

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

下面的代码显示了如何提取第3层中IPv4数据包的
头\u长度
总长度
、源地址和目标地址。请参阅以了解偏移:


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



类型定义结构{
无符号字符版本;
无符号字符头长度;
无符号短总长度;
地址src中的结构;
结构地址dst;
}包;
int rb_数据包_写入_(环形缓冲区*b、int fd、int计数){
int i;
对于(i=0;i20级){
返回i;
}
包p;
无符号字符*开始=b->blob+b->读取光标;
无符号字符b1=开始[0];
p、 版本=b1>>4;
p、 标题长度=b1&0xf;
p、 总长度=bigendian反序列化uint16(开始+2);
如果(b->level%s(%u)”,p.version,s,d,p.total_长度);
}
返回i;
}

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

下面的代码显示了如何提取第3层中IPv4数据包的
头\u长度
总长度
、源地址和目标地址。请参阅以了解偏移:


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



类型定义结构{
无符号字符版本;
无符号字符头长度;
无符号短总长度;
地址src中的结构;
结构地址dst;
}包;
int rb_数据包_写入_(环形缓冲区*b、int fd、int计数){
int i;
对于(i=0;i20级){
返回i;
}
包p;
无符号字符*开始=b->blob+b->读取光标;
无符号字符b1=开始[0];
p、 版本=b1>>4;
p、 标题长度=b1&0xf;
p、 总长度=bigendian反序列化uint16(开始+2);
如果(b->level%s(%u)”,p.version,s,d,p.total_长度);
}
返回i;
}

谢谢您的回复。我同意你的看法,但你不认为我应该能够读取流的TCP数据包中的数据,因为我能够读取html页面或流的所有其他数据包。绝对可以。我的怀疑是,为了读取所有我需要的数据,您只调用了read()函数一次