Winsock C ++代理

时间:2011-12-04 00:59:25

标签: c++ networking tcp proxy winsock

我正在尝试使用此代码:

#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("\r\n");// 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, "\0");
            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 closed\n";
            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] = '\0';
            strcat(recv_buf, "\0");
            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 closed\n";
        }
    }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()函数失败。除了无法连接外,我的浏览器上没有显示任何内容。有谁能发现问题?

2 个答案:

答案 0 :(得分:4)

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

编辑:由于您使用的是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
}

答案 1 :(得分:0)

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