【自动回帖器/原理】自动回帖器的原理与实现(二)代码篇


请先阅读 自动回帖器的原理与实现(一)原理篇

一共有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 *)&para[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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值