首頁  >  問答  >  主體

c++利用socket模拟http,返回乱码

我利用c++的socket模拟了http访问某网站,结果返回乱码。
这个乱码很奇怪,它不是完全乱码,具体情况就是:
一部分中文乱码,一部分英文乱码,大部分还是正确的。
我用wireshark查看的时候,发现http返回是200。同时,我查看了返回的html文本,也是正确的。但就是在用socket接收的时候,会出现部分乱码。

对于本程序,我的思路是:
在myhttp.h中,封装一个mysocket的类,实现socket的connect,send和recv。recv是采用非阻塞的方式。为了保证所有的来自服务端的数据已经在缓存区,所以在send后sleep(1)后才调用recv。另外,我还封装了一个myhttp类,继承于mysocket。myhttp主要是接收各种http参数,然后构造出一个http请求,然后发送。

test.cc主要是对myhttp的调用。

下面是我的代码:
myhttp.h

#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <initializer_list>
#include <unistd.h>

class mysocket{
private:
    int sockfd;
    struct sockaddr_in servaddr;
    string response;
protected:
    mysocket(string ip,string port){
        const char * c_ip = ip.c_str();
        const char * c_port = port.c_str();
    
        this->sockfd = socket(AF_INET,SOCK_STREAM,0);
        memset(&(this->servaddr),0,sizeof(this->servaddr));
        (this->servaddr).sin_family = AF_INET;
        (this->servaddr).sin_port = htons(atoi(c_port));
        inet_pton(AF_INET,c_ip,&(this->servaddr).sin_addr);
    }
    void mysocket_connect(){
        connect(this->sockfd,(struct sockaddr*)&(this->servaddr),sizeof(this->servaddr));
    }
    void mysocket_send(string request){
        const char * c_request = request.c_str();
        send(this->sockfd,c_request,strlen(c_request),0);
        sleep(1);    
    }
    void mysocket_recv(){
        char buf[1024];
        memset(&buf,0,sizeof(buf));
        while(int recvlength = recv(this->sockfd,buf,sizeof(buf),MSG_DONTWAIT)){
            if(recvlength < 0)
                break;
            else{
                this->response += buf;
                memset(&buf,0,sizeof(buf));
                
            }
        }
        cout << this->response;
    }
};

class myhttp:public mysocket{
private:
    string ip;
    string port;
    //得到数据length
    string getLength(string data){
        int length = data.size();
        char lenstr[12] = {0};
        sprintf(lenstr,"%d",length);
        return string(lenstr);
    }

    
    
public:    
    myhttp(string ip,string port):mysocket(ip,port){    //调用父类构造函数
        this->ip = ip;
        this->port = port;
    }
    
    //path,addition
    void GET(string path,initializer_list<string> args){
        //处理可变长度参数
        string addition = "";
        for(auto arg : args)
            addition = addition + arg + "\r\n";
        //形成http请求
        string http_request = "GET " + path + " HTTP/1.1\r\nHost: " + this->ip + ":" + this->port + "\r\n" + addition + "\r\n";
        
        this->mysocket_connect();
        this->mysocket_send(http_request);
        this->mysocket_recv();
        //while(1){}
    }

    //path,data,contentType,addition
    void POST(string path,string data,string contentType,initializer_list<string> args){
        //处理可变长度参数
        string addition = "";
        for(auto arg : args)
            addition = addition + arg + "\r\n";
        //得到data长度
        string length = this->getLength(data);
        //形成http请求
        string http_request = "POST " + path + " HTTP/1.1\r\nHost: " + this->ip + ":" + this->port + "\r\nContent-Type: " + contentType + "\r\ncontent-length: " + length + "\r\n" + addition + "\r\n" + data;
        this->mysocket_connect();
        this->mysocket_send(http_request);
        this->mysocket_recv();
        //while(1){}
    }
};

test.cc

#include <iostream>
#include <fstream>
  
using namespace std;
 
#include "myhttp.h"
 
int main(){
    myhttp * Myhttp = new myhttp("123.57.236.235","80");
    Myhttp->GET("/Public/js/jquery.min.js",{});
    return 0;
}

乱码部分(比如对某jquery文件的访问的返回的文本):

大家讲道理大家讲道理2765 天前627

全部回覆(4)我來回復

  • 伊谢尔伦

    伊谢尔伦2017-04-17 13:27:08

    看來我自己來寫答案吧!終於解決了!希望能幫到後來的人。

    以下是我的分析與解決過程:

    首先,我發現了一個問題:
    兩個亂碼位置之間的距離為1024個字元。而在我的程式中,recv中的buf的大小為char buf[1024]。兩個1024是不是太巧了?

    然後,我嘗試了一下在每一次recv後,呼叫strlen(buf)。理論上應該輸出1024吧? (至少不會大於1024)。然後,結果卻是,strlen(buf)的值為1030,超出了6個。然後我在想,亂碼是不是來自那6個超出的陣列元素?

    於是,我開始更改recv中的參數值:
    recv(this->sockfd,buf,(sizeof(buf) - 6),MSG_DONTWAIT)
    變成這樣,結果就沒有亂碼了。

    以上就是解決方法。

    最後,我還是沒有搞清楚原因,請各位指教?

    回覆
    0
  • 迷茫

    迷茫2017-04-17 13:27:08

    能把部分亂碼貼上來麼

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 13:27:08

    最好不要用cpp來做這種,處理字串很頭痛。

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 13:27:08

    你貼出來的亂碼是怎麼來的,終端印出來的嗎?
    建議先不要看列印的情況,先把輸出儲存到一個檔案中,然後取出該檔案用其它文字編輯器打開看看是不是亂碼。
    我覺得有可能你看到的亂碼只是你終端機的編碼問題,跟你代碼沒關係。

    回覆
    0
  • 取消回覆