做完win socket后续修改实现Linux(jni,android)
萌新做笔记,请大佬勿喷,弟弟我屁话也不多,就不做详解了
QuickHttp.cpp核心
//
// Created by Administrator on 2022/7/31.
//
#include "QuickHttp.h"
int so;
string buf;
//WinSocket初始化
void QuickHttp::initWinSocket() {
WSADATA wsaData;
//参数:版本号,指向WSADATA结构体的指针
WSAStartup(MAKEWORD(2, 2), &wsaData);
so = socket(AF_INET, SOCK_STREAM, 0);
}
string QuickHttp::getBuf() {
return buf;
}
int QuickHttp::httpGet(const string &strUrl, const string &strMethod, const string &strData) {
//绑定地址端口
int iPort = getPortFromUrl(strUrl);
if (iPort < 0) {
debugOut("获取URL端口失败\n");
return -1;
}
string strIP = getIpFromUrl(strUrl);
if (strIP.empty()) {
debugOut("从URL获取IP地址失败\n");
return -1;
}
//创建HTTP协议表头
string strHttpHead = httpHeadCreate(strMethod, strUrl, strData);
SOCKADDR_IN in; //服务端地址
in.sin_port = htons(iPort);//连接端口6000
//绑定目标ip
if (inet_pton(AF_INET, strIP.data(), &in.sin_addr) <= 0) {
debugOut("inet_pton error ! Error code: %d,Error message:%s\n", errno, strerror(errno));
return -1;
}
in.sin_family = AF_INET;
//连接到服务端
int isRet = connect(so, (SOCKADDR *) &in, sizeof(SOCKADDR));
if (isRet == -1) {
return -1;
}
//非阻塞方式连接
send(so, strHttpHead.data(), strlen(strHttpHead.data()) , 0);
/**
* how的方式有三种分别是
* SHUT_RD(0):关闭sockfd上的读功能,此选项将不允许sockfd进行读操作。不允许接受。
* SHUT_WR(1):关闭sockfd的写功能,此选项将不允许sockfd进行写操作。不允许发送。
* SHUT_RDWR(2):关闭sockfd的读写功能。不允许发送和接受(和 close() 一样)。
**/
shutdown(so, 1);
buf = httpDataTransmit(so);
close(so);
WSACleanup();
return 1;
}
//发送HTTP请求并且接受响应
string QuickHttp::httpDataTransmit(int isSocFd) {
//接受服务器返回的信息
string info;//接受的信息
char ch;//每次接受的信息
int rlength = 0;//接受数据的总大小
int rlen = recv(isSocFd, &ch, 1, 0);//每次接受的数据大小
rlength += rlen;
while (rlen != 0 && rlen != SOCKET_ERROR) {
info += ch;
rlen = recv(isSocFd, &ch, 1, 0);//每次接受的数据大小
rlength += rlen;
}
//编码转换 防止在控制台显示乱码
char *pszBuffer = new char[info.length() + 1];
auto *pszWideBuffer = new wchar_t[(info.length() + 1) * 2];
memset(pszWideBuffer, 0, (info.length() + 1) * 2);
memset(pszBuffer, 0, info.length() + 1);
int cchWideChar = info.length() + 1;
MultiByteToWideChar(CP_UTF8, 0, info.c_str(), info.length(), pszWideBuffer, cchWideChar * 2);//将unicode编码,转换为宽字节
WideCharToMultiByte(CP_ACP, 0, pszWideBuffer, wcslen(pszWideBuffer), pszBuffer, info.length() + 1, NULL,
NULL);//将宽字节,转换为控制台编码
info = pszBuffer;
delete[] pszBuffer;
delete[] pszWideBuffer;
return info;
}
QuickHttp *QuickHttp::getInstance() {
return new QuickHttp();
}
//从HTTP请求URL中获取端口号
int QuickHttp::getPortFromUrl(const string &strUrl) {
int nPort = -1;
char *strHostAddr = (char *) getHostAddFromUrl(strUrl).data();
if (strHostAddr == NULL) {
return -1;
}
char strAddr[URLSIZE] = {0};
strcpy(strAddr, strHostAddr);
char *strPort = strchr(strAddr, ':');
if (strPort == NULL) {
nPort = 80;
} else {
nPort = atoi(++strPort);
}
return nPort;
}
//从Http请求URL中获取IP地址
string QuickHttp::getIpFromUrl(const string &strUrl) {
string url = getHostAddFromUrl(strUrl);
char *strHostAddr = (char *) url.data();
char *strAddr = (char *) malloc(strlen(strHostAddr) + 1);
memset(strAddr, 0, strlen(strAddr) + 1);
int nCount = 0;
int nFlag = 0;
for (int i = 0; i < strlen(strAddr) + 1; i++) {
if (strHostAddr[i] == ':') {
break;
}
strAddr[i] = strHostAddr[i];
if (strHostAddr[i] == '.') {
nCount++;
continue;
}
if (nFlag == 1) {
continue;
}
if ((strHostAddr[i] >= 0) || (strHostAddr[i] <= '9')) {
nFlag = 0;
} else {
nFlag = 1;
}
}
if (strlen(strAddr) <= 1) {
return NULL;
}
//判断是否为点分十进制IP,否则通过域名获取IP
if ((nCount == 3) && (nFlag == 0)) {
return strAddr;
} else {
struct hostent *he = gethostbyname(strAddr);
free(strAddr);
if (he == NULL) {
return NULL;
} else {
struct in_addr **addr_list = (struct in_addr **) he->h_addr_list;
for (int i = 0; addr_list[i] != NULL; i++) {
return inet_ntoa(*addr_list[i]);
}
return NULL;
}
}
}
//从URL中获取Host地址
//从URL中获取Host地址
string QuickHttp::getHostAddFromUrl(const string &strUrl) {
char url[URLSIZE] = {0};
strcpy(url, strUrl.c_str());
char *strAddr = strstr(url, "http://");
if (strAddr == NULL) {
strAddr = strstr(url, "https://");
if (strAddr != NULL) {
strAddr += 8;
}
} else {
strAddr += 7;
}
if (strAddr == NULL) {
strAddr = url;
}
char *strHostAddr = (char *) malloc(strlen(strAddr) + 1);
memset(strHostAddr, 0, strlen(strAddr) + 1);
for (int i = 0; i < strlen(strAddr) + 1; i++) {
if (strAddr[i] == '/') {
break;
} else {
strHostAddr[i] = strAddr[i];
}
}
string host = strHostAddr;
free(strHostAddr);
return host;
}
string QuickHttp::httpHeadCreate(const string &strMethod, const string &strUrl, const string &strData) {
string strHost = getHostAddFromUrl(strUrl);
string strParam = getParamFromUrl(strUrl);
string strHttpHead;
strHttpHead.append(strMethod);
strHttpHead.append(" /");
strHttpHead.append(strParam);
strHttpHead.append(" HTTP/1.1\r\n");
strHttpHead.append("User-Agent: Mozilla/4.0\r\n");
strHttpHead.append("Host: ");
strHttpHead.append(strHost);
strHttpHead.append("\r\n");
strHttpHead.append("Cache-Control: no-cache\r\n");
strHttpHead.append("Connection: Keep-Alive\r\n");
if (strMethod == "POST") {
char len[8] = {0};
unsigned long iLen = strData.size();
sprintf(len, "%lu", iLen);
strHttpHead.append("Content-Type: application/x-www-form-urlencoded\r\n");
strHttpHead.append("Content-Length: ");
strHttpHead.append(len);
strHttpHead.append("\r\n\r\n");
strHttpHead.append(strData);
}
strHttpHead.append("\r\n");
return strHttpHead;
}
//从HTTP请求URL中获取HTTP请求参数
string QuickHttp::getParamFromUrl(const string &strUrl) {
char url[URLSIZE] = {0};
strcpy(url, strUrl.c_str());
char *strAddr = strstr(url, "http://");
if (strAddr == NULL) {
strAddr = strstr(url, "https://");
if (strAddr != NULL) {
strAddr += 8;
}
} else {
strAddr += 7;
}
if (strAddr == NULL) {
strAddr = url;
}
char *strParam = (char *) malloc(strlen(strAddr) + 1);
memset(strParam, 0, strlen(strAddr) + 1);
int iPos = -1;
for (int i = 0; i < strlen(strAddr) + 1; i++) {
if (strAddr[i] == '/') {
iPos = i;
break;
}
}
if (iPos == -1) {
strcpy(strParam, "");
} else {
strcpy(strParam, strAddr + iPos + 1);
}
string param = strParam;
free(strParam);
return param;
}
QuickBody *QuickHttp::getQuickBody() {
QuickBody *quickBody = QuickBody::getInstance();
quickBody->Analysis(getBuf());
return quickBody;
}
void QuickHttp::debugOut(const string &fmt, ...) {
#ifdef __DEBUG__
va_list ap;
va_start(ap, fmt);
vprintf(fmt.c_str(), ap);
va_end(ap);
#endif
}
QuickHttp.h 头文件
//
// Created by Administrator on 2022/7/31.
//
#ifndef TRANSLATE_QUICKHTTP_H
#define TRANSLATE_QUICKHTTP_H
#include <winsock2.h>
#include "string"
#include "QuickBody.h"
#include <wspiapi.h>
#include <iostream>
#include <io.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#define BUFSIZE 4096
#define URLSIZE 2048
class QuickHttp {
public:
//该只限制于win
void initWinSocket();
static QuickHttp *getInstance();
int httpGet(const string &strUrl, const string &strMethod, const string &strData);
string getBuf();
QuickBody *getQuickBody();
private:
string getIpFromUrl(const string &strUrl);
int getPortFromUrl(const string &strUrl);
string getHostAddFromUrl(const string &strUrl);
void debugOut(const string &fmt, ...);
string getParamFromUrl(const string &strUrl);
string httpHeadCreate(const string &strMethod, const string &strUrl, const string &strData);
string httpDataTransmit(int isSocFd);
};
#endif //TRANSLATE_QUICKHTTP_H
Body解析
QuickBody.cpp
//
// Created by Administrator on 2022/8/3.
//
#include <iostream>
#include "QuickBody.h"
string QuickBody::getCode() { return this->code; }
string QuickBody::getBody() { return this->body; }
map<string, string> QuickBody::getHeaders() {
return this->headers;
}
QuickBody *QuickBody::getInstance() {
return new QuickBody();
}
/**
* http协议头文件开始解析
* http协议内容分为三段:
* 1.解析协议版本和状态码
* 2。返回头内容
* 3。内容
* @param name 头文件
*/
void QuickBody::Analysis(const string &name) {
vector<string> body = split(name, "\r\n\r\n");
for (int i = 0; i < body.size(); i++) {
if (i == 0) {
initHeader(body[i]);
} else {
//内容
this->body += body[i];
}
}
}
/**
* 分割字符串
* @param str 需要分割内容
* @param pattern 分割特征码
* @return vector<string>集合
*/
vector<string> QuickBody::split(const string &str1, const string &pattern) {
string::size_type pos;
vector<string> result;
string str = str1 + pattern;//扩展字符串以方便操作
int size = str.size();
for (int i = 0; i < size; i++) {
pos = str.find(pattern, i);
if (pos < size) {
string s = str.substr(i, pos - i);
result.push_back(s);
i = pos + pattern.size() - 1;
}
}
return result;
}
/**
* 返回头解析
* @param body
*/
void QuickBody::initHeader(string body) {
vector<string> header = split(body, "\r\n");
for (int j = 0; j < header.size(); ++j) {
if (j == 0) {
//状态码
this->code = header[j];
} else {
//header获取key和value
headersSplit(header[j], ": ");
}
}
}
void QuickBody::headersSplit(const string &str, const string &pattern) {
string str1 = str + pattern;
string::size_type pos;
vector<string> result;
int size = str1.size();
for (int i = 0; i < size; i++) {
pos = str1.find(pattern, i);
if (pos < size) {
string s = str1.substr(i, pos - i);
result.push_back(s);
i = pos + pattern.size() - 1;
}
}
this->headers.insert(map<string, string>::value_type(result[0], result[1]));
}
QuickBody.h
//
// Created by Administrator on 2022/8/3.
//
#ifndef TRANSLATE_QUICHBODY_H
#define TRANSLATE_QUICHBODY_H
#include "string"
#include <vector>
#include <utility>
#include <map>
using namespace std;
class QuickBody {
public:
static QuickBody *getInstance();
void Analysis(const string &name);
vector<string> split(const string &str, const string &pattern);
string getCode();
string getBody();
map<string, string> getHeaders();
private:
map<string, string> headers;
string code;
string body;
void initHeader(string body);
void headersSplit(const string &str, const string &pattern);
};
#endif //TRANSLATE_QUICHBODY_H
main.cpp
//
// main.cpp
// HttpClient
//
// Created by LiYong on 2018/1/23.
//
#include <iostream>
#include <vector>
#include "include/QuickHttp.h"
using namespace std;
int main(int argc, const char *argv[]) {
QuickHttp *http = QuickHttp::getInstance();
http->initWinSocket();
http->httpGet("https://www.baidu.com", "GET", "");
QuickBody *body = http->getQuickBody();
cout << body->getBody();
/*map<string, string> result = body->getHeaders();
for (auto it = result.begin(); it != result.end(); it++) {
cout << it->first << " " << it->second << endl;
}*/
return 0;
}
如果有大佬发现有问题签请多多指教