用VC++实现http代理 1

来源(czn.com.cn)

From: http://www.czn.com.cn/exec/2005_12/3/200512381513.shtml

用VC++实现http代理 1
http://www.czn.com.cn2005-12-3soldier_CZN

为了帮网友些个用http下载动画的程序,临时在网上翻了翻,看看有没有利用http代理来下载的例子。结果,似乎很多人都愿意去转载一个有头无尾的例子,还美其名曰“我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。”

如果真的想帮助大家,为什么不说的详细一些?

无奈之下,自己去翻rfc文档,找了些资料,写了这个利用http代理来下载文件的资料

代码如下:

(1)一些基本变量

SOCKET HTTPSocket; // 主socket
struct sockaddr_in SocketAddr; // address socket
struct sockaddr_in BindSocket; // for bind


int m_nRecvTimeout; // recieve timeout
int m_nSendTimeout; // send timeout

WSADATA wsaData;

// 要下载文件部分。好像在BindSocket.sin_addr.s_addr = inet_addr (strHost);时,只能使用ip地址,所以了。。。

// 如果谁知道更好的方法,别忘了告诉我一下。

CString strHost="111.111.111.111 ";
CString DownLoadAddress="http://www.aitenshi.com/bbs/images/";
CString hostFile="logo.gif";
int HttpPort=80;


(2)一些函数,用来取得http头,和获取文件大小

int GetFileLength(char *httpHeader) {
    CString strHeader;
    int local;
    strHeader=(CString)httpHeader;
    local=strHeader.Find("Content-Length",0);
    local+=16;
    strHeader.Delete(0,local);
    local=strHeader.Find("\r");
    strHeader.SetAt(local,'\0');

    char temp[30];
    strcpy(temp,strHeader.GetBuffer(strHeader.GetLength()));
    return atoi(temp);
}

int GetHttpHeader(SOCKET sckDest,char *str) {
    BOOL m_bResponsed=0;
    int m_nResponseHeaderSize;

    if(!m_bResponsed) {
        char c = 0;
        int nIndex = 0;
        BOOL bEndResponse = FALSE;
        while(!bEndResponse && nIndex < 1024) {
            recv(sckDest,&c,1,0);
            str[nIndex++] = c;
            if(nIndex >= 4) {
                if(str[nIndex - 4] == '\r' && str[nIndex - 3] == '\n' && str[nIndex - 2] == '\r' && str[nIndex - 1] == '\n')
                    bEndResponse = TRUE;
            }
        }
        m_nResponseHeaderSize = nIndex;
        m_bResponsed = TRUE;
    }

    return m_nResponseHeaderSize;
}



(3)用来发送的部分

void szcopy(char* dest,const char* src,int nMaxBytes) {
    int i_cntr=0;
    while ((src[i_cntr]!='\0')  (i_cntr dest[i_cntr]=src[i_cntr++];
    dest[i_cntr]='\0';
}

BOOL SocketSend(SOCKET sckDest,const char* szHttp) {
    char szSendHeader[MAXHEADERLENGTH];
    int iLen=strlen(szHttp);
    szcopy(szSendHeader,szHttp,iLen);
    if(send (sckDest ,(const char FAR *)szSendHeader ,iLen ,0)==SOCKET_ERROR) {
        closesocket(sckDest);
        AfxMessageBox("Error when send");
        return FALSE;
    }

    return TRUE;
}

BOOL SocketSend(SOCKET sckDest,CString szHttp) {

    int iLen=szHttp.GetLength();
    if(send (sckDest,szHttp,iLen,0)==SOCKET_ERROR) {
        closesocket(sckDest);
        AfxMessageBox("Error when send");
        return FALSE;
    }

    return TRUE;
}



(4)用于连接的函数

这里是做了一些连接用的操作,分了两种情况

1)如果没有使用代理,则直接连到你指定的计算机

2)如果使用了代理,则直接连到代理

BOOL CDLAngelDlg::ConnectHttp(){

    message="正在建立连接\n";


    UpdateData(TRUE);
    if(m_combo=="HTTP") { // m_combo 一个下拉条

        HTTPSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        SocketAddr.sin_addr.s_addr = inet_addr (m_ProxyAddr);
        SocketAddr.sin_family=AF_INET;
        SocketAddr.sin_port=htons(atoi(m_Port));

        struct fd_set fdSet;
        struct timeval tmvTimeout={0L,0L};

        FD_ZERO(&fdSet);
        FD_SET(HTTPSocket, &fdSet);

        if (select(0,&fdSet,NULL,NULL,&tmvTimeout)==SOCKET_ERROR) {
            closesocket(HTTPSocket);
            AfxMessageBox("Error when select.");
            return 0;
        }


        if (connect(HTTPSocket, (const struct sockaddr *)&SocketAddr, sizeof(SocketAddr))==SOCKET_ERROR) {
            message="\n代理连接失败\n";
            m_message.CleanText();
            m_message.AddText(message);
            return 0;
        }


        // 发送CONNCET请求令到代理服务器,用于和代理建立连接

        //代理服务器的地址和端口放在m_ProxyAddr,m_Port 里面

        CString temp;
        char tmpBuffer[1024];
        temp.Format("CONNECT %s:%s HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n",m_ProxyAddr,m_Port);
        if(!SocketSend(HTTPSocket,temp)) {
            message="连接代理失败";
            return 0;
        }

        // 取得代理响应,如果连接代理成功,代理服务器将返回200 Connection established

        GetHttpHeader(HTTPSocket,tmpBuffer);
        temp=tmpBuffer;
        if(temp.Find("HTTP/1.0 200 Connection established",0)==-1) {
            message="连接代理失败\n";
            return 0;
        }

        message="代理连接完成\n";
        m_message.AddText("代理连接完成\n");
        return 1; // ----------〉这里是应该注意的,连接到代理后,就可以返回了,不需要再连接网上的另外一台机,代理服务器会自动转发数据,所以,连接完代理就像连接到网上另外一台机一样
    } else if(m_combo=="Socks4") { // 这个,是为了给其他代理做准备
        MessageBox("请注意,现在无法使用代理功能!");
    } else if(m_combo=="Socks5") {
        MessageBox("请注意,现在无法使用代理功能!");
    }


    // 如果没有使用代理,就要连接到网上的另一台机

    // 准备socket
    HTTPSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    if (HTTPSocket==INVALID_SOCKET) {
        AfxMessageBox("Error when socket");
        return 0;
    }

    //设置超时
    struct linger zeroLinger;
    zeroLinger.l_onoff = 1;
    zeroLinger.l_linger = 0;
    if(setsockopt(HTTPSocket,SOL_SOCKET,SO_LINGER ,(const char *)&zeroLinger ,sizeof(zeroLinger))!=0) {
        closesocket(HTTPSocket);
        AfxMessageBox("Error when setscokopt(LINGER)");
        return 0;
    }


新闻来源:网络

Link: http://www.asm32.net/article_details.aspx?id=7


浏览次数 469 发布时间 2005/12/3 0:00:00 从属分类 VC++ 【评论】【 】【打印】【关闭
 
| www.asm32.net | 2006版 | 资料中心 | linux | asm/asm32 | C/C++ | VC++ | java | Python | 书签 | ASP.Net书签 | 京ICP备09029108号-1