if(port == 443){ // https
strcpy(buffer, "HTTP/1.0 200 Connection established\r\n\r\n");
write(client, buffer, strlen(buffer));
tunnel(server, client, buffer);
return;
}
tunnel()如下所示
void tunnel(int server, int client, char* buffer){
int servercon, clientcon;
int x;
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);
while(true){
cout << "test" << endl;
clientcon = read(client, buffer, BUFSIZE);
write(server, buffer, clientcon);
servercon = read(server, buffer, BUFSIZE);
write(client, buffer, servercon);
if(???) // This condition
break;
}
close(client);
close(server);
}
当代理服务器收到CONNECT方法时,我试图实现隧道。 此代码运行良好(HTTPS网站已成功加载) 但是,问题是无限的while()循环无法转义,因为read()函数有时永远不会返回0。
作为休息条件,我尝试了几种选择。
1)servercon == 0(有时read()函数永远不会返回0)
2)servercon == -1(发生安全连接失败。我不知道为什么)
3)添加一个变量i作为计时器,i&lt; 100000(它工作,但效率太低)
我应该如何设置休息条件?
(使套接字无阻塞是必要的。没有它,程序将永远停在read()函数。我不知道原因,但使套接字无阻塞解决了问题。)
答案 0 :(得分:1)
您的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连接将后续请求发送到同一服务器。在每个HTTP / S请求上建立新的TCP连接,甚至是新的HTTPS会话都非常耗时并且浪费带宽,因为它涉及TCP和TLS握手的多次往返。因此,HTTP 1.1及更高版本的默认行为是保持连接处于打开状态,除非任何一方通过Connection: close
标头明确声明需要关闭。