我利用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文件的访问的返回的文本):
伊谢尔伦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)
变成这样,结果就没有乱码了。
以上就是解决方法。
最后,我还是没有搞清楚原因,请各位指教?
ringa_lee2017-04-17 13:27:08
你贴出来的乱码是怎么来的,终端打印出来的吗?
建议先不要看打印的情况,先把输出保存到一个文件中,然后取出该文件用其它文本编辑器打开看看是不是乱码。
我觉得有可能你看到的乱码只是你终端的编码问题,跟你代码没关系。