Sto lavorando su un proxy HTTP TCP: è necessario trasformarlo in un proxy prioritario.
Il proxy standard utilizzato per gestire ogni connessione con fork
e il processo figlio gestisce la connessione. Ora ho implementato un meccanismo di accodamento di priorità in cui i pacchetti provenienti da entrambi i lati delle connessioni vengono accodati e rimossi dalla coda: i pacchetti provenienti da client e server remoti vengono accodati nel mio proxy, mentre i pacchetti vengono rimossi dalle code e inviati ai client o ai server remoti. I pacchetti vengono inseriti con un algoritmo prioritario di mine e i pacchetti rimossi sono quelli con la priorità più alta.
Ho pensato tre possibili implementazioni del meccanismo receive packets from clients and servers and send packets with high priority to destination
, ma nessuna delle tre mi soddisfa o ha qualche problema concettuale.
1) Il proxy di fork genera i processi figli, ognuno dei quali deve "parlare" con le code di priorità, nel processo main
: ciò richiederebbe un qualche tipo di IPC e per uno scambio veloce di dati come una connessione TCP IPC non sembra una buona idea.
2) Potrei conservare tutto in main
: loop con select
su tutti i descrittori di file socket (lato client e server) memorizzati in una lettura fd_set
(in modo che possa ricevere i pacchetti che arrivano al proxy e conservarli in code prioritarie). I pacchetti che devono essere inviati al client o al server vengono prima rimossi dalle code, ma il socket che userò per inviare il pacchetto potrebbe bloccarsi: quindi, rendere il socket non bloccante o generare un thread che invierà solo un pacchetto e poi morire?
3) La terza opzione consiste nell'utilizzare un thread per connessione: ancora una volta, ogni thread dovrà parlare con le code prio, inserendo pacchetti ricevuti da client e server in code e inviando pacchetti presi dalle code alla sua destinazione. Ma una richiesta HTTP CONNECT non è un semplice ciclo di ricezione dal server fd: richiede un ciclo select
in cui i pacchetti ricevuti dall'esterno vengono accodati e nel frattempo devo inviare i pacchetti rimossi dalla coda alla destinazione.
Non sono il tipo faccio le mie cose per me , ma ho trovato solo tre soluzioni e non riesco a capire altri modi.
Lavorare su Ubuntu 14.04, C ++ 11.
Modifica Fornirò ulteriori informazioni: il seguente metodo viene chiamato dal thread di rimozione dopo aver rimosso il pacchetto con la massima priorità dalle code prio:
void dealPacket(Packet p) {
int client = p.clientFD;
int server;
Request req = p.request;
std::string payload = p.payload;
// if there's no server file descriptor,
// this is the request packet coming from clients
if (p.server == -1) {
// open remote server fd, connect to it
// and return the server fd
server = openBindConnect(p.address);
if (req == GET) {
// send GET request to server
if (sendGETRequest(server, payload)) {
char data[1500];
// while server sends packets,
// queue them up
do {
Packet newPacket = craftPacket(data);
insertPacket(newPacket);
} while (recv(server, data));
}
}
else if (req == CONNECT) {
// if connection was successful, must send
// a "200 OK" packet to client, then client and
// server will start sending and receiving
if (send200OKtoClient(client)) {
while (true) {
char data[1500];
FD_SET(client, &readset);
FD_SET(server, &readset);
// select() loop is used to check if
// client or server sent packets; if so,
// queue them up
select(maxFD, &readset);
if (FD_ISSET(client, &readset)) || if (FD_ISSET(server, &readset)) {
// receive Packets from client or server;
Packet newPacket = craftPacket(data);
// insert in queues
insertPacket(newPacket);
}
}
}
}
}
// if this packets belong to an already existing connection,
// just send it (or close the socket pair <client,server> if
// this packet is the last one of one connection)
else {
server = p.serverFD;
if (p.lastPacket) {
close(client);
close(server);
}
else {
// send packet to destination
}
}
}
Come puoi vedere, è un metodo abbastanza discutibile: ci sono send
e recv
, e questo syscalls può bloccare il thread, che è il thread di rimozione, e nel frattempo le code di priorità potrebbero essere state riempite mentre il thread di rimozione è bloccato a causa di send
o recv
.
Potrebbe essere più comodo se il thread di rimozione fosse in grado di rimuovere pacchetti e lasciare che qualcos'altro li gestisse : per ogni pacchetto dequeued, il thread di rimozione può generare un thread che aprirà una nuova connessione (se il pacchetto è una richiesta HTTP) o invierà semplicemente il pacchetto alla sua destinazione. Ma così facendo, molti thread nascono e muoiono molto rapidamente, quindi hanno più interruttori di contesto del solito.