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