Winsock C++ Proxy

Winsock C++ Proxy

本文关键字:Proxy C++ Winsock      更新时间:2023-10-16

我想让这段代码工作:

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib" ) 
#include <Windows.h>
using namespace std;
int port = 5012;
SOCKET listen_sock;
SOCKET client_sock;
char FR_recv_buf [1048576] = "";
char recv_buf [102400] = "";
int Receive();
int Listen();
//function to initialize winsock
bool InitializeWinsock()
{
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if(iResult != 0)
    {
        cout << "WSAStartup failed with error: " << iResult << endl;        
        return false;
    }
    else
    {
        cout << "WSAStartup successfully initialized." << endl; 
        return true;
    }
}
int ForwardResponse()
{
    if (send(client_sock, FR_recv_buf, sizeof(FR_recv_buf), 0) == SOCKET_ERROR)
    {
        cout << "Forward Response: send() failed with error: " << WSAGetLastError() << endl;
        closesocket(client_sock);
        //WSACleanup();
        return 0;
    }
    else
    {
        cout << "Forward Response: send() success.n";
        //go back to begginning again?
        Receive();
        //CreateThread(0,0,(LPTHREAD_START_ROUTINE)Receive, 0, 0 ,0);
    }   
}
//Function to parse hostname from http request
string ParseHostname(char * buf)
{
    size_t pos;
    //string to hold hostname substring
    string hostname_t;  
    //copy request to string for easier parsing
    string httpheader = buf;
    pos = httpheader.find("Host: ");//find "Host: " line
    hostname_t = httpheader.substr(pos + 6);//copy to substring, not                 including "Host: ", just the hostname
    pos = hostname_t.find("rn");// find end of line
    hostname_t.erase(pos);//erase the rest of the string which is unwanted
    return hostname_t;
}
//Function to forward HTTP request from browser to webserver
int ForwardRequest()
{
    int bytes_received;
    SOCKADDR_IN Dest;
    SOCKET frecv_sock;
    hostent *Host;
    //parse hostname from http request
    string hostname = ParseHostname(recv_buf);
    if((Host=gethostbyname(hostname.c_str()))==NULL)
    {
        DWORD dwError = WSAGetLastError();
        if (dwError != 0)
        {
            if(dwError == WSAHOST_NOT_FOUND) 
            {
                cout << "Host " << hostname.c_str()  << " not found.n";
                WSACleanup();
                return FALSE;
            }
            else if (dwError == WSANO_DATA) 
            {
                cout << "No data record found.n";;
                WSACleanup();
                return FALSE;
            }
            else
            {
                cout << "Function failed with error: " << dwError << endl;
                WSACleanup();
                return FALSE;
            }
        }
    }
    else
    {
        cout << "Successfully connected to host: " <<  hostname.c_str() << endl;
        //privmsg(wsockdl.sock,sendbuf,curchan);
    }
    Dest.sin_family=AF_INET;
    Dest.sin_port=htons(80);
    memcpy(&Dest.sin_addr,Host->h_addr,Host->h_length);
    // Create a SOCKET for connecting to server
    if((frecv_sock = socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
    {
        cout << "Forward Request: Error at socket(), error code: " <<     WSAGetLastError() << endl;
        closesocket(frecv_sock);
        WSACleanup();
        return FALSE;
    }
    // Connect to server
    if(connect( frecv_sock,(SOCKADDR*)&Dest,sizeof(Dest))==SOCKET_ERROR)
    {
        cout << "Forward Request: connect() failed, error code: " << WSAGetLastError() << endl;
        closesocket( frecv_sock);
        WSACleanup();
        return FALSE;
    }
    //send intercepted request to server
    if (send(frecv_sock, recv_buf, strlen(recv_buf), 0) == SOCKET_ERROR)
    {
        cout << "Forward Request: send() failed with error: " << WSAGetLastError() << endl;
        closesocket(frecv_sock);
        WSACleanup();
        return 0;
    }
    else
    {
        cout << "Forward Request: send() success.n";       
    }   
    //receive request from server
    do{
        bytes_received = recv(frecv_sock,FR_recv_buf,sizeof(FR_recv_buf),0);
        if (bytes_received > 0){
            strcat (FR_recv_buf, "");
            cout << "Forward Request: recv() success. Bytes received: " << bytes_received << endl;
            CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ForwardResponse, 0 ,0 ,0);
            //ForwardResponse();
        }
        else if ( bytes_received == 0 ){
            cout << "Forward Request: Connection closedn";
            closesocket(frecv_sock);
        }
        else if ( bytes_received == SOCKET_ERROR){
            cout << "Forward Request: recv() failed with error: " << WSAGetLastError() << endl;
            closesocket(frecv_sock);
            WSACleanup();
            return 0;
        }
    }while (bytes_received > 0);
}
//Function to accept connection and receive data from browser
int Receive()
{
    SOCKADDR_IN csin;
    int csin_len = sizeof(csin);
    int iResult;
    //accept client connection
    client_sock = accept(listen_sock , (LPSOCKADDR)&csin, &csin_len);//pauses here to wait for connection from client
    if (client_sock == INVALID_SOCKET) {
        cout << "accept failed with error: "<< WSAGetLastError() << endl;
        closesocket(client_sock);
        WSACleanup();
        return 1;
    }
    else{
        cout << "Client connection from IP: " << inet_ntoa(csin.sin_addr) << ":" << csin.sin_port << endl;      
    }
    CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0); //Start another thread to accept.
    do {
        iResult = recv(client_sock, recv_buf, sizeof(recv_buf), 0);
        if (iResult == SOCKET_ERROR) {
            closesocket(client_sock);
            WSACleanup();
            cout << "Receive: recv() failed with error: "<< WSAGetLastError() << endl;      
        }
        else if (iResult > 0){
            //null terminate receive buffer
            //recv_buf[iResult] = '';
            strcat(recv_buf, "");
            cout <<"Receive: Bytes received: " << iResult << endl;
            //forward HTTP request from browser to web server
            cout << recv_buf << endl;
            HANDLE pChildThread = CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)ForwardRequest, 0 , 0 ,0);
            WaitForSingleObject(pChildThread,60000);  //Wait for connection between proxy and remote server
            CloseHandle(pChildThread);      
        }
        else if ( iResult == 0 ){
            cout << "Receive: Connection closedn";
        }
    }while ( iResult > 0 );
    return 0;
}
//Function which listens for incoming connections to the proxy
int Listen()
{
    SOCKADDR_IN local;
    memset(&local,0,sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(port);
    local.sin_addr.s_addr = INADDR_ANY;
    //create socket for listening to
    listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    //bind function associates a local address with a socket.
    if (bind(listen_sock, (LPSOCKADDR)&local, sizeof(local)) == 0) 
    {   
        if (listen(listen_sock, 10) == 0) 
        {
            cout << "Listening on: " << port << endl; 
        }
        else
        {
            cout << "Error listening on socket.n";
        }
    }
    else{
        cout << "bind() failed with error: "<< WSAGetLastError() << endl;
    }   
    //accept and start receiving data from broswer
    CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0);
    return 0;
}
int CloseServer()
{
    closesocket(client_sock);
    WSACleanup();
    return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
    InitializeWinsock();
    Listen();
    cin.get();
    return 0;
}

但是似乎连接过早结束,或者recv()send()功能失败。除了无法连接外,我的浏览器上什么都没有显示。有人能发现问题吗?

一个主要问题是您只有一个客户端套接字。您创建的每个线程共享相同的客户端套接字,因此如果在第一个连接完成之前建立了两个连接,则第一个套接字将被第二个连接覆盖。请记住,线程共享进程中的所有内存,包括全局变量之类的东西。

编辑:既然你正在使用c++,为什么不封装变量和函数在一个类?而不是静态地为缓冲区分配内存,而是在堆上使用new创建它们。

编辑2

简单多线程服务器:

class Connection
{
public:
    Connection()
        : buffer(0), buffer_size(0)
        { }
    void run(SOCKET sock);
privat:
    SOCKET input_socket;  // Socket we read from
    SOCKET output_socket; // Socket we write to
    char *buffer;         // Buffer we read data into, and write data from
    size_t buffer_size;   // Total size of buffer (allocated memory)
    size_t read_size;     // Number of bytes read
    void connect();
    void recv();
    void send();
};
void Connection::run(SOCKET sock)
{
    input_socket = sock;
    if (buffer == 0)
    {
        // Allocate buffer
    }
    // Connect to the real server
    connect();
    for (;;)
    {
        try
        {
            recv();
            send();
        }
        catch (exception &e)
        {
            std::cerr << "Error: " << e.what() << 'n';
            break;
        }
    }
    // Clean up
    delete [] buffer;
    closesocket(output_socket);
    closesocket(input_socket);
}
void Connection::recv()
{
    // Read data into the buffer, setting "read_size"
    // Like: read_size = recv(input_socket, buffer_size, 0);
    // Throw exception on error (includes connection closed)
    // NOTE: If error is WSAEWOULDBLOCK, set read_size to 0, don't throw exception
}
void Connection::send()
{
    if (read_size > 0)
    {
        // Send data from the buffer
        // Like: send(output_socket, buffer, read_size, 0))
        // Throw exception on error
    }
}
void Connection::connect()
{
    // Connect to the real server
    // Set the output_socket member variable
}
DWORD client_thread(LPVOID param)
{
    SOCKET socket = (SOCKET) param;
    // Make socket nonblocking
    int mode = 1;
    ioctlsocket(socket, FIONBIO, &mode)
    // Main thread stuff
    Connection connection;
    connection.run(socket); 
}
int main()
{
    // Create master socket, and other initialization
    for (;;)
    {
        SOCKET client_socket = accept(...);
        CreateThread(0, 0 , (LPTHREAD_START_ROUTINE) client_thread,
            (LPVOID) client_socket , 0 ,0);
    }
    // Clean up
}

另一个主要问题是,您将''附加到接收到的缓冲区中,显然期望send()将识别它并从那里停止发送,即使send()的大小参数是sizeof(FR_recv_buf),这是它真正尊重的。另一个问题是,像FR_recv_buf这样的数据项是实例变量,而不是局部变量,因此您不能处理多个并发连接。