让我先告诉我想做的事情。我想写一个非常简单的代理服务器。我使用的套接字API创建套接字。 socket = socket(AF_INET, SOCK_STREAM, 0));
我的代理服务器,直到我尝试了一个数据流的罚款。所以我所做的就是我的服务器套接字听取了请求,并分析它们,然后将它们转发到实际的服务器,然后我用read()调用来读取数据包和我盲目地将其转发回客户端。
对于所有的HTML页面和图像,它工作正常。但是当我尝试着一个视频流,我无法做到这一点。
我的插座始终返回应用层数据(HTTP数据包),但在视频流只有第一个包是http和休息都只是TCP数据包。所以,我能只转发第一个HTTP数据包。当我尝试读取一个包含数据(这些都是TCP)的其他数据包我不明白在应用层东西(这是显而易见的,因为其中没有在这些数据包应用层)。所以我坚持,我不知道如何读从TCP层(我不想用原始套接字),这些数据包,并让我的工作做好。
提前致谢
如果您使用socket API,那么你是在HTTP层上,也就是你的一切“只是TCP”。如果连接某个地方卡住了,这是最有可能是别的东西坏了。注意也不能保证该HTTP请求或应答标题将即使配合在单个数据包中;他们只是通常做。
一个HTTP 1.1兼容的流媒体服务器将使用“内容编码:分块”,并报告每个块的长度,而不是整个文件的长度,你应该进行代理时,记住这一点。
所以我所做的就是我的服务器套接字听取了请求,并解析它们
为什么? HTTP代理不必解析任何东西,除了请求的第一线,知道在哪里,使上游连接。其他的一切只是复制在两个方向字节。
你必须解析报文头知道有多少数据从套接字读取。起初,使用例如环形缓冲区(圆形一个!)的BSD sys/queue.h
从流命令接收到的数据。
下面的代码显示如何提取IPv4分组的header_length
,total_length
,源和目的地地址在层3是指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;
}