TCP 代理转发数据示意图如下:
Client <--------------------------->TCP Proxy <---------------------------->Server
Client 先发起请求,代理在接收到connect 请求之后,新建一个线程处理该客户端的转发需求。
在调用recv 接收数据时,有时程序会一直阻塞在那里,原因是socket 默认是阻塞模式,而当前没有数据可接收时会一直等待。还有另一个情况:调用一次recv, 数据并没有接收完全,再调用recv 时仍然会阻塞。在应用层除非明确知道结束标志或者数据长度,否则没法知道数据是否已接收完毕。
正确的做法是轮询,使用select 实现,当某个socket处于可以接收时,就去读取数据,然后用另一个socket 转发。
实现的方法:
fd_set readfds;
TIMEVAL tv;
tv.tv_usec = 100;
tv.tv_sec = 1;
do{
FD_ZERO(&readfds);
FD_SET(socket_client, &readfds);
FD_SET(socket_server, &readfds);
int n = select(0, &readfds, NULL, NULL, &tv);
if (n>0) //有数据可读
{
if (FD_ISSET(socket_client, &readfds))
{
int nr = recv(socket_client, buffer, buffer_size, 0);
if (nr > 0)
int ns = send(socket_server, buffer, nr, 0);
}
if (FD_ISSET(socket_server, &readfds))
{
int nr = recv(socket_server, buffer, buffer_size, 0);
if (nr > 0)
int ns = send(socket_client, buffer, nr, 0);
}
}
else if (n == SOCKET_ERROR) //选择错误
{
printf("select error");
break;
}
else //超时,Sleep 1s
{
Sleep(1000);
}
}while(true);
参考:
https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select