408 lines
11 KiB
C++
Executable File
408 lines
11 KiB
C++
Executable File
#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最稳定
|
||
//顺利通过 GCC,arm-linux-gcc,arm-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;
|
||
}
|
||
|