版主考勤工资设为首页收藏本站

姜堰人民论坛-姜堰第一门户社区

 找回密码
 加入人坛
搜索
查看: 1834|回复: 1
打印 上一主题 下一主题

用C++實現http代理

[复制链接]
跳转到指定楼层
楼主
发表于 2008-8-12 14:34:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
為了幫網友些個用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] == ''
    && str[nIndex - 2] == '\r' && str[nIndex - 1] == '')
    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="正在建立連接";


    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="代理連接失敗";
    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\rUser-Agent: MyApp/0.1\r\r",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="連接代理失敗";
    return 0;
    }

    message="代理連接完成";
    m_message.AddText("代理連接完成");
    return 1; // ----------〉這里是應該注意的,連接到代理后,就可以返回了,不需要再連接網上的另外一臺機,代理服務器會自動轉發數據,所以,連接完代理就像連接到網上另外一臺機一樣
    }

    // 這個,是為了給其他代理做準備
    else if(m_combo=="Socks4")
    {MessageBox("請注意,現在無法使用代理功能!");}
    else if(m_combo=="Socks5")
    {MessageBox("請注意,現在無法使用代理功能!");}


    // 如果沒有使用代理,就要連接到網上的另一臺機
沙发
 楼主| 发表于 2008-8-12 14:34:44 | 只看该作者
// 準備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;
    }
      //設置接收超時
    if(setsockopt(HTTPSocket,SOL_SOCKET,SO_RCVTIMEO
    ,(const char *)&m_nRecvTimeout
    ,sizeof(m_nRecvTimeout))!=0)
    {
    closesocket(HTTPSocket);
    AfxMessageBox("Error when setsockopt(RCVTIME).");
    return 0;
    }

    //設置發送超時
    if(setsockopt(HTTPSocket,SOL_SOCKET,SO_SNDTIMEO
    ,(const char *)&m_nSendTimeout
    ,sizeof(m_nSendTimeout))!=0)
    {
    closesocket(HTTPSocket);
    AfxMessageBox("Error when setsockopt(SNDTIMEO).");
    return 0;
    }


    SocketAddr.sin_addr.s_addr = htonl (INADDR_ANY);
    SocketAddr.sin_family=AF_INET;

    // 進行端口綁定
    if (bind (HTTPSocket,
    (const struct sockaddr FAR *)&SocketAddr,
    sizeof(SocketAddr))==SOCKET_ERROR)
    {
    closesocket(HTTPSocket);
    AfxMessageBox("Error when bind socket.");
    return 0;
    }

    //準備連接

    /// 準備連接信息
    BindSocket.sin_addr.s_addr = inet_addr (strHost);
    BindSocket.sin_family=AF_INET;
    BindSocket.sin_port=htons(HttpPort);


    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 *)&BindSocket, sizeof(BindSocket))==SOCKET_ERROR)
    {
    AfxMessageBox("第一次連接失敗,準備第二次連接");
    if (connect(HTTPSocket
    ,(const struct sockaddr *)&BindSocket
    ,sizeof(BindSocket))==SOCKET_ERROR)
    {
    closesocket(HTTPSocket);
    AfxMessageBox("連接失敗");
    return 0;
    }

    }

    message="連接完成";

    return 1;
    }


      (5)發送http請求,為下載數據進行準備

    int CDLAngelDlg::SendHttpHeader()
    {
    //進行下載

    CString temp;
    BOOL bReturn;
    char tmpBuffer[MAXBLOCKSIZE];
  ///第1行:方法,請求的路徑,版本
    temp="GET "+DownLoadAddress+hostFile+" HTTP/1.0\r";
    bReturn=SocketSend(HTTPSocket,temp);
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }


    ///第2行:主機
    temp="Host "+strHost+"\r";
    bReturn=SocketSend(HTTPSocket,temp);
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }


    ///第3行:接收的數據類型
    bReturn=SocketSend(HTTPSocket,"Accept: */*\r");
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }


    ///第4行:
    temp=DownLoadAddress;
    temp.Insert(0,"Referer ");
    temp+="\r";
    bReturn=SocketSend(HTTPSocket,temp);
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }


    ///第5行:瀏覽器類型

    bReturn=SocketSend(HTTPSocket,"User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent;)\r");
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }

    ///第6行:連接設置,保持
    // SocketSend(HTTPSocket,"Connection:Keep-Alive\r");

    ///第7行:Cookie.

    bReturn=SocketSend(HTTPSocket,"Cache-Control: no-cache\r");
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }


    bReturn=SocketSend(HTTPSocket,"Proxy-Connection: Keep-Alive\r");
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }

    /// 續傳

    Range是要下載的數據范圍,對續傳很重要
    if(continueFlag)
    {
    temp.Format("Range: bytes=%d- \r",conLength);
    bReturn=SocketSend(HTTPSocket,temp);
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }
    }
///最后一行:空行
    bReturn=SocketSend(HTTPSocket,"\r");
    if(!bReturn)
    {
    message="發送請求失敗";
    return 0;
    }

    ///取得http頭
    int i;
    i=GetHttpHeader(HTTPSocket,tmpBuffer);
    if(!i)
    {
    message="獲取HTTP頭出錯";
    return 0;
    }

    //如果取得的http頭含有404等字樣,則表示連接出問題
    temp=tmpBuffer;
    if(temp.Find("404")!=-1)
    {

    return 0;
    }

    // 得到待下載文件的大小

    filelength=GetFileLength(tmpBuffer);

    return 1;
    }


      這樣,就連接到網上的另一臺機了,如何下載數據,不用多說了吧

    while((num!=SOCKET_ERROR) && (num!=0))
    {
    num=recv (HTTPSocket
    ,(char FAR *)tmpBuffer
    ,(MAXBLOCKSIZE-1)
    ,0);


    file.Write(tmpBuffer,num);

    if(ExitFlag)
    {
    file.Close();
    closesocket(HTTPSocket);

    DownComplete=1;

    m_message.CleanText();
    m_message.ShowColorText(RGB(128,128,0),DLCompleteMes);

    m_progress.ShowWindow(SW_HIDE);
    m_stopDownload.ShowWindow(SW_HIDE);
    _endthread();
    }

    }


      基本就是這樣了,本人寫程序水平也不是很高,這個程序還是可以用的。
您需要登录后才可以回帖 登录 | 加入人坛

本版积分规则

关闭

站长推荐上一条 /1 下一条

姜堰论坛|姜堰人民论坛|姜堰第一门户社区 ( 苏ICP备18040877号-1 公安备案:浙公网安备33010802004735号  人坛成长的足迹:   

GMT+8, 2024-11-29 06:57 , Processed in 0.116274 second(s), 20 queries .

快速回复 返回顶部 返回列表