Ваш цикл tunnel()
полностью игнорирует возвращаемые значения read()
и write()
.Вместо этого попробуйте что-то вроде этого:
bool writeAll(int sckt, void *buffer, size_t buflen)
{
char *pbuffer = (char*) buffer;
while (buflen > 0)
{
ssize_t numSent = write(sckt, pbuffer, buflen);
if (numSent < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
return false;
}
pbuffer += numSent;
buflen -= numSent;
}
return true;
}
...
strcpy(buffer, "HTTP/1.0 200 Connection established\r\n\r\n");
if (writeAll(client, buffer, strlen(buffer)))
tunnel(server, client, buffer);
close(client);
close(server);
return;
...
void tunnel(int server, int client, char *buffer)
{
int maxFD = max(server, client) + 1;
ssize_t numRead;
FD_SET fd;
int x = fcntl(server, F_GETFL, 0);
fcntl(server, F_SETFL, x | O_NONBLOCK);
x = fcntl(client, F_GETFL, 0);
fcntl(client, F_SETFL, x | O_NONBLOCK);
do
{
cout << "test" << endl;
FD_ZERO(&fd);
FD_SET(&fd, server);
FD_SET(&fd, client);
x = select(maxFD, &fd, NULL, NULL, NULL);
if (x < 0) break;
if (FD_ISSET(&fd, client))
{
numRead = read(client, buffer, BUFSIZE);
if (numRead <= 0) break;
if (!writeAll(server, buffer, numRead))
break;
}
if (FD_ISSET(&fd, server))
{
numRead = read(server, buffer, BUFSIZE);
if (numRead <= 0) break;
if (!writeAll(client, buffer, numRead))
break;
}
}
while (true);
}
Что касается того, почему ваши чтения не всегда возвращают 0, когда вы ожидаете, это, скорее всего, из-за того, что клиент и сервер используют HTTP-keep-alive, чтобы сохранитьтуннельное соединение открывается после того, как сервер отправил свой ответ, поэтому клиент может отправлять последующие запросы на тот же сервер, используя то же TCP-соединение.Установление нового соединения TCP и даже нового сеанса HTTPS для каждого HTTP / S-запроса занимает много времени и тратит пропускную способность, поскольку включает в себя многократные обходы для квитирования TCP и TLS.Таким образом, стандартное поведение HTTP 1.1 и более поздних версий заключается в том, чтобы поддерживать соединение открытым, если ни одна из сторон явно не заявит, что закрытие требуется через заголовок Connection: close
.