Когда мой HTTP-прокси был простым многопоточным, запросы GET и CONNECT работали нормально: теперь я хочу разместить в середине диалога TCP между клиентами и серверами механизм организации очередей, в котором проталкиваются байты, поступающие от клиента и серверов. очереди с приоритетами, и только данные с наивысшим приоритетом извлекаются из очередей и отправляются по назначению.
Эффективные данные, которые я получил от recv()
с клиентов и серверов хранится в 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;
Я не могу опубликовать весь код здесь, это слишком много. Я постараюсь объяснить поток пакета infoPkt
в моей программе:
У меня есть следующие классы:
ClientManager
: цикл с accept()
, получая HTTP-запрос от клиента, создаю первый infoPkt
этой связи с запросом внутри него и помещая его в очереди prio DequeManager::getInstance().insert(newElem);
, Начните accept()
снова
HTTPManager
: этот класс, какие методы все static
занимается реальным обменом данными между клиентом и сервером; HTTPManager::dealPkt(infoPkt p)
вызывается из DequeManager
, связывая это с queueingThread
нить (см. DequeManager
ниже), когда первый пакет соединения удален; после отправки 200 OK
к клиенту, я сselect()
клиентский и серверный fds для проверки входящих данных; что я recv()
Вставляю в прио очереди в DequeManager
; Если я recv()
0 байтов от клиента или сервера, я создаю infoPkt
без полезной нагрузки, но с infoPkt.last
установлен в true
а также break
select()
петля;
DequeManager
здесь работают два потока, один зацикливается на проверку на голодание (если пакет провел слишком много времени в очереди, он будет перемещен в очередь с более высоким приоритетом), а другой всегда сначала удаляет пакеты из очереди с более высоким приоритетом, затем из очередей с более низким значением prio, когда высший из них пуст; когда нить удаляет infoPkt
У нас есть два сценария:
serverFd
в infoPkt
-1: это означает, что это пакет HTTP-запроса, соединение по-прежнему не установлено, так как у меня нет дескриптора файла сервера; удаление темы делает socket()
, bind()
а также connect()
на удаленный сервер, установите новый сервер fd в infoPkt.serverFd
, звонки std::thread queueingThread(HTTPManager::dealPkt, packet); queuingThread.detach();
и продолжает убирать снова;
serverFd
в infoPkt
> 0: это означает, что это infoPkt
принадлежность к уже существующему соединению, помещенному в очередь клиентом или сервером; сначала я проверяю infoPkt.last
флаг, если это true
это последний пакет соединения, recv()
IN с клиента или сервера вернул 0, поэтому я создал это infoPkt
без payload
но установка infoPkt.last
в true
так что я выполняю close(infoPkt.clientFd);
а также close(infoPkt.serverFd);
; в противном случае, если infoPkt.serverFd
> 0 и infoPkt.last
не является true
этот пакет будет отправлен в пункт назначения infoPkt.direction
,
«Манипулирование потоком», которое я написал в заголовке, относится к обмену данными в select()
в соединении HTTP CONNECT: данные, которые я получаю от клиента, не отправляются на сервер сразу, а помещаются в очереди prio и отправляются позже, только когда поток удаления удалит эти данные, потому что, согласно механизмам приоритета, соблюдаются условия, чтобы сообщить это его очередь. В то время как мой предыдущий прокси-сервер с немедленной пересылкой данных в пункт назначения при получении данных прошел нормально: я пытаюсь согласовать механизм приоритетов между ними, задерживая обмен данными, но программы работают не так, как я ожидал; Соединение закрывается после отправки одного или двух пакетов, и я не могу понять, почему.
Вот вывод моей программы, когда я пытаюсь подключиться к домашней странице 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.3667426496 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.36111642368 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.36111642368 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
Если кто-то скажет: «Это неправильно, потому что обмен данными в TCP-соединении не должен задерживаться вручную из-за вашего механизма приоритетов», я выброшу свой код и успокоюсь, найдя другой способ добиться этого. управление трафиком в соединении TCP, пакет за пакет; Искренне, я бы предпочел, чтобы кто-то сказал мне: «Вы, придурок, просто проверьте это, и все будет работать», поэтому я знаю, что я не потрачу впустую месяцы на этот мой любительский проект: D
редактироватьЯ предоставляю только значимый код из моего проекта, если у вас есть какие-либо вопросы, не стесняйтесь спрашивать. Вот мой гист
Проблема в том, что TCP имеет явный механизм фиксировать переупорядочение проблем. Это может включать в себя NACK, которые заставляют отправителя повторно отправлять пакеты.
Ваше «приоритетное» переупорядочение байтов в потоке TCP будет в лучшем случае создайте много повторной отправки данных, поэтому ваш «приоритет» ухудшает все. Но вполне возможно, что любая сторона просто сдается, когда поток TCP слишком нарушен.
Других решений пока нет …