任意操纵 TCP 连接流会导致问题吗?

Does arbitrary manipulation of TCP connection flow cause problems?

当我的 HTTP 代理是一个简单的 multi-threaded 代理时,GET 和 CONNECT 请求运行良好:现在我想在客户端和服务器之间的 TCP 对话中间放置一个 queue ing 机制,其中来自客户端和服务器的字节按优先级 queues 推送,只有具有最高优先级的数据才会从 queues 中弹出并发送到目的地。

我从客户端和服务器 recv()ing 获得的有效数据与一些元数据一起存储在 struct infoPkt 中:

typedef struct infoPacket {
    int clientFd;
    int serverFd;
    int request;
    int direction;
    int priority;
    char payload[MAX_PAYLOAD_SIZE];
    int payloadSize;
    in_addr_t serveraddr;
    char host[256];
    std::chrono::time_point<std::chrono::system_clock> start;
    bool first;
    bool last;
} infoPkt;

我不能post这里所有的代码,太多了。我将尝试在我的程序中解释数据包 infoPkt 的流程:

我有以下 classes:

我在标题中写的"flow manipulation"指的是select()中的数据交换,在CONNECT HTTP连接中:我从客户端获取的数据不是立即发送到服务器,而是推送在 prio queues 和稍后发送时,仅当删除线程将删除该数据时,因为根据优先级机制,满足条件告诉它轮到它了。虽然我以前的代理在接收到数据时立即将数据转发到目的地,但一切顺利:我试图在两者之间设置优先级机制,延迟数据交换,但程序没有按我预期的那样工作;连接在发送一两个数据包后自行关闭,我不明白为什么。

这是我尝试连接到 Netflix 主页时程序的输出。

Created ClientManager
Start PROXY, thread id 67426496
Number of interfaces (or their IP addr) has changed, mmap() again
Found new interfaces: wlan0[192.168.1.88] 
priority 1 to hostname www.netflix.com
priority 1 to hostname nflxvideo.net
priority 2 to hostname www.youtube.com
priority 2 to hostname googlevideo.com
priority 3 to hostname www.facebook.com
remover thread with method DequeManager::removeAll() detached
controller thread with method DequeManager::aging() detached
67426496 THREAD MAIN
Proxy listening to port 8000, here we go!

67426496 ClientManager::getRequestFromClient received from client 215 byte
67426496 ClientManager::manageClient() inserted C 4, S -1, CONNECT, UPLOAD, prio 1, size 215, host www.netflix.com, first 1, last 0 --->
CONNECT www.netflix.com:443 HTTP/1.1
Host: www.netflix.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36


67426496 ClientManager::getRequestFromClient received from client 215 byte
67426496 ClientManager::manageClient() inserted C 5, S -1, CONNECT, UPLOAD, prio 1, size 215, host www.netflix.com, first 1, last 0 --->
CONNECT www.netflix.com:443 HTTP/1.1
Host: www.netflix.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36


111642368 DequeManager::removeAndDealPkt created pair (4 7)
137008896 HTTPManager::dealPkt() thread 137008896 started
137008896 HTTPManager::dealPkt() dealing with socket fd pair (4 7)
137008896 HTTPManager::dealPkt [CONNECT] sent 200 OK to client
137008896 HTTPManager::dealPkt [CONNECT] max fd+1 between client 4 and server 7: 8
137008896 HTTPManager::dealPkt [CONNECT] queued up pkt from client, 209 bytes
111642368 DequeManager::removeAndDealPkt created pair (5 8)
111642368 DequeManager::removeAndDealPkt send() C 4, S 7, CONNECT, UPLOAD, prio 1, size 209, host www.netflix.com, first 0, last 0
145401600 HTTPManager::dealPkt() thread 145401600 started
145401600 HTTPManager::dealPkt() dealing with socket fd pair (5 8)
145401600 HTTPManager::dealPkt [CONNECT] sent 200 OK to client
145401600 HTTPManager::dealPkt [CONNECT] max fd+1 between client 5 and server 8: 9
111642368 DequeManager::removeAndDealPkt sent_bytes 209
145401600 HTTPManager::dealPkt [CONNECT] queued up pkt from client, 209 bytes
111642368 DequeManager::removeAndDealPkt send() C 5, S 8, CONNECT, UPLOAD, prio 1, size 209, host www.netflix.com, first 0, last 0
111642368 DequeManager::removeAndDealPkt sent_bytes 209
137008896 HTTPManager::dealPkt [CONNECT] recv() 0 from client, crafting last packet 4 7
137008896 HTTPManager::dealPkt dealPkt() thread terminated
145401600 HTTPManager::dealPkt [CONNECT] recv() 0 from client, crafting last packet 5 8
145401600 HTTPManager::dealPkt dealPkt() thread terminated
111642368 DequeManager::removeAndDealPkt get LAST PACKET, closing fds 4 and 7
111642368 DequeManager::removeAndDealPkt get LAST PACKET, closing fds 5 and 8
67426496 ClientManager::getRequestFromClient received from client 215 byte
67426496 ClientManager::manageClient() inserted C 6, S -1, CONNECT, UPLOAD, prio 1, size 215, host www.netflix.com, first 1, last 0 --->
CONNECT www.netflix.com:443 HTTP/1.1
Host: www.netflix.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36


111642368 DequeManager::removeAndDealPkt created pair (6 5)
145401600 HTTPManager::dealPkt() thread 145401600 started
145401600 HTTPManager::dealPkt() dealing with socket fd pair (6 5)
145401600 HTTPManager::dealPkt [CONNECT] sent 200 OK to client
145401600 HTTPManager::dealPkt [CONNECT] max fd+1 between client 6 and server 5: 7
145401600 HTTPManager::dealPkt [CONNECT] queued up pkt from client, 215 bytes
111642368 DequeManager::removeAndDealPkt send() C 6, S 5, CONNECT, UPLOAD, prio 1, size 215, host www.netflix.com, first 0, last 0
111642368 DequeManager::removeAndDealPkt sent_bytes 215
145401600 HTTPManager::dealPkt [CONNECT] recv() 0 from client, crafting last packet 6 5
145401600 HTTPManager::dealPkt dealPkt() thread terminated
111642368 DequeManager::removeAndDealPkt get LAST PACKET, closing fds 6 and 5
^CCaught signal 2

如果有人说"this is wrong because data exchange in TCP connection is not expected to be manually delayed from within with a priority mechanism of yours",我就扔掉我的代码,放下心来,另辟蹊径实现TCP连接中的流量控制,一个包一个包;真诚地,我更希望有人对我说 "you moron, just check this and everything will work",所以我知道我不会在我的这个业余项目上浪费几个月 :D

编辑:我只提供了我项目中的重要代码,如果您有任何问题,请随时提出。 Here's my Gist

问题是 TCP 有一个明确的机制来修复 重新排序问题。这可能涉及强制发送方重新发送数据包的 NACK。

您 "priority" 对 TCP 流中字节的重新排序最多 会创建大量重新发送数据,因此您的 "priority" 会降低一切。但是很有可能当 TCP 流被破坏得太厉害时,任何一方都放弃了。