Files
pubg/T3/http.h
T
2026-05-02 14:30:03 +08:00

408 lines
11 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <time.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#ifdef __cplusplus
extern "C"{
#endif
char* strstrstr(char* str, char* text, char* rear);//变态级的函数,看了可能会崩溃
char* httppost(char* hostname, char* url, char* cs);//POST方法
char* httpget(const char* hostname, char* url);//GET方法
char* getip(char* hostname);//域名转换IP
int hextoint(char* hex);//16进制字符串转整数
#ifdef __cplusplus
}
#endif
char* httppost(char* hostname, char* url, char* cs){
// sock句柄
int sockfd;
struct sockaddr_in serveraddr;
//两个是同一个类型,可混用,但是会警告
//int addrlen = sizeof(serveraddr);
socklen_t addrlen = sizeof(serveraddr);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
//printf("创建网络连接失败---socket error!\n");
return NULL;
}
//C4droid的GCC没有这个函数,编译会报错
//bzero(&serveraddr, addrlen);
//可以使用这个函数
memset(&serveraddr,0,addrlen);
serveraddr.sin_family = AF_INET;
//端口80
serveraddr.sin_port = htons(80);
struct hostent* host;
host = gethostbyname(hostname);
if (host == NULL){
printf("无法解析域名\n");
close(sockfd);
return NULL;
}
struct in_addr ip = *((struct in_addr *)host->h_addr);
//printf("ip:%s\n",inet_ntoa(ip));
serveraddr.sin_addr = ip;
if (connect(sockfd, (struct sockaddr*) & serveraddr, addrlen) < 0){
//printf("连接到服务器失败,connect error!\n");
close(sockfd);
return NULL;
}
//因为懒,所以char[2048]
//可以通过strlen获取参数长度来动态申请内存
char postxyt[2048];
char postsjlen[5];
// 发送数据
//32位要用 "%u" 经测试发现还是long最稳定
//顺利通过 GCCarm-linux-gccarm-linux-gnueabi-gcc,安卓jni 编译 无警告
#if __SIZEOF_LONG__ == 8
sprintf(postsjlen, "%lu", strlen(cs));
#else
sprintf(postsjlen, "%u", strlen(cs));
#endif
memset(postxyt, 0, 2048);
// 追加字符串(请求协议头)
//个人感觉strcat函数比较低效
//用char指针和strcpy函数会比较快
sprintf(postxyt,"POST /%s HTTP/1.1\r\nHost: %s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %ld\r\n\r\n%s\r\n\r\n",url,hostname,strlen(cs),cs);
//别问,问就是 “一切皆文件”
/*
if (write(sockfd, postxyt, strlen(postxyt)) == -1){
//printf("发送失败!错误代码:%d,错误信息:%s\n", errno, strerror(errno));
close(sockfd);
return NULL;
}*/
if (send(sockfd, postxyt, strlen(postxyt),0) == -1){
printf("%d%s\n", errno, strerror(errno));
close(sockfd);
return NULL;
}
fd_set fds;
struct timeval tv = { 3,0 }; //select等待3秒,3秒轮询,要非阻塞就置0
//非阻塞需要循环
FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
FD_SET(sockfd, &fds); //添加描述符
if (select(sockfd + 1, &fds, NULL, NULL, &tv) < 1){
//非阻塞时使用continue;
//-1错误
//0无写入数据
close(sockfd);
return NULL;
}
if (FD_ISSET(sockfd, &fds)) { //测试sock是否可读,即是否网络上有数据
char xyt[1024];
char* xytzz = xyt;
char* xytmaxlen = xyt + 1023;
int readlen;
while (readlen = read(sockfd, xytzz, 1)){
if(*xytzz == '\n'){
//printf("匹配到一个\\n\n");
if(strncmp(xytzz - 3,"\r\n\r",3) == 0){
*++xytzz = '\0';
//printf("嗨呀,完全匹配,好开心\n");
break;
}
}
xytzz++;
if(xytmaxlen == xytzz){
//printf("什么吊毛协议头这么长\n");
close(sockfd);
return NULL;
}
}
if(!readlen){
//printf("服务器断开了连接,并未发送任何数据。\n");
close(sockfd);
return NULL;
}
//printf("%s\n--\n",xyt);
char* xylen = strstrstr(xyt,"Content-Length: ","\n");
char* xyzw;
if(xylen == NULL){
//如果读取正文长度失败则进入分段读取模式
char hexlen[8];
char* hex = hexlen;
do{
read(sockfd, hex, 1);
}while(*hex++ != '\n');
*hex = '\0';
int rdlen = hextoint(hexlen);
if(rdlen == 0){
close(sockfd);
return NULL;
}
//rdlen++;
xyzw = (char*)malloc(rdlen + 2);//把\r\n读出来
read(sockfd, xyzw, rdlen + 2);//方便下面读取区块信息
//xyzw[rdlen] = '\0';
//读取下一块内容
while(1){
hex = hexlen;
do{
read(sockfd, hex, 1);
}while(*hex++ != '\n');
*hex = '\0';
int chlen = hextoint(hexlen);
//判断当前区块是否为0
if(chlen == 0)break;
rdlen += chlen;
xyzw = (char*)realloc(xyzw,rdlen + 2);
char* xrzz = xyzw + rdlen - chlen;
read(sockfd, xrzz, chlen + 2);
//xyzw[rdlen] = '\0';
}
xyzw[rdlen] = '\0';
}else{
//得到正文长度,一次性读取 申请内存
int xyzwlen = atoi(xylen);
free(xylen);
//printf("正文共%d字节\n",xyzwlen);
xyzw = (char*)malloc(xyzwlen + 1);
readlen = read(sockfd, xyzw, xyzwlen);//接受网络数据
xyzw[readlen] = '\0';
//printf("读取了%d字节\n",readlen);
}
close(sockfd);
return xyzw;
}
close(sockfd);
return NULL;
}
char* httpget(const char* hostname, char* url){
// sock句柄
int sockfd;
struct sockaddr_in serveraddr;
//两个是同一个类型,可混用,但是会警告
//int addrlen = sizeof(serveraddr);
socklen_t addrlen = sizeof(serveraddr);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
//printf("创建网络连接失败---socket error!\n");
return NULL;
}
//C4droid的GCC没有这个函数,编译会报错
//bzero(&serveraddr, addrlen);
//可以使用这个函数
memset(&serveraddr,0,addrlen);
serveraddr.sin_family = AF_INET;
//端口80
serveraddr.sin_port = htons(80);
struct hostent* host;
host = gethostbyname(hostname);
if (host == NULL){
//printf("无法解析域名\n");
close(sockfd);
return NULL;
}
struct in_addr ip = *((struct in_addr *)host->h_addr);
//printf("ip:%s\n",inet_ntoa(ip));
serveraddr.sin_addr = ip;
if (connect(sockfd, (struct sockaddr*) & serveraddr, addrlen) < 0){
//printf("连接到服务器失败,connect error!\n");
close(sockfd);
return NULL;
}
//因为懒,所以char[2048]
//可以通过strlen获取参数长度来动态申请内存
char postxyt[2048];
memset(postxyt, 0, 2048);
// 追加字符串(请求协议头)
//个人感觉strcat函数比较低效
//用char指针和strcpy函数会比较快
sprintf(postxyt,"GET /%s HTTP/1.1\r\nHost: %s\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n",url,hostname);
//别问,问就是 “一切皆文件”
/*
if (write(sockfd, postxyt, strlen(postxyt)) == -1){
//printf("发送失败!错误代码:%d,错误信息:%s\n", errno, strerror(errno));
close(sockfd);
return NULL;
}*/
if (send(sockfd, postxyt, strlen(postxyt),0) == -1){
printf("%d%s\n", errno, strerror(errno));
close(sockfd);
return NULL;
}
fd_set fds;
struct timeval tv = { 3,0 }; //select等待3秒,3秒轮询,要非阻塞就置0
//非阻塞需要循环
FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
FD_SET(sockfd, &fds); //添加描述符
if (select(sockfd + 1, &fds, NULL, NULL, &tv) < 1){
//非阻塞时使用continue;
//-1错误
//0无写入数据
close(sockfd);
return NULL;
}
if (FD_ISSET(sockfd, &fds)) { //测试sock是否可读,即是否网络上有数据
char xyt[1024];
char* xytzz = xyt;
char* xytmaxlen = xyt + 1023;
int readlen;
while (readlen = read(sockfd, xytzz, 1)){
if(*xytzz == '\n'){
//printf("匹配到一个\\n\n");
if(strncmp(xytzz - 3,"\r\n\r",3) == 0){
*++xytzz = '\0';
//printf("嗨呀,完全匹配,好开心\n");
break;
}
}
xytzz++;
if(xytmaxlen == xytzz){
//printf("什么吊毛协议头这么长\n%s\n",xyt);
close(sockfd);
return NULL;
}
}
if(!readlen){
//printf("服务器断开了连接,并未发送任何数据。\n");
close(sockfd);
return NULL;
}
//printf("%s\n--\n",xyt);
char* xylen = strstrstr(xyt,"Content-Length: ","\n");
char* xyzw;
if(xylen == NULL){
//如果读取正文长度失败则进入分段读取模式
char hexlen[8];
char* hex = hexlen;
do{
read(sockfd, hex, 1);
}while(*hex++ != '\n');
*hex = '\0';
int rdlen = hextoint(hexlen);
if(rdlen == 0){
close(sockfd);
return NULL;
}
//rdlen++;
xyzw = (char*)malloc(rdlen + 2);//把\r\n读出来
read(sockfd, xyzw, rdlen + 2);//方便下面读取区块信息
//xyzw[rdlen] = '\0';
//读取下一块内容
while(1){
hex = hexlen;
do{
read(sockfd, hex, 1);
}while(*hex++ != '\n');
*hex = '\0';
int chlen = hextoint(hexlen);
//判断当前区块是否为0
if(chlen == 0)break;
rdlen += chlen;
xyzw = (char*)realloc(xyzw,rdlen + 2);
char* xrzz = xyzw + rdlen - chlen;
read(sockfd, xrzz, chlen + 2);
//xyzw[rdlen] = '\0';
}
xyzw[rdlen] = '\0';
}else{
//得到正文长度,一次性读取 申请内存
int xyzwlen = atoi(xylen);
free(xylen);
//printf("正文共%d字节\n",xyzwlen);
xyzw = (char*)malloc(xyzwlen + 1);
readlen = read(sockfd, xyzw, xyzwlen);//接受网络数据
xyzw[readlen] = '\0';
//printf("读取了%d字节\n",readlen);
}
close(sockfd);
return xyzw;
}
close(sockfd);
return NULL;
}
char* strstrstr(char* str, char* front, char* rear){
if(!str || !front || !rear)return NULL;//如果你不传NULL,我至于吗
char* s;
char* t;
while(*str) {
s = str;
t = front;
while (*s == *t) {
s++;
t++;
if (!*t) {
str = s;
char* old = str;
do{
s = str;
t = rear;
while (*s == *t) {
s++;
t++;
if (!*t) {
int charlen = str - old;
char* newstr = (char*)malloc(charlen + 1);
strncpy(newstr, old, charlen);
//使用Visual studio编程时会警告strncpy函数存在风险,使用strncpy_s替换之
//strncpy_s(newstr, charlen + 1,old, charlen);
newstr[charlen] = '\0';
return newstr;
}
}
str++;
}while(*str);
return NULL;
}
}
str++;
}
return NULL;
}
char* getip(char* hostname) {
//不多bb,面向百度编程
struct hostent* host;
host = gethostbyname(hostname);
if (host == NULL){
perror("cannot get host by hostname");
return NULL;
}
return inet_ntoa(*((struct in_addr *)host->h_addr));
}
int hextoint(char * hex){
int value = 0;
while (*hex){
if (*hex >= 'A' && *hex <= 'F')
value = (*hex - 55) + 16 * value;
else if (*hex >= 'a' && *hex <= 'f')
value = (*hex - 87) + 16 * value;
else if (*hex >= '0' && *hex <= '9')
value = (*hex - 48) + 16 * value;
else{
return value;
}
hex++;
}
return value;
}