请先阅读 自动回帖器的原理与实现(一)原理篇
一共有9个源文件,分别是:autoProcess.cpp
autoReply.cpp/h
baseTcp.cpp/h
encoding.cpp/h
mycompress.cpp/h
使用时,只需要修改autoProcess.cpp中的
homePageLink:主页名字,如www.url.cn
message:回复帖子的内容,如:你好,这是回帖内容
forumLink:帖子的路径,如帖子地址为www.url.cn/thread-55254-1-1.html,那么这里只需要填写/thread-55254-1-1.html
cookiename:所需cookie值字段名
cookievalue:所需cookie值字段值
文件:autoProcess.cpp
#include "pthread.h"
#include "autoReply.h"
#define THREAD 30
#define COOKIECOUNT 2
#define BEGINPORT 40000
#define DESTPORT 80
#define REPLYTIME 2
#define WAITTIME 10
const unsigned char homePageLink[] = {"www.url.cn"};
const unsigned char message[] = {"相思鸟好可爱!!!!帮顶一下!"};
const unsigned char forumLink[] = {"/thread-55254-1-1.html"};
const unsigned char cookiename[2][20] =
{{"3j9D_2132_saltkey"},
{"3j9D_2132_auth"}
};
const unsigned char cookievalue[THREAD][2][120] =
{
//30
//cookie值3j9D_2132_saltkey
{{"6lne0885"},
//cookie值3j9D_2132_auth
{"8d2eYvagXII1aNmBqFZdu4lXovcA%2ByvanI83ZnXlqvq7VgvurrcfIVwpuPp6jnteTHsFkZrqjE3zVNGwc0kFd71xXw"}},
};
typedef struct dd
{
int thread;
}threadParameter;
static pthread_t *tid = NULL;
static threadParameter *para = NULL;
unsigned char ip[16];
void * autoReplyThread(void *v);
int main()
{
tid = new pthread_t[THREAD];
para = new threadParameter[THREAD];
int i;
BaseTcp::getHostIPAddr(homePageLink, ip);
for(i = 0; i < THREAD; i++)
{
para[i].thread = i;
pthread_create(&tid[i], NULL, autoReplyThread, (void *)¶[i]);
}
for(i = 0; i < THREAD; i++)
{
pthread_join(tid[i], NULL);
}
}
void * autoReplyThread(void *v)
{
int mythread = ((threadParameter*)v)->thread;
autoReply myauto;
ofstream auto_out_put;
char file[100];
snprintf(file, sizeof(file), "./log%d.log", mythread);
//cout<<file<<endl;
auto_out_put.open(file, ostream::out|ostream::trunc);
myauto.setOutput(&auto_out_put);
myauto.setCookieCount(COOKIECOUNT);
myauto.setMyport(BEGINPORT + mythread);
//myauto.setAccount(account, password);
myauto.setHostIP(ip, DESTPORT);
string smessage = (char *)message;
myEncode::API_IC_UTFToGBK(smessage);
myauto.setMessage((unsigned char *)smessage.c_str());
myauto.setForumPage(forumLink);
myauto.setHomePage(homePageLink);
int i;
for(i = 0; i < COOKIECOUNT; i++)
{
myauto.setCookieName(i, cookiename[i]);
myauto.setCookieValue(i, cookievalue[mythread][i]);
}
myauto.setReplyTime(REPLYTIME);
myauto.setWaitTime(WAITTIME);
if(myauto.process())
{
auto_out_put<<"yeah~!回帖成功!"<<endl;
}
//auto_out_put<<"yeah~!回帖成功!"<<endl;
auto_out_put.close();
}
文件:autoReply.cpp
#include "autoReply.h"
int autoReply::process()
{
*output<<"------------线程已经创建---------------"<<endl;
time_t timep;
time(&timep);
*output<<"创建时间:"<<ctime(&timep)<<endl;
//如果连接失败则一直连接
while(connectToDest() == -1);
if(sendForumPageRequest() != -1)
{
if(getForumPage())
{
int i;
for(i = 0; i < replyTime; i++)
{
/*sendReplyPageRequest();
getLastPage();
Close();
sleep(waitTime);
while(connectToDest() == -1);*/
if(sendReplyPageRequest() != -1)
{
if(getLastPage())
{
time(&timep);
*output<<"第"<<i<<"次回复时间:"<<ctime(&timep)<<endl;
Close();
sleep(waitTime);
while(connectToDest() == -1);
}
else
{
*output<<"第"<<i<<"次接收LastPage失败"<<endl;
//return 0;
}
}
else
{
*output<<"第"<<i<<"次接收发送ReplyPage失败"<<endl;
//return 0;
}
}
return 1;
}
else
*output<<"接收ForumPage失败"<<endl;
}
else
*output<<"发送ForumPage失败"<<endl;
return 0;
}
autoReply::autoReply()
{
output = &cout;
}
/*连接到服务器,失败返回-1,成功返回0*/
int autoReply::connectToDest()
{
if(blockTcpInit("0.0.0.0", myport) != -1)
{
return TcpConnect((char *)myWebInfo.IP, myWebInfo.port);
}
return -1;
}
void autoReply::setCookieCount(const int cookietime)
{
myWebInfo.cookie = cookietime;
}
void autoReply::setMyport(const int pmyport)
{
myport = pmyport;
}
void autoReply::setOutput(ostream *out)
{
output = out;
}
void autoReply::setAccount(const unsigned char *paccount, const unsigned char *ppassword)
{
memcpy(myAccount.account, paccount, strlen((char*)paccount) + 1);
memcpy(myAccount.password, ppassword, strlen((char*)ppassword) + 1);
}
void autoReply::setHostIP(const unsigned char *ip, const int pport)
{
memcpy(myWebInfo.IP, ip, strlen((char*)ip) + 1);
myWebInfo.port = pport;
}
void autoReply::setMessage(const unsigned char *message)
{
memcpy(myWebInfo.message, message, strlen((char*)message) + 1);
}
void autoReply::setForumPage(const unsigned char *forumpage)
{
memcpy(myWebInfo.forumPage, forumpage, strlen((char*)forumpage) + 1);
}
void autoReply::setHomePage(const unsigned char *homepage)
{
memcpy(myWebInfo.homePage, homepage, strlen((char*)homepage) + 1);
}
void autoReply::setReplyPage(const unsigned char *replypage)
{
memcpy(myWebInfo.replyPage, replypage, strlen((char*)replypage) + 1);
}
int autoReply::setCookieName(const int index, const unsigned char * name)
{
if(index >= COOKIE)
{
return 0;
}
memcpy(myWebInfo.myCookie[index].name, name, strlen((char*)name) + 1);
return 1;
}
int autoReply::setCookieValue(const int index, const unsigned char * value)
{
if(index >= COOKIE)
{
return 0;
}
memcpy(myWebInfo.myCookie[index].key, value, strlen((char*)value) + 1);
return 1;
}
void autoReply::setformhash(const unsigned char *formhash)
{
memcpy(myWebInfo.formhash, formhash, strlen((char*)formhash) + 1);
}
//设置回复次数
void autoReply::setReplyTime(const int time)
{
replyTime = time;
}
//设置等待时间
void autoReply::setWaitTime(const int time)
{
waitTime = time;
}
//设置cookie返回格式到cookie中
int autoReply::setCookie(unsigned char *cookie, int length)
{
int i = 0, rc, j = 0;
unsigned char *strpos = cookie;
for(i = 0; i < myWebInfo.cookie - 1; i++)
{
rc = snprintf((char*)strpos + j, length - j, "%s=%s; ", myWebInfo.myCookie[i].name, myWebInfo.myCookie[i].key);
j += rc;
}
//最后一个单独处理
rc = snprintf((char*)strpos + j, length - j, "%s=%s\r\n", myWebInfo.myCookie[i].name, myWebInfo.myCookie[i].key);
j += rc;
return j;
}
//函数作用:构造forum页的请求
//返回请求报文长度
int autoReply::createForumPageRequest(unsigned char *head, int length)
{
unsigned char *strpos = head;
int i = 0, rc;
/*get头*/
rc = snprintf((char*)strpos + i, length - i, "GET %s HTTP/1.1\r\n", myWebInfo.forumPage);
i += rc;
/*host头*/
rc = snprintf((char*)strpos + i, length - i, "Host: %s\r\n", myWebInfo.homePage);
i += rc;
/*connect*/
rc = snprintf((char*)strpos + i, length - i, "Connection: keep-alive\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n");
i += rc;
/*unsigned charset*/
/* rc = snprintf((char*)strpos + i, length - i, "Referer: http://www..cn\r\n");
i += rc;*/
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Accept-Encoding: gzip,deflate,sdch\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Accept-Language: en-US,en;q=0.8\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n");
i += rc;
/*unsigned charset*/
unsigned char cookietemp[1024];
setCookie(cookietemp, 1024);
rc = snprintf((char*)strpos + i, length - i, "Cookie: %s", cookietemp);
i += rc;
/testtest/
//cout<<"cookie"<<cookietemp<<endl;
/*空行*/
rc = snprintf((char*)strpos + i, length - i, "\r\n");
i += rc;
// cout<<"myhead"<<head<<endl;
return i;
}
//函数作用:构造homepage请求头
//返回请求报文长度
int autoReply::createReplyRequest(unsigned char *head, int length)
{
unsigned char *strpos = head;
int i = 0, rc;
/*get头*/
rc = snprintf((char*)strpos + i, length - i, "POST /%s\r\n", myWebInfo.replyPage);
i += rc;
/*host头*/
rc = snprintf((char*)strpos + i, length - i, "Host: %s\r\n", myWebInfo.homePage);
i += rc;
/*connect*/
rc = snprintf((char*)strpos + i, length - i, "Connection: keep-alive\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Content-Length: %i\r\n", getMessageLength());
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Content-Type: application/x-www-form-urlencoded\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Origin: %s\r\n", myWebInfo.homePage);
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Accept-Encoding: gzip,deflate,sdch\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Content-Type: application/x-www-form-urlencoded\r\n");
i += rc;
/*unsigned charset*/
rc = snprintf((char*)strpos + i, length - i, "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n");
i += rc;
/*unsigned charset*/
unsigned char cookietemp[1024];
setCookie(cookietemp, 1024);
rc = snprintf((char*)strpos + i, length - i, "Cookie: %s", cookietemp);
i += rc;
/*空行*/
rc = snprintf((char*)strpos + i, length - i, "\r\n");
i += rc;
char tempchar[1024];
snprintf(tempchar, 1024, "message=%s&formhash=%s&subject=", myWebInfo.message, myWebInfo.formhash);
//对message进行urlencode编码
rc = snprintf((char*)strpos + i, length - i, "%s", (myEncode::UrlDecode(tempchar)).c_str());
i += rc;
return i;
}
int autoReply::sendForumPageRequest()
{
unsigned char header[HEADER];
//创建http请求头部,并发送
int len = createForumPageRequest(header, HEADER);
return writen(header, len);
}
int autoReply::sendReplyPageRequest()
{
unsigned char header[HEADER];
//创建http请求头部,并发送
int len = createReplyRequest(header, HEADER);
return writen(header, len);
}
//函数作用:返回报文的状态码
//返回0是错误,否则返回正常码
int autoReply::parseState(const unsigned char *header, int length)
{
const unsigned char* p;
p = (unsigned char*)memmem((char *)header, length, "HTTP/1.1 ", 9);
if(p)
{
return strtol((char*)(p + 9), NULL, 10);
}
return 0;
}
void autoReply::readNoUseData(int length)
{
char *temppage = new char[length];
readn(temppage, length);
delete temppage;
}
//函数作用:得到报文的头部信息,存入header中,header数组长度为length
//返回头部大小
int autoReply::getHeader(unsigned char *header, int length)
{
unsigned char *p = header;//p记录当前缓冲区读到的位置
unsigned char *pos = p;//pos记录解析到的位置
int len = 3;
readn(p, 3);
p += 3;
while((readn(p, 1) != -1) && (len < length))
{
p += 1;
len += 1;
//cout<<"pos="<<(char)pos[pos-header]<<endl;
//第一次进来缓冲区应该有4个字符,
if((*pos == '\r')&&(*(pos + 1) == '\n')&&(*(pos + 2) == '\r')&&(*(pos + 3) == '\n'))
{
break;
}
pos += 1;
}
//cout<<<<endl;
//cout<<"hearder:"<<header<<endl;
return len;
}
int autoReply::getLength()
{
unsigned char header[20];
unsigned char *p = header;//p记录当前缓冲区读到的位置
unsigned char *pos = p;//pos记录解析到的位置
int len = 1;
readn(p, 1);
p += 1;
while((readn(p, 1) != -1) && (len < 20))
{
p += 1;
len += 1;
//第一次进来缓冲区应该有4个字符,
if((*pos == '\r')&&(*(pos + 1) == '\n'))
{
break;
}
pos += 1;
}
return strtol((char*)header, NULL, 16);
}
int autoReply::getNextLength()
{
//先读掉上次的/r/n
unsigned char p[2];
readn(p, 2);
//读大小
return getLength();
}
//1包含要找的,0不包含
//在长度为length的page中找到key,如果flag=1,将key到delimit之间的数据放入长度为aluelen的dest中,否则将key的下一个数据到delimite之间的数据放入dest中
int autoReply::getLittleString(const unsigned char *page, int length, const unsigned char *key, unsigned char *dest, int valuelen, unsigned char *delimit, int flag)
{
const unsigned char* p;
//cout<<"i want to find key:"<<key<<endl;
//cout<<"key length:"<<strlen((char*)key)<<endl;
//cout<<"body:"<<page<<endl;
//cout<<"length="<<length<<endl;
//找到page中的key子串
p = (unsigned char*)memmem((char *)page, length, key, strlen((char*)key));
if(p)
{
// cout<<"findkey="<<key<<endl;
unsigned char * result;
//如果要将key也返回
if(flag)
{
result = (unsigned char *)strtok((char *)p, (char *)delimit);
}
else//如果不返回key
{
result = (unsigned char *)strtok((char*)((char *)p + strlen((char*)key)), (char *)delimit);
}
if(result)
{
int resultlen = strlen((char*)(char *)result) + 1;
// cout<<"resultlen="<<resultlen;
if(resultlen <= valuelen)
{
memcpy(dest, result, resultlen);
return resultlen - 1;
}
}
}
return 0;
}
//在长度为length的page中找到formhash存入dest中
int autoReply::getFormhash(const unsigned char *page, int length)
{
int rc = 0,len = 0;
rc = getLittleString(page, length, (unsigned char *)"formhash=", myWebInfo.formhash, 100, (unsigned char *)"\"", 0);
len += rc;
return len;
}
//在长度为length的page中找到reply放入长度为aluelen的dest中
int autoReply::getReplyPage(const unsigned char *page, int length)
{
unsigned char *destpage = myWebInfo.replyPage;
int valuelen = 1024;
int rc = 0,len = 0;
rc = getLittleString(page, length, (unsigned char *)"forum.php?mod=post&action=reply", destpage + len, valuelen - len, (unsigned char *)"\'", 1);
len += rc;
memcpy(destpage + len, "&", 1);
len += 1;
rc = getLittleString(page, length, (unsigned char *)"extra=", destpage + len, valuelen - len, (unsigned char *)"&", 1);
len += rc;
char temp[] = {"&replysubmit=yes&infloat=yes&handlekey=fastpost&inajax=1 HTTP/1.1"};
memcpy(destpage + len, temp, sizeof(temp));
len += sizeof(temp);
return len;
}
//得到回帖的最后部分的消息长度
int autoReply::getMessageLength()
{
int messagelen = strlen((char*)"message=") + strlen((char*)myWebInfo.message) + strlen((char*)"&formhash=") + strlen((char*)myWebInfo.formhash) + strlen((char*)"&subject=");
return messagelen;
}
/*得到forum的回复页,设置formhash和回帖地址*/
int autoReply::getForumPage()
{
//cout<<"----------------ForumPage---------------------"<<endl;
unsigned char header[HEADER];
unsigned char *compressdata;
unsigned char *uncompressdata;
//cout<<"header大小为:"<<getHeader(header, HEADER)<<endl;
getHeader(header, HEADER);
int state = parseState(header, HEADER);
if(state == 200)
{
// cout<<"状态码:200"<<endl;
int pageLen = 0;
//得到页面大小
pageLen = getLength();
//cout<<"aa"<<endl;
if(pageLen > 0)
{
// cout<<"网页大小为"<<pageLen<<endl;
compressdata = new unsigned char[pageLen];
//解压后的网页会更大!这里要注意
uncompressdata = new unsigned char[pageLen*2];
readn(compressdata, pageLen);
//gzip_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
int destlen = pageLen*2;
//对gzip网页解压
if(myCompress::gzip_uncompress(uncompressdata, (uLongf *)&destlen, compressdata, pageLen) == Z_OK)
{
// cout<<"---------uncompressdata--------------"<<endl;
// cout<<"uncompress data len:"<<destlen<<endl;
// cout<<uncompressdata<<endl;
//得到forum.php?mod=post&action=reply,tid,fid,extra等等
//unsigned char replypage[1024];
//unsigned char formhash[100];
//得到回复页网址,设置myWebInfo的replypage
getReplyPage(uncompressdata, pageLen*2);
// cout<<"回复的地址是:"<<myWebInfo.replyPage<<endl;
//得到回复页的formhash,设置对应值
getFormhash(uncompressdata, pageLen*2);
// cout<<"formhash="<<myWebInfo.formhash<<endl;
}
delete compressdata;
delete uncompressdata;
pageLen = getNextLength();
while(pageLen > 0)
{
// cout<<"下一个网页大小为"<<pageLen<<endl;
readNoUseData(pageLen);
pageLen = getNextLength();
}
return 1;
}
}
else
{
*output<<"状态码:"<<state<<endl;
}
return 0;
}
int autoReply::getLastPage()
{
//cout<<"----------------ReplyPage---------------------"<<endl;
unsigned char Lastheader[HEADER];
memset(Lastheader,0,HEADER);
//sleep(1);
//cout<<"header大小为:"<<getHeader(Lastheader, HEADER)<<endl;
//cout<<"header:"<<Lastheader<<endl;
getHeader(Lastheader, HEADER);
int state = parseState(Lastheader, HEADER);
if(state == 200)
{
// cout<<"状态码:200"<<endl;
//{
int pageLen = 0;
pageLen = getLength();
if(pageLen > 0)
{
// cout<<"网页大小为"<<pageLen<<endl;
readNoUseData(pageLen);
pageLen = getNextLength();
while(pageLen > 0)
{
// cout<<"下一个网页大小为"<<pageLen<<endl;
readNoUseData(pageLen);
pageLen = getNextLength();
}
return 1;
}
//}
}
else
{
*output<<"状态码:"<<state<<endl;
}
return 0;
}
文件:AutoReply.h
#define HEADER 2048
#define COOKIE 2
#include "string.h"
#include <time.h>
#include "mycompress.h"
#include "encoding.h"
#include "baseTcp.h"
typedef struct aa
{
//cookie变量的名字
unsigned char name[30];
//cookie变量的值
unsigned char key[120];
//eb5acdQuuNifiSi0hwAmGPySlTR2iAIAmf98BiLAhsv1pZIcbmy9GwTOBHjSmpZ%2FbLQQlr1jUV7urpdafYY33HEvBw
}cookieParameter;
typedef struct bb
{
unsigned char account[20];
unsigned char password[20];
}myInfo;
typedef struct cc
{
unsigned char IP[16];
int port;
//要发送的消息
unsigned char message[50];
unsigned char homePage[100];
//帖子所在页面
unsigned char forumPage[100];
//通过帖子所在页面得到的回帖页面
unsigned char replyPage[1024];
//cookie
cookieParameter myCookie[COOKIE];
//最多cookie为COOKIE,但是使用数目是cookie
int cookie;
unsigned char formhash[100];
}webInfo;
class autoReply : BaseTcp
{
private:
myInfo myAccount;
webInfo myWebInfo;
ostream *output;
//回复次数
int replyTime;
//等待时间
int waitTime;
int myport;
public:
autoReply();
int connectToDest();
void setCookieCount(int cookietime);
void setMyport(const int pmyport);
void setOutput(ostream *out);
void setAccount(const unsigned char *paccount, const unsigned char *ppassword);
void setHostIP(const unsigned char *ip, const int pport);
void setMessage(const unsigned char *message);
void setForumPage(const unsigned char *forumpage);
void setHomePage(const unsigned char *homepage);
//--------------------------------------
void setReplyPage(const unsigned char *replypage);
int setCookieName(const int index, const unsigned char * name);
int setCookieValue(const int index, const unsigned char * value);
//-----------------------
void setformhash(const unsigned char *formhash);
void setReplyTime(const int time);
void setWaitTime(const int time);
//--------------------------构造cookie的格式
int setCookie(unsigned char *cookie, int length);
int createForumPageRequest(unsigned char *head, int length);
int createReplyRequest(unsigned char *head, int length);
int sendForumPageRequest();
int sendReplyPageRequest();
int parseState(const unsigned char *header, int length);
void readNoUseData(int length);
int getHeader(unsigned char *header, int length);
int getLength();
int getNextLength();
int getLittleString(const unsigned char *page, int length, const unsigned char *key, unsigned char *dest, int valuelen, unsigned char *delimit, int flag);
int getFormhash(const unsigned char *page, int length);
int getReplyPage(const unsigned char *page, int length);
int getMessageLength();
int getForumPage();
int getLastPage();
int process();
};
文件:baseTcp.cpp
/* 作者:zxx
* 日期:2012.05.29
* 描述:基本套接字类
* */
#include "baseTcp.h"
/*函数作用:设置套接字fd的状态,nonblocking为1,设置为非阻塞模式,nonblocking为0,设置为阻塞模式
成功返回0,失败返回-1*/
int BaseTcp::set_nonblocking(int fd, int nonblocking)
{
int rc;
rc = fcntl(fd, F_GETFL, 0);
if(rc < 0)
return -1;
rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
if(rc < 0)
return -1;
return 0;
}
/*构造函数:初始设置为阻塞模式*/
BaseTcp::BaseTcp()
{
sockfd = -1;
way = 0;
}
BaseTcp::~BaseTcp()
{
//如果套接字曾经打开过,则关闭
if(sockfd != -1)
{
close(sockfd);
}
}
/*函数作用:得到host对应的ip,DNS解析成功返回1,否则返回0*/
int BaseTcp::getHostIPAddr(const unsigned char *host, unsigned char *ip)
{
if(ip == NULL)
{
return 0;
}
else
{
struct addrinfo hints, *info, *infop;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo((char *)host, NULL, &hints, &info) != -1)
{
infop = info;
//只解析第一个
if(infop && infop->ai_addr != NULL)
{
struct sockaddr_in *s = (struct sockaddr_in*)infop->ai_addr;
inet_ntop(AF_INET, &s->sin_addr, (char *)ip, 16);
freeaddrinfo(info);
return 1;
}
}
//memcpy(ip, "219.151.15.20", 14);
return 0;
}
}
int BaseTcp::getErrno()
{
return errno;
}
/*函数作用:关闭套接字*/
void BaseTcp::forseClose()
{
if(sockfd != -1)
{
shutdown(sockfd, 2);
close(sockfd);
sockfd = -1;
}
}
/*函数作用:关闭套接字*/
void BaseTcp::Close()
{
if(sockfd != -1)
{
//shutdown(sockfd, 2);
close(sockfd);
sockfd = -1;
}
}
int BaseTcp::getSocket()
{
return sockfd;
}
/*函数作用:将字符串型的IP,端口,转为数值型存入dst结构中
* 返回0,转换成功,-1失败*/
int BaseTcp::hostToNum(const char* ip, const int port, struct sockaddr_in *dst)
{
//转换要绑定的IP地址
if(inet_pton(AF_INET, ip, &dst->sin_addr))
{
dst->sin_port = htons(port);
dst->sin_family = AF_INET;
return 0;
}
return -1;
}
/*函数作用:将IP,port绑定在套接字上,内部使用了socket和bind函数,阻塞类型
* 成功:返回0
* 失败:返回-1*/
int BaseTcp::blockTcpInit(const char *ip, const int port)
{
struct sockaddr_in souraddr;
//将ip,port转为结构体中保存
if(hostToNum(ip, port, &souraddr) == 0)
{
//绑定套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd != -1)
{
int flag = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
if(bind(sockfd, (struct sockaddr *)&souraddr, sizeof(struct sockaddr)) == 0)
{
way = 0;
return 0;
}
//cout<<"error1"<<endl;
}
//cout<<"error2"<<endl;
}
return -1;
}
int BaseTcp::blockTcpInit(const struct sockaddr_in *souraddr)
{
//绑定套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd != -1)
{
if(bind(sockfd, (struct sockaddr *)souraddr, sizeof(struct sockaddr)) == 0)
{
way = 0;
return 0;
}
}
return -1;
}
/*函数作用:将IP,port绑定在套接字上,内部使用了socket和bind函数,非阻塞类型
* 成功:返回0
* 失败:返回-1*/
int BaseTcp::nonblockTcpInit(const char *ip, const int port)
{
struct sockaddr_in souraddr;
//将ip,port转为结构体中保存
if(hostToNum(ip, port, &souraddr) == 0)
{
//绑定套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd != -1)
{
if(bind(sockfd, (struct sockaddr *)&souraddr, sizeof(struct sockaddr)) == 0)
{
if(set_nonblocking(sockfd, 1) == 0)
{
way = 1;
return 0;
}
}
}
}
return -1;
}
int BaseTcp::nonblockTcpInit(const struct sockaddr_in *souraddr)
{
//绑定套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd != -1)
{
if(bind(sockfd, (struct sockaddr *)souraddr, sizeof(struct sockaddr)) == 0)
{
if(set_nonblocking(sockfd, 1) == 0)
{
way = 1;
return 0;
}
}
}
return -1;
}
/*函数作用:connect到IP,PORT
* 成功返回0,失败返回-1*/
int BaseTcp::TcpConnect(const char *ip, const int port)
{
struct sockaddr_in souraddr;
//将ip,port转为结构体中保存
if(hostToNum(ip, port, &souraddr) == -1)
{
return -1;
}
return connect(sockfd, (struct sockaddr *)&souraddr, sizeof(struct sockaddr));
}
int BaseTcp::TcpConnect(const struct sockaddr_in *souraddr)
{
return connect(sockfd, (struct sockaddr *)souraddr, sizeof(struct sockaddr));
}
/*函数作用:写入buf中n字节的数据
* 返回值:-1为错误,否则返回写入的字节*/
ssize_t BaseTcp::writen(const void *buf, size_t n)
{
size_t nleft;
ssize_t nwritten;
const unsigned char *ptr;
ptr = (unsigned char* )buf;
nleft = n;
nwritten = 0;
while(nleft > 0)
{
if((nwritten = write(sockfd, ptr, nleft)) <= 0)
{
if(nwritten < 0 && errno == EINTR)
{
nwritten = 0;
}
else
{
//如果是阻塞模式读
if(way == 1)
{
//不是错误,而是没有空间写了
if(errno == EWOULDBLOCK)
{
nwritten = 0;
continue;
}
}
//printPeer(sockfd);
//cout<<"写错误:"<<errno<<endl;
return -1;
}
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
void printPeer(int sockfd, ostream *output);
/*函数作用:读取套接字中的数据到buf,读取n字节
* 返回值:-1为错误,否则为读取的字节数目
-2,非阻塞诶模式下的读结束*/
ssize_t BaseTcp::readn(void *buf, const size_t n)
{
size_t nleft;
ssize_t nread;
unsigned char *ptr;
ptr = (unsigned char *)buf;
//记录还未读取的数目
nleft = n;
//记录读取了的数目
nread = 0;
//如果还没读完
while(nleft > 0)
{
// cout<<"nleft = "<<nleft<<endl;
if((nread = read(sockfd, ptr, nleft)) < 0)
{
//受到中断,重新读
if(errno == EINTR)
{
nread = 0;
}
else
{
if(way == 1)
{
//不是错误,而是写到了数据尾部
if(errno == EWOULDBLOCK)
{
continue;
//return -2;
}
}
printPeer(sockfd, &cout);
cout<<"读错误:"<<errno<<endl;
return -1;
}
}
else
{
if(nread == 0)
{
break;
}
// ptr[nread] = '\0';
// cout<<ptr<<endl;
nleft -= nread;
ptr += nread;
}
}
return (n - nleft);
}
/*函数作用:将sockaddr转为字符串类型输出*/
void numToHost(struct sockaddr* sockaddr, char *ip)
{
struct in_addr s = ((struct sockaddr_in*)sockaddr)->sin_addr;
inet_ntop(AF_INET, &s, ip, 16);
}
/*函数作用:打印套接字sockfd绑定的源和目的IP*/
void printPeer(int sockfd, ostream *output)
{
struct sockaddr local, peer;
char ip[20];
socklen_t len = sizeof(struct sockaddr);
getsockname(sockfd, &local, &len);
numToHost(&local, ip);
*output<<"源地址:"<<ip<<endl;
getpeername(sockfd, &peer, &len);
numToHost(&peer, ip);
*output<<"目的地址:"<<ip<<endl;
}
文件:baseTcp.h
/* 作者:zxx
* 日期:2012.05.29
* 描述:基本套接字类
* */
#ifndef BASE_TCP
#define BASE_TCP
#include "sys/socket.h"
#include "errno.h"
#include "netdb.h"
#include "string.h"
#include "arpa/inet.h"
#include "stdio.h"
#include "iostream"
#include <unistd.h>
#include <fcntl.h>
#include "fstream"
using namespace std;
//#include ""
class BaseTcp
{
private:
int sockfd;
/*0----block,1-----nonblock*/
int way;
int set_nonblocking(int fd, int nonblocking);
public:
//初始化Tcp连接的函数,内置调用socket和bind
int blockTcpInit(const char *ip, const int port);
int blockTcpInit(const struct sockaddr_in* souraddr);
int nonblockTcpInit(const char *ip, const int port);
int nonblockTcpInit(const struct sockaddr_in* souraddr);
int TcpConnect(const char *ip, const int port);
int TcpConnect(const struct sockaddr_in *souraddr);
ssize_t writen(const void *buf, size_t n);
ssize_t readn(void *buf, const size_t n);
void Close();
void forseClose();
int getSocket();
int hostToNum(const char* ip, const int port, struct sockaddr_in *dst);
static int getHostIPAddr(const unsigned char *host, unsigned char *ip);
int getErrno();
BaseTcp();
~BaseTcp();
};
#endif
文件:encoding.cpp
/*作者:zxx
日期:2012.09.07
程序描述:基础类,用于字符串编码解码*/
#include "encoding.h"
/*函数作用:将utf编码转为gbk编码
成功:返回0*/
int myEncode::API_IC_UTFToGBK(std::string& str)
{
const char * rsIn = str.c_str();
int rsInLength = str.length();
char buff[str.length() + 128];
memset(buff, 0, sizeof(buff));
char *rsOut = buff;
int rsOutLength = str.length() + 128;
int iLeftRoomLen,iLeftInLen,iOutLen;
iconv_t stCvt;
stCvt = iconv_open("GBK", "UTF-8");
if (stCvt == 0) return -1;
iLeftInLen = rsInLength;
iLeftRoomLen = iLeftInLen * 4 + 1;
iOutLen = iLeftRoomLen;
char * pszWorkingBuffer = new char[iLeftRoomLen];
if (pszWorkingBuffer == NULL)
return -1;
char * pszOutBuf = pszWorkingBuffer;
memset(pszWorkingBuffer,0,iLeftRoomLen);
int iRet;
char *pInBuf = (char *)rsIn;
while (iLeftInLen > 0)
{
iRet = iconv(stCvt, &pInBuf, (size_t*)&iLeftInLen, &pszWorkingBuffer, (size_t *)&iLeftRoomLen);
if (iRet == (int)((size_t)-1))
{
if (errno == EILSEQ)
{
iLeftInLen -= 2;
pInBuf += 2;
}
else
{
iconv_close(stCvt);
delete[] pszOutBuf;
return -2;
}
}
}
iconv_close(stCvt);
pszOutBuf[iOutLen - iLeftRoomLen] = 0;
rsOutLength = iOutLen - iLeftRoomLen;
memcpy(rsOut, pszOutBuf, rsOutLength);
delete[] pszOutBuf;
str = rsOut;
return 0;
}
/*函数作用:将gbk编码转为utf-8编码
成功:返回0*/
/*int myEncode::API_Gbk2Utf8(const char *szSource, std::string &strDest)
{
char szUniString[strlen(szSource)*2];
int iLen = string_gbk2unicode(szSource, szUniString, strlen(szSource));
unsigned char pTemp[4] = {0};
unsigned short iTemp;
char *pUTFString = (char *)malloc(sizeof(szUniString) *2+1);
int pos = 0;
for (int i=0; i<iLen; i++)
{
iTemp = (((unsigned char)szUniString[i])<<8) + (szUniString[i+1] & 0xff);
i++;
int len= UCS2toUTF8Code(iTemp, pTemp);
if (0 == len)
{
return -1;
}else{
memcpy((void*)(pUTFString+pos),(const void*)pTemp,len);
pos+=len;
}
memset(pTemp , 0 ,sizeof(pTemp));
}
pUTFString[pos]='\0';
strDest = pUTFString;
free(pUTFString);
return 0;
}*/
/*函数作用:将szToEncode进行url编码
成功:返回编码后的数据*/
std::string myEncode::UrlEncode(const std::string& szToEncode)
{
std::string src = szToEncode;
char hex[] = "0123456789ABCDEF";
string dst;
for (size_t i = 0; i < src.size(); ++i)
{
unsigned char cc = src[i];
if (isascii(cc))
{
if (cc == ' ')
{
dst += "%20";
}
else
dst += cc;
}
else
{
unsigned char c = static_cast<unsigned char>(src[i]);
dst += '%';
dst += hex[c / 16];
dst += hex[c % 16];
}
}
return dst;
}
/*函数作用:将szToEncode进行url解码
成功:返回解码后的数据*/
std::string myEncode::UrlDecode(const std::string& szToDecode)
{
std::string result;
int hex = 0;
for (size_t i = 0; i < szToDecode.length(); ++i)
{
switch (szToDecode[i])
{
case '+':
result += ' ';
break;
case '%':
if (isxdigit(szToDecode[i + 1]) && isxdigit(szToDecode[i + 2]))
{
std::string hexStr = szToDecode.substr(i + 1, 2);
hex = strtol(hexStr.c_str(), 0, 16);
//字母和数字[0-9a-zA-Z]、一些特殊符号[$-_.+!*'(),] 、以及某些保留字[$&+,/:;=?@]
//可以不经过编码直接用于URL
if (!((hex >= 48 && hex <= 57) || //0-9
(hex >=97 && hex <= 122) || //a-z
(hex >=65 && hex <= 90) || //A-Z
//一些特殊符号及保留字[$-_.+!*'(),] [$&+,/:;=?@]
hex == 0x21 || hex == 0x24 || hex == 0x26 || hex == 0x27 || hex == 0x28 || hex == 0x29
|| hex == 0x2a || hex == 0x2b|| hex == 0x2c || hex == 0x2d || hex == 0x2e || hex == 0x2f
|| hex == 0x3A || hex == 0x3B|| hex == 0x3D || hex == 0x3f || hex == 0x40 || hex == 0x5f
))
{
result += char(hex);
i += 2;
}
else result += '%';
}else {
result += '%';
}
break;
default:
result += szToDecode[i];
break;
}
}
return result;
}
//int main(){}
文件:encoding.h
/*作者:zxx
日期:2012.09.07
程序描述:基础类,用于字符串编码解码*/
#ifndef MY_ENCODE
#define MY_ENCODE
#include "string.h"
#include "stdlib.h"
#include "iconv.h"
#include "errno.h"
#include "string"
using namespace std;
//
class myEncode
{
public:
static int API_IC_UTFToGBK(std::string& str);
//int API_Gbk2Utf8(const char *szSource, std::string &strDest);
static string UrlEncode(const string& szToEncode);
static string UrlDecode(const string& szToDecode);
};
#endif
文件:mycompress.cpp
//http://hi.baidu.com/anyclick/item/88d3debf98b24cd385dd794e
//http://www.cppblog.com/woaidongmao/archive/2011/06/05/148089.html
/*作者:zxx
日期:2012.09.07
程序描述:基础类,用于字符串编码解码*/
#include "mycompress.h"
/*函数作用:将数据进行gzip解压
唱功:返回Z_OK*/
int myCompress::gzip_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
{
z_stream stream;
int err;
stream.next_in = (Bytef*)source;
stream.avail_in = (uInt)sourceLen;
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
err = inflateInit2(&stream, 16+MAX_WBITS);
if (err != Z_OK) return err;
err = inflate(&stream, Z_NO_FLUSH);
if (err != Z_STREAM_END) {
inflateEnd(&stream);
if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
return Z_DATA_ERROR;
return err;
}
*destLen = stream.total_out;
err = inflateEnd(&stream);
return err;
}
/*函数作用:将数据进行gzip压缩
唱功:返回0,失败返回-1*/
/* Compress gzip data */
int myCompress::gzip_compress(Bytef *data, uLong ndata, Bytef *zdata, uLong *nzdata)
{
z_stream c_stream;
int err = 0;
if(data && ndata > 0)
{
c_stream.zalloc = (alloc_func)0;
c_stream.zfree = (free_func)0;
c_stream.opaque = (voidpf)0;
if(deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
c_stream.next_in = data;
c_stream.avail_in = ndata;
c_stream.next_out = zdata;
c_stream.avail_out = *nzdata;
while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)
{
if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;
}
if(c_stream.avail_in != 0) return c_stream.avail_in;
for (;;) {
if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;
if(err != Z_OK) return -1;
}
if(deflateEnd(&c_stream) != Z_OK) return -1;
*nzdata = c_stream.total_out;
return 0;
}
return -1;
}
//int main(){}
文件:mycompress.h
/*作者:zxx
日期:2012.09.07
程序描述:基础类,用于字符串压缩
注意:编译的时候要加上-lz选项指明zlib库函数*/
#ifndef MY_COMPRESS
#define MY_COMPRESS
#include "zlib.h"
class myCompress
{
public:
static int gzip_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
static int gzip_compress(Bytef *data, uLong ndata, Bytef *zdata, uLong *nzdata);
};
#endif