争取一天看一个文件,随便找一个好看的看起eva/src/api/evaipseek
#ifndef EVAIPSEEKER_H
#define EVAIPSEEKER_H
#include <string>
#include <fstream>
//一看头文件,只有file操作,看来不是socket相关
class EvaIPSeeker
{
public:
EvaIPSeeker();
EvaIPSeeker(std::string absPath);
~EvaIPSeeker();
const std::string getIPLocation(const std::string ip);
const std::string getIPLocation(const unsigned int ip);
const bool isQQWryExisted();
private:
unsigned int searchIP(const unsigned int ip);
unsigned int readIP(unsigned int offset);
unsigned int getMiddleOffset(const unsigned int begin, const unsigned int end);
int compareIP(const unsigned int ip1, const unsigned int ip2);
std::string getIPRecord(const unsigned int offset);
std::string readString(const unsigned int offset);
std::string readArea(const unsigned int offset);
bool getIndexOffset(std::fstream& inputfile);
private:
std::fstream ipFile; //file i/o stream
std::string fileName; //the data file path
int firstIndexOffset; //the first index offset of the index area
int lastIndexOffset; //the last index offset of the index area
char byte4[4]; //tmp char array
char byte3[3]; //tmp char array
};
#endif
/***************************************************************************
* Copyright (C) 2005 by casper *
* tlmcasper@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <iostream>
#include <string>
#include <fstream>
#include “evaipseeker.h”
#include “evaipaddress.h”//这里还依赖一个文件,看来得看看这个
#define STRING_LEN 80
#define IP_RECORD_LENGTH 7
#define REDIRECT_MODE_1 0x01
#define REDIRECT_MODE_2 0x02
#define DATAFILENAME “QQWry.dat” //qq直接用文件,都不用sql
#define READINT3(X) (( X[0] & 0xFF )|(( X[1] & 0xFF)<< 8 )|(( X[2] & 0xFF )<< 16 )) //用移位操作的都是高手,是否?
#define READINT4(X) (( X[0] & 0xFF )|(( X[1] & 0xFF)<< 8 )|(( X[2] & 0xFF )<< 16 )|(( X[3] & 0xFF ) << 24 ))
using namespace std;
//get the path of IP data file which is in the working directory,store in @fileName
//param:null
//return:null
EvaIPSeeker::EvaIPSeeker()
{
fileName = DATAFILENAME;
}
//get the absolute path of IP data file,store it in @fileName;
//param: string absPath
//return: null
EvaIPSeeker::EvaIPSeeker(string absPath)
{
fileName = absPath + “/” + DATAFILENAME;
}
//check the status of IP data file,close it if it opened.
//param: null
//return: null
EvaIPSeeker::~EvaIPSeeker()
{
if(ipFile.is_open())
ipFile.close();
}
//check if QQWry.dat exists
//param: null
//return: true or false
const bool EvaIPSeeker::isQQWryExisted()
{
ipFile.open(fileName.c_str(), ios::in);
if(!ipFile)
return false;
else
{
ipFile.close();
return true;
}
}
//search ip in the index area of IP data file,return the offset of IP record if found.
//param: unsigned int ip
//return: unsigned int offset
unsigned int EvaIPSeeker::searchIP(const unsigned int ip)
{
unsigned int startIP;
unsigned int endIP;
unsigned int midIP,mOffset;
int r;
unsigned int i,j;
startIP = readIP(firstIndexOffset);
endIP = readIP(lastIndexOffset);
r = compareIP(ip,startIP);
if(r == 0)
return firstIndexOffset;
else if(r < 0)
return 0;
for(i = firstIndexOffset, j = lastIndexOffset; i < j;)
{
mOffset = getMiddleOffset(i, j);
midIP = readIP(mOffset);
r = compareIP(ip, midIP);
if(r > 0)
i = mOffset;
else if(r < 0)
{
if(mOffset == j)
{
j -= IP_RECORD_LENGTH;
mOffset = j;
}
else
j = mOffset;
}
else
{
if(!ipFile.is_open())
ipFile.open(fileName.c_str(), ios::in|ios::binary);
ipFile.seekg(mOffset+4, ios::beg);
ipFile.read(byte3, 3);
ipFile.close();
return READINT3(byte3);
}
}
if(!ipFile.is_open())
ipFile.open(fileName.c_str(), ios::in|ios::binary);
ipFile.seekg(mOffset+4, ios::beg);
ipFile.read(byte3, 3);
midIP = readIP(READINT3(byte3));
r = compareIP(ip, midIP);
if(r <= 0) return READINT3(byte3);
else return 0;
}
//read 4 bytes start from the offset,and change them to an IP address.
//param: unsigned int offset
//return: unsigned int IP
unsigned int EvaIPSeeker::readIP(unsigned int offset)
{
unsigned int tmpIP;
if(!ipFile.is_open())
ipFile.open(fileName.c_str(), ios::in|ios::binary);
ipFile.seekg(offset, ios::beg);
ipFile.read(byte4,4);
tmpIP = READINT4(byte4);
ipFile.close();
return tmpIP;
}
//compare two IP
//param: unsigned int ip1, unsigned int ip2
//return: int result
int EvaIPSeeker::compareIP(const unsigned int ip1, const unsigned int ip2)
{
if( ip1 > ip2 ) return 1;
else if ( ip1 < ip2 ) return -1;
else return 0;
}
//get the middle offset of two offsets.
//param: unsigned int begin, unsigned int end
//return: unsigned int theMiddleOffset
unsigned int EvaIPSeeker::getMiddleOffset(const unsigned int begin, const unsigned int end)
{
int records = (end – begin) / IP_RECORD_LENGTH;
records >>= 1;
if(records == 0) records = 1;
return begin + records * IP_RECORD_LENGTH;
}
//read a string start from the offset until meet a char ‘\0’
//param: unsigned int offset
//return: string str
string EvaIPSeeker::readString(const unsigned int offset)
{
static char tmpstr[STRING_LEN];
string str;
ipFile.seekg(offset, ios::beg);
ipFile.getline(tmpstr,STRING_LEN,’\0′);
str = tmpstr;
return str;
}
//get one IP record (country and area) of the offset
//param: unsigned int offset
//return: string location
string EvaIPSeeker::getIPRecord(const unsigned int offset)
{
char flag;
string country;
string area;
string location;
unsigned int countryOffset;
if(!ipFile.is_open())
ipFile.open(fileName.c_str(), ios::in|ios::binary);
ipFile.seekg(offset+4, ios::beg);//ignore the ip data
ipFile.get(flag);
if(flag == REDIRECT_MODE_1)
{
ipFile.read(byte3, 3);
countryOffset = READINT3(byte3); //get the offset of country data
ipFile.seekg(countryOffset);
ipFile.get(flag); // check the flag again,maybe it’s an other redirectroy
if(flag == REDIRECT_MODE_2)
{
ipFile.read(byte3, 3);
country = readString(READINT3(byte3));
ipFile.seekg(countryOffset+4);//if mode2,we need pass 4 bytes to reach the area data;
}
else
{
country = readString(countryOffset);
}
area = readArea(ipFile.tellg());
}
else if(flag == REDIRECT_MODE_2)
{
ipFile.read(byte3, 3);
country = readString(READINT3(byte3));
area = readArea(offset+8);
}
else
{
ipFile.putback(flag);//make the inside pointer back 1 character
country = readString(ipFile.tellg());
area = readArea(ipFile.tellg());
}
location = country + area;
ipFile.close();
return location;
}
//read the Area data start from the offset.
//param: unsigned int offset
//return: string areaData
string EvaIPSeeker::readArea(const unsigned int offset)
{
char flag;
unsigned int areaOffset;
ipFile.seekg(offset, ios::beg);
ipFile.get(flag);
if(flag == REDIRECT_MODE_1 || flag == REDIRECT_MODE_2)
{
ipFile.read(byte3, 3);
areaOffset = READINT3(byte3);
if(areaOffset != 0)
return readString(areaOffset);
else
return “Unknow Area”;//if the areaoffset is zero,it’s show there’s no data for the area
}
else
return readString(offset);
}
//get the Index arrange of the Index area from infile
//param: fstream& infile
//return: true or false
bool EvaIPSeeker::getIndexOffset(fstream& infile)
{
infile.seekg(ios::beg);
infile.read(byte4, 4);
firstIndexOffset = READINT4(byte4);
infile.read(byte4, 4);
lastIndexOffset = READINT4(byte4);
if(( firstIndexOffset == -1 )||( lastIndexOffset == -1 ))
{
return false;
}
return true;
}
//main function, get the location of an IP address,if IP is not valid or the Data file missed then return IP address.
//param: unsigned int ip
//return: string location or string ip
const string EvaIPSeeker::getIPLocation(const unsigned int ip)
{
EvaIPAddress addr(ip);
if(!isQQWryExisted())
return addr.toString();
ipFile.open(fileName.c_str(), ios::in|ios::binary);
if(!ipFile)
return addr.toString();
else
{
if(!getIndexOffset(ipFile))
{
ipFile.close();
return addr.toString();
}
return getIPRecord(searchIP(addr.IP()));
}
}
//main function, get the location of an IP address,if IP is not valid or the Data file missed then return IP address.
//param: string ip
//return: string location or string ip
const string EvaIPSeeker::getIPLocation(const string ip)
{
EvaIPAddress addr(ip);
if(!addr.isValid())
return addr.toString();
if(!isQQWryExisted())
return addr.toString();
ipFile.open(fileName.c_str(), ios::in|ios::binary);
if(!ipFile)
return addr.toString();
else
{
if(!getIndexOffset(ipFile))
{
ipFile.close();
return addr.toString();
}
return getIPRecord(searchIP(addr.IP()));
}
}
更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2013-10/92148p2.htm
相关阅读:
Ubuntu7.10下安装最新版EVA QQ来聊天 http://www.linuxidc.com/Linux/2007-11/9003.htm
CentOS下安装EVA QQ http://www.linuxidc.com/Linux/2013-07/87051.htm
没看到具体的关键实现,只是一个文件检索。保存了ip,国家,地区信息。忽略之。
#ifndef EVAIPADDRESS_H
#define EVAIPADDRESS_H
#include <inttypes.h>
#include <string>
/*
this class is only for ipv4 addresses
this class can be used as below:
EvaIPAddress addr(“255.255.255.255”); // or EvaIPAddress addr(0xffffffff) ;
uint ip = addr.IP();
std::string strIP = addr.toString();
*/
class EvaIPAddress{
public:
EvaIPAddress() {};
EvaIPAddress(const uint ip);
EvaIPAddress(const std::string &strIP);
EvaIPAddress(const EvaIPAddress &address);
void setAddress(const uint ip);
void setAddress(const std::string &strIP);
const bool isValid() const;
const uint IP() const;
const std::string toString();
EvaIPAddress &operator= (const EvaIPAddress &rhs);
private:
bool isValidIP;
uint mIP;
uint getIntIP(const std::string &strIP);
};
#endif
看着头文件,也只是一个工具类。
/***************************************************************************
* Copyright (C) 2005 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evaipaddress.h”
#include <stdlib.h>
EvaIPAddress::EvaIPAddress(const uint ip)
:isValidIP(false)
{
mIP = ip;
isValidIP = true;
}
EvaIPAddress::EvaIPAddress(const std::string &strIP)
:isValidIP(false)
{
mIP = getIntIP(strIP);
if(mIP)
isValidIP = true;
}
EvaIPAddress::EvaIPAddress(const EvaIPAddress &address)
:isValidIP(false)
{
mIP = address.IP();
isValidIP = address.isValid();
}
void EvaIPAddress::setAddress(const uint ip)
{
mIP = ip;
}
void EvaIPAddress::setAddress(const std::string &strIP)
{
mIP = getIntIP(strIP);
}
const bool EvaIPAddress::isValid() const
{
return isValidIP;
}
const uint EvaIPAddress::IP() const
{
return mIP;
}
const std::string EvaIPAddress::toString()
{
char strIP[16];
memset(strIP, 0, 16);
sprintf(strIP, “%d.%d.%d.%d”, (mIP&0xFF000000)>>24, (mIP&0x00FF0000)>>16, (mIP&0x0000FF00)>>8, (mIP&0x000000FF));
return std::string(strIP);
}
EvaIPAddress &EvaIPAddress::operator= (const EvaIPAddress &rhs)
{
mIP = rhs.IP();
isValidIP = rhs.isValid();
return *this;
}
uint EvaIPAddress::getIntIP(const std::string &strIP)
{
int num = 0;
for(uint i=0; i< strIP.length(); i++)
if(strIP[i] == ‘.’) num++;
// check if it consists of 4 parts
if(num != 3){
isValidIP = false;
return 0;
}
// get all 4 parts in
unsigned char parts[4];
int start = 0, end = 0;
for(int i=0; i<4; i++){
for(uint j= start; j<strIP.length(); j++){
if(strIP[j] == ‘.’){
end = j;
break;
}
if(strIP[j] < ‘0’ || strIP[j] > ‘9’){
isValidIP = false;
return 0;
}
}
//printf(“3 strIP:%s\n”,strIP.c_str());
std::string tmp = strIP.substr(start, end – start);
int tmpInt = atoi(tmp.c_str());
if(tmpInt< 0 || tmpInt > 255){
isValidIP = false;
return 0;
}
parts[i] = (unsigned char)tmpInt;
start = end + 1;
}
// put all 4 parts into one uint
return ((uint)parts[0])<<24 | ((uint)parts[1])<<16 | ((uint)parts[2])<<8 | parts[3];
}
不错,这个工具类,自己可以随时用到。 随时拿来主义。嘎嘎
刚看了2个文件,都很基础,没花时间,接着看。。。
#ifndef EVACONNECTER_H
#define EVACONNECTER_H
#include <qobject.h>
#include <qptrlist.h>//ptr-list,指着list,qt还有这list
#include <qhostaddress.h>
#include <qstring.h>
#include “evapacket.h” //看来又得多看2个文件
#include “evanetwork.h”
class QTimer; //o ,要是定时判断,connect–timeout–
class EvaConnecter : public QObject {
Q_OBJECT
public:
EvaConnecter(EvaNetwork *network);
~EvaConnecter();
void append(OutPacket *out);
InPacket *getInPacket();
const unsigned int numOfOutPackets() const { return outPool.count(); }//现在什么都要搞个pool
const unsigned int numOfInPackets() const { return inPool.count(); }
void redirectTo(const int ip, const short port);
void connect();
void stop();
void clientReady();
const EvaNetwork::Type getConnectionType() const { return connecter->connectionType(); }
const QHostAddress getSocketIp();
const unsigned int getSocketPort();
signals:
void isReady();
void networkException(int);
void packetException(int);
void sendMessage(int, bool);
void sendQunMessage(int, bool, QString);//哇。群啊
void newPacket();
void clientNotReady();
private:
bool connectionReady;
bool isClientSetup;
QPtrList<InPacket> inPool; //一个poll就是一个链表,ptr-list与直接用list区别在哪里
QPtrList<OutPacket> outPool;
QTimer *timer;
bool isConnected;
bool isMonitorRunning;
EvaNetwork *connecter;
unsigned char buffer[65535]; //哇。这么大的buffer,存的什么
unsigned short packetLength;
unsigned int bufLength;
void sendOut( OutPacket *out);
void removePacket(const int hashCode ); // remove packet which needs acknowlegement,都用到hash了。
void removeOutRequests(const short cmd);
private slots:
void isReadySlot();
void processPacket(char *data, int len);
void dataCommingSlot(int len);
void packetMonitor();
void clearAllPools();
};
#endif
开始接近核心处理逻辑,网络通信等,兴奋ing
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evaconnecter.h”//哦,又加了这么多头文件
#include “evaqtutil.h”
#include “evahtmlparser.h”
#include “evaimsend.h”
#include “evaqun.h”
#include <qtimer.h>
#include <qmutex.h>//用上了锁,多线程了
#include <arpa/inet.h>
#include <stdlib.h>
#define POOL_CHECK_INTERVAL 2000 /// every 2 second check two pools, 2秒,才检查一次,这么久
EvaConnecter::EvaConnecter(EvaNetwork *network)
{
memset(buffer, 0, 65535);
packetLength = 0;
bufLength = 0;
connecter = network;
connectionReady = false;
isMonitorRunning = false;
isClientSetup = false;
QObject::connect(connecter, SIGNAL(isReady()), this, SLOT(isReadySlot()));
QObject::connect(connecter, SIGNAL(dataComming(int)), this, SLOT(dataCommingSlot(int)));
QObject::connect(connecter, SIGNAL(exceptionEvent(int)), this, SIGNAL(networkException(int)));
outPool.setAutoDelete(true);
inPool.setAutoDelete(false);
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(packetMonitor()));
}
EvaConnecter::~EvaConnecter()
{
delete connecter;
if(timer->isActive())
timer->stop();
delete timer;
}
void EvaConnecter::append(OutPacket *out)
{
sendOut(out); // force to send,这个函数哪里实现的,先清空out buffer,再往send buffer append data
if(out->needAck()){
outPool.append(out);
if(!timer->isActive()) // start out/in pool checking timer
timer->start(POOL_CHECK_INTERVAL, false);
}else
delete out;
}
InPacket *EvaConnecter::getInPacket()
{
if(inPool.count() <= 0 ){
emit packetException(-1);
return NULL;
}
return inPool.take();
}
void EvaConnecter::redirectTo(const int ip, const short port)
{
inPool.clear();
outPool.clear();
//http代理,,不是tcp,udp发送??
if(connecter->connectionType()!= EvaNetwork::HTTP_Proxy){
connectionReady = false;
connecter->setServer(QHostAddress(ip), port==-1?connecter->getHostPort():port);
}else{
connecter->setServer(connecter->getHostAddress(), connecter->getHostPort());
connecter->setDestinationServer(QHostAddress(ip).toString(), 443); // always 443 for http proxy, http代理没玩过啊。不懂
}
connect();
}
void EvaConnecter::connect()
{
memset(buffer, 0, 65535);
packetLength = 0;
bufLength = 0;
connecter->connect();
}
void EvaConnecter::stop()
{
if(timer->isActive())
timer->stop();
while(isMonitorRunning);
//QTimer::singleShot(200, this, SLOT(clearAllPools()));
clearAllPools();
memset(buffer, 0, 65535);
packetLength = 0;
bufLength = 0;
connectionReady = false;
isMonitorRunning = false;
isClientSetup = false;
printf(“EvaConnecter stopped \n”);
}
void EvaConnecter::clearAllPools()
{
while(isMonitorRunning);
inPool.clear();
outPool.clear();
}
void EvaConnecter::sendOut( OutPacket *out)
{
if(timer->isActive())
timer->stop();
if(!connectionReady) return;
unsigned char *buf = (unsigned char *)malloc(MAX_PACKET_SIZE * sizeof(unsigned char));//这个宏,哪里定义的
int len;
out->fill(buf, &len);
connecter->write((char *)buf, len);
free(buf);
if(!timer->isActive())
timer->start(POOL_CHECK_INTERVAL, false);
}
void EvaConnecter::removePacket(const int hashCode)
{
QMutex mutex;
mutex.lock();
for( uint i = 0; i < outPool.count(); i++){
if(outPool.at(i)->hashCode() == hashCode){
outPool.remove(i);
–i;
}
}
mutex.unlock();
}
void EvaConnecter::removeOutRequests(const short cmd)
{
while(isMonitorRunning);
for( uint i = 0; i < outPool.count(); i++){
if(outPool.at(i)->getCommand() == cmd){
outPool.remove(i);//packet里面有个cmd字段
–i;
}
}
}
void EvaConnecter::isReadySlot()
{
connectionReady = true;
emit isReady();//这不是死循环吗?信号–槽–信号
}
void EvaConnecter::dataCommingSlot(int len)
{
char *rawData = new char[len+1];
if(!connecter->read(rawData, len)){
fprintf(stderr, “–Eva Connecter: Bytes read wrong!\n”);
return;
}
if(connecter->connectionType() != EvaNetwork::UDP){
memcpy(buffer+bufLength, rawData, len);
bufLength += len;
delete []rawData;
unsigned short tmp;
memcpy(&tmp, buffer, 2);
packetLength = ntohs(tmp);
//操作了这么多,到底干了什么?
while(bufLength >= packetLength){
rawData = new char[packetLength];
memcpy(rawData, buffer, packetLength);
memcpy(buffer, buffer + packetLength, bufLength – packetLength);
len = packetLength;
bufLength -=packetLength;
processPacket(rawData, len);//最后还是这个函数处理
delete []rawData;
if(!bufLength) break;
memcpy(&tmp, buffer, 2);
packetLength = ntohs(tmp);
}
}else{
processPacket(rawData, len);//这个是udp处理。。
delete []rawData;
}
}
void EvaConnecter::processPacket( char * data, int len )
{
InPacket *packet = new InPacket((unsigned char *)data, len);
if(!packet->getLength()){
printf(“Bad packet, ignore it\n”);
delete packet;
return;
}
removePacket(packet->hashCode());
//心动包啊。。这个只是用户端,服务端在哪里?
if(packet->getCommand() == QQ_CMD_KEEP_ALIVE)
removeOutRequests(QQ_CMD_KEEP_ALIVE);
//为何直接移除了
if(packet->getCommand() == QQ_CMD_GET_FRIEND_ONLINE)
removeOutRequests(QQ_CMD_GET_FRIEND_ONLINE);
inPool.append(packet);
if(isClientSetup || (!isClientSetup && packet->getCommand()!= QQ_CMD_RECV_IM &&
packet->getCommand()!= QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS))
emit newPacket();
else if(!isClientSetup)
emit clientNotReady();
}
void EvaConnecter::packetMonitor()
{
if(!connectionReady) return;
if(isMonitorRunning) return;
isMonitorRunning = true;
for ( uint i=0; i < outPool.count(); i++ ){
if(outPool.at(i)->needResend()){
sendOut(outPool.at(i));
}else{
short cmd = outPool.at(i)->getCommand();
isMonitorRunning = false;
if(cmd == QQ_CMD_SEND_IM){
SendIM *im = dynamic_cast<SendIM *>(outPool.at(i));
if(im)
emit sendMessage(im->getReceiver(), false);
else
emit packetException( cmd);
} else if( cmd == QQ_CMD_QUN_CMD ){
QunPacket *qun = dynamic_cast<QunPacket *>(outPool.at(i));
if(qun){
char qunCmd = qun->getQunCommand();
if(qunCmd == QQ_QUN_CMD_SEND_IM || qunCmd == QQ_QUN_CMD_SEND_IM_EX)
emit sendQunMessage(qun->getQunID(), false, QString::null);
else
emit packetException(cmd);
} else
emit packetException(cmd);
} else
emit packetException(cmd);
if(!connectionReady) return;
if(!isMonitorRunning) return;
removePacket(outPool.at(i)->hashCode());
if(!outPool.count() && !inPool.count() && timer) timer->stop();
return;
}
}
if(isClientSetup && inPool.count()>0){
emit newPacket();
}
if(!outPool.count() && !inPool.count() && timer) timer->stop();
isMonitorRunning = false;
}
void EvaConnecter::clientReady( )
{
isClientSetup = true;
while(inPool.count())
emit newPacket();
}
const QHostAddress EvaConnecter::getSocketIp( )
{
if(connecter) return connecter->getSocketIp();
return QHostAddress();
}
const unsigned int EvaConnecter::getSocketPort( )
{
if(connecter) return connecter->getSocketPort();
return 0;
}
不错,越来越深入,,22:30,做几个俯卧撑,继续
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef EVANETWORK_H
#define EVANETWORK_H
#include <qobject.h>
#include <qhostaddress.h>
class EvaSocket;
class EvaHttpProxy;
class EvaNetwork : public QObject{
Q_OBJECT
public:
enum Type { UDP, TCP, HTTP_Proxy}; //3种方式,可以好好看看http代理,这方面技术没研究过
enum Event { Init, Connecting, Ready, Failed, None, BytesReadWrong,
Proxy_None, Proxy_TCP_Ready, Proxy_Connecting, Proxy_Ready,
Proxy_Need_Auth, Proxy_Read_Error, Proxy_Error };
EvaNetwork(const QHostAddress &host, const short port, const Type type = UDP);//默认是udp
~EvaNetwork();
//哦。有server,那么服务器部分的程序,有吗
void setServer(const QHostAddress &address, const short port);
const QHostAddress &getHostAddress() const; // if it’s Http Proxy, return the proxy’s address
const short getHostPort() const;
void setDestinationServer(const QString &server, const short port); // for Http Proxy only;
void setAuthParameter(const QString &username, const QString &password);//代理认证?
void setAuthParameter(const QCString ¶m);
void newURLRequest();
void connect();
bool read(char *buf, int len);
bool write(const char *buf, const int len);
void setWriteNotifierEnabled(bool enabled);
void close();
const Type connectionType() { return type; }
const QHostAddress getSocketIp();
const unsigned int getSocketPort();
signals:
void isReady();
void dataComming(int);
void exceptionEvent(int); // all in enum type Event;
void writeReady();
private:
EvaSocket *socket; //基本socket
Type type;
private slots:
void processProxyEvent(int);
};
#endif
/*********************************************************************
继续看cpp文件
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evanetwork.h”
#include “evasocket.h”
EvaNetwork::EvaNetwork(const QHostAddress &host, const short port, const Type type)
:socket(NULL)
{
this->type = type;
switch(type){
case UDP:
socket = new EvaSocket(host, port); // default is UDP
QObject::connect(socket, SIGNAL(isReady()), this, SIGNAL(isReady()));//socket—>this
QObject::connect(socket, SIGNAL(writeReady()), SIGNAL(writeReady()));
QObject::connect(socket, SIGNAL(receivedData(int)), this, SIGNAL(dataComming(int)));
QObject::connect(socket, SIGNAL(exceptionEvent(int)), this, SLOT(processProxyEvent(int)));
break;
case TCP:
socket = new EvaSocket(host, port, EvaSocket::TCP);
QObject::connect(socket, SIGNAL(isReady()), this, SIGNAL(isReady()));
QObject::connect(socket, SIGNAL(writeReady()), SIGNAL(writeReady()));
QObject::connect(socket, SIGNAL(receivedData(int)), this, SIGNAL(dataComming(int)));
QObject::connect(socket, SIGNAL(exceptionEvent(int)), this, SLOT(processProxyEvent(int)));
break;
case HTTP_Proxy:
socket = new EvaHttpProxy(host, port);
QObject::connect(socket, SIGNAL(proxyWriteReady()), SIGNAL(writeReady()));
QObject::connect(socket, SIGNAL(proxyEvent(int)), this, SLOT(processProxyEvent(int)));
QObject::connect(socket, SIGNAL(dataArrived(int)), this, SIGNAL(dataComming(int)));
QObject::connect(socket, SIGNAL(socketException(int)), this, SIGNAL(exceptionEvent(int)));
break;
default:
socket = new EvaSocket(host, port); // default is UDP
break;
}
}
EvaNetwork::~EvaNetwork()
{
if(socket) delete socket;
}
void EvaNetwork::setServer(const QHostAddress &address, const short port)
{
socket->setHost(address, port);
}
const QHostAddress &EvaNetwork::getHostAddress() const
{
return socket->getHostAddress();
}
const short EvaNetwork::getHostPort() const
{
return socket->getHostPort();
}
void EvaNetwork::setDestinationServer(const QString &server, const short port) // for Http Proxy only;
{
if(type != HTTP_Proxy) return;
//看来在这个类EvaHttpProxy里,实现了http代理,得详细看看
((EvaHttpProxy*)(socket))->setDestinationServer(server, port);
}
void EvaNetwork::setAuthParameter(const QString &username, const QString &password)
{
((EvaHttpProxy*)(socket))->setAuthParameter(username, password);
}
void EvaNetwork::setAuthParameter(const QCString ¶m)
{
((EvaHttpProxy*)(socket))->setBase64AuthParam(param);
}
void EvaNetwork::newURLRequest()
{
((EvaHttpProxy*)(socket))->tcpReady();
}
void EvaNetwork::connect()
{
socket->startConnecting();
}
bool EvaNetwork::read(char *buf, int len)
{
return socket->read(buf, len);
}
bool EvaNetwork::write(const char *buf, const int len)
{
return socket->write(buf, len);
}
//什么东西都是socket实现的,这里只是封装了一下
void EvaNetwork::setWriteNotifierEnabled(bool enabled)
{
socket->setWriteNotifierEnabled(enabled);
}
void EvaNetwork::processProxyEvent(int num)
{
if(type != HTTP_Proxy){
switch(num){
case EvaSocket::Init:
case EvaSocket::Connecting:
case EvaSocket::Ready:
case EvaSocket::Failed:
case EvaSocket::None:
case EvaSocket::BytesReadWrong:
emit exceptionEvent(num);
break;
}
}else{
switch(num){
case EvaHttpProxy::Proxy_None:
case EvaHttpProxy::Proxy_TCP_Ready:
case EvaHttpProxy::Proxy_Connecting:
break;
case EvaHttpProxy::Proxy_Ready:
emit isReady();
break;
case EvaHttpProxy::Proxy_Need_Auth:
emit exceptionEvent(Proxy_Need_Auth);
break;
case EvaHttpProxy::Proxy_Read_Error:
emit exceptionEvent(Proxy_Read_Error);
break;
case EvaHttpProxy::Proxy_Error:
emit exceptionEvent(Proxy_Error);
break;
}
}
}
void EvaNetwork::close( )
{
socket->closeConnection();
}
const QHostAddress EvaNetwork::getSocketIp( )
{
if(socket) return socket->getSocketAddress();
return QHostAddress();
}
const unsigned int EvaNetwork::getSocketPort( )
{
if(socket) return socket->getSocketPort();
return 0;
}
还是没啥具体实现,还是继续找最底层的socket函数
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef EVASERVERS_H
#define EVASERVERS_H
#include <qobject.h>
#include <qvaluelist.h> //qt这么多奇怪的list
#include <qhostaddress.h>
/**
This class loads all Tencent’s tcp and udp servers, and return a random server IP address
This class also involves some DNS operations.
看样子,是直接用qq的服务器,他从哪里知道的qq的服务器,还能有dns操作。未接触的知识
@author yunfan
*/
class QDns;
class EvaServers : public QObject
{
Q_OBJECT
public:
EvaServers(QString &dataRoot);
virtual ~EvaServers();
void fetchAddress(bool isUdp);
signals:
void isReady(QHostAddress ip);
private:
typedef struct serverItem{
int type;
QString addr;
} serverItem;
enum { UDP, TCP, Addr_URL, Addr_IP};
QString filename;
bool gotIP;
bool isLoaded;
int fetchType;
QDns *dns; //qt还有dns类。无所不能
QValueList<serverItem> TCPServers;
QValueList<serverItem> UDPServers;
bool loadServers();
void defaultAddress();
private slots:
void getResultsSlot();
};
#endif
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evaservers.h”
#include <qdns.h>
#include <qfile.h>
#include <qdatastream.h>
#include <qdatetime.h> // seed for rand()
#include <stdlib.h> // rand() function
EvaServers::EvaServers(QString &dataRoot):
gotIP(FALSE),
isLoaded(FALSE)
{
filename = dataRoot + “/servers”;
QTime t = QTime::currentTime();
srand( t.hour()*12+t.minute()*60+t.second()*60 );
isLoaded = this->loadServers();
dns = NULL;
}
EvaServers::~EvaServers()
{
delete dns;
}
void EvaServers::fetchAddress( bool isUdp )
{
int num = 0;
if(isUdp){
num = UDPServers.count();
fetchType = UDP;
} else{
num = TCPServers.count();
fetchType = TCP;
}
if(num == 0 ){
defaultAddress();
return;
}
int index = rand() % num;
serverItem addr;
if(isUdp)
addr = UDPServers[index];
else
addr = TCPServers[index];
if(addr.type == Addr_IP){
emit isReady(QHostAddress(addr.addr.latin1())); // this way, Red Hat 9 might work properly
return;
}
// the address should be a URL now, so we try to get the IP
if(dns!=NULL) {
QObject::disconnect(dns, 0,0,0);
delete dns;
}
dns = new QDns(addr.addr, QDns::A);
QObject::connect(dns, SIGNAL(resultsReady()), this, SLOT(getResultsSlot()));
}
bool EvaServers::loadServers( )
{
QFile file(filename);
if(!file.open(IO_ReadOnly)){
return FALSE;
}
QTextStream stream(&file);
QString line;
QStringList lineList;
int nextType = 0;
while(!stream.atEnd()){
line = stream.readLine().stripWhiteSpace();
if(line == “UDP”){
nextType = UDP;
continue;
}else if(line == “TCP”){
nextType = TCP;
continue;
} else if(line == “” ){
//nextType = 0;
continue;
}
lineList = QStringList::split(“:”, line);
if(lineList.size() != 2)
continue;
lineList[0].stripWhiteSpace();
serverItem *item = new serverItem();
if(lineList[0]==”URL”){
item->type = Addr_URL;
}else if(lineList[0]==”IP”){
item->type = Addr_IP;
}else
continue;
item->addr = lineList[1].stripWhiteSpace();
if(nextType == UDP){
UDPServers.append(*item);//从file里面获得server地址列表
}
if(nextType == TCP){
TCPServers.append(*item);
}
}
file.close();
return TRUE;
}
void EvaServers::defaultAddress()
{
if(fetchType == TCP){
emit isReady(QHostAddress(“218.17.209.23”)); //这个是缺省地址。
}else{
emit isReady(QHostAddress(“218.17.209.20”)); //又是tcp又是udp,腾讯真正的是怎么个逻辑通信的?
}
}
void EvaServers::getResultsSlot( )
{
QValueList<QHostAddress> list = dns->addresses();//域名解析出来ip地址
if(list.count() == 0 ){
defaultAddress();
return;
}
QHostAddress addr = list[0];
emit isReady(addr);
}
管中窥豹啊。
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef EVASOCKET_H
#define EVASOCKET_H
#include <qhostaddress.h>
#include <qcstring.h> //cstring,,这么多没用过的类
#include <qobject.h>
// Implementing UDP & TCP connections to Tencent Server
class QSocketDevice;
class QSocketNotifier;
class EvaSocket : public QObject {//这个socket类,也包括http?
Q_OBJECT
public:
enum Type { TCP, UDP};
enum Status { Init, Connecting, Ready, Failed, None, BytesReadWrong};
EvaSocket(const QHostAddress &host, const short port, const Type type = UDP);
~EvaSocket();
const Type getConnectType() const { return connectionType; }
void setHost( const QHostAddress &address, const short port);
const QHostAddress &getHostAddress() const { return server; }
const short getHostPort() const { return serverPort; }
const Status getStatus() const { return connectionStatus; }
void closeConnection();
void startConnecting();
bool write(const char *buf, const int len);
bool read(char *buf, int len);
const QHostAddress getSocketAddress();
const unsigned short getSocketPort();
void setWriteNotifierEnabled(bool enabled);
signals:
void isReady(); // emit when socket is connected
void receivedData(int); // emit after receiving data from server
void exceptionEvent(int); // emit whenever exception happens
void writeReady();
protected:
QSocketDevice *connectSocket;
QSocketNotifier *socketReadNotifier;
QSocketNotifier *socketWriteNotifier;
int receivedLength;
char *receivedBuffer;
private:
Type connectionType;
QHostAddress server;
short serverPort;
Status connectionStatus; // connected or not
private slots:
void slotWriteReady(int);
void slotReceiveReady(int);
};
// call read after receiving proxyEvent(Proxy_Ready) SIGNAL
class EvaHttpProxy : public EvaSocket {//基于socket
Q_OBJECT
public:
enum ProxyStatus { Proxy_None, Proxy_TCP_Ready, Proxy_Connecting, Proxy_Ready,
Proxy_Need_Auth, Proxy_Read_Error, Proxy_Error};
EvaHttpProxy(const QHostAddress &proxyHost, const short proxyPort, const QString username = QString::null,
const QString password = QString::null);
void setDestinationServer(const QString &server, const int port); // server could be IP or URL
const QString &getDestinationServer() const { return destinationAddress; }
void setAuthParameter(const QString &username, const QString &password);
const QCString &getBase64AuthParam() const { return base64AuthParam;}//主要就是进行了一些认证
void setBase64AuthParam(const QCString ¶m) { base64AuthParam = param; status = Proxy_None; }
bool doInitConnecting();
bool doAuthConnecting();
const ProxyStatus getProxyStatus() const { return status; }
signals:
void dataArrived(int);
void proxyEvent( int );
void socketException(int);
void proxyWriteReady();
public slots:
void tcpReady();
void slotWriteReady();
private:
ProxyStatus status;
QString destinationAddress;
QCString base64AuthParam;
QCString sentBuffer;
char *readBuffer;
void received(int len);
private slots:
void parseData(int len);
};
#endif
/***************************************************************************
* Copyright (C) 2004-2005 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evasocket.h”
#include “qmdcodec.h” //待研究
#include <stdlib.h>
#include <qsocketdevice.h>
#include <qsocketnotifier.h>
#include <qapplication.h>
#include <qmutex.h>
#include <qtimer.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/mman.h> //干嘛的
/*!
\class EvaSocket evasocket.h
\brief The EvaSocket class provides a UDP or TCP connection 看来不包含http
It provides a very simple non-blocking socket connection.
socketWriteNotifier is only used once to notify that the connection is ready
to write, after isReady() emited, socketWriteNotifier is disabled unless
setHost() is called.
*/
EvaSocket::EvaSocket(const QHostAddress &host, const short port, const Type type)
: socketReadNotifier(NULL), socketWriteNotifier(NULL)
{
connectionStatus = None;
receivedLength = 0;
receivedBuffer = NULL;
connectionType = type;
server = host;
serverPort = port;
if(connectionType == UDP){
connectSocket = new QSocketDevice(QSocketDevice::Datagram); //udp被当成device,qt这么认为
}else{
connectSocket = new QSocketDevice(QSocketDevice::Stream);
connectSocket->setBlocking(false);
socketWriteNotifier = new QSocketNotifier(connectSocket->socket(),
QSocketNotifier::Write,0,”writeNotifier”); //写通知,这个是基于epoll?select?poll?
QObject::connect(socketWriteNotifier,SIGNAL(activated(int)),SLOT(slotWriteReady(int)));
socketWriteNotifier->setEnabled(false);
}
socketReadNotifier = new QSocketNotifier(connectSocket->socket(),
QSocketNotifier::Read,0,”readNotifier”);
connectionStatus = Init;
QObject::connect(socketReadNotifier,SIGNAL(activated(int)),SLOT(slotReceiveReady(int)));
socketReadNotifier->setEnabled(false);
}
EvaSocket::~EvaSocket()
{
delete connectSocket;
if(socketReadNotifier) {
socketReadNotifier->setEnabled(false);
delete socketReadNotifier;
}
if(socketWriteNotifier) {
socketWriteNotifier->setEnabled(false);
delete socketWriteNotifier;
}
}
const QHostAddress EvaSocket::getSocketAddress( )
{
if(connectSocket) return connectSocket->address();
return QHostAddress();
}
const unsigned short EvaSocket::getSocketPort( )
{
if(connectSocket) return connectSocket->port();
return 0;
}
void EvaSocket::setHost(const QHostAddress &address, const short port)
{
server = address;
serverPort = port;
connectionStatus = None;
if(connectSocket->isValid()){
delete connectSocket;
if(socketReadNotifier) {
socketReadNotifier->setEnabled(false);
delete socketReadNotifier;
}
if(socketWriteNotifier) {
socketWriteNotifier->setEnabled(false);
delete socketWriteNotifier;
}
if(connectionType == UDP){
connectSocket = new QSocketDevice(QSocketDevice::Datagram);
}else{
connectSocket = new QSocketDevice(QSocketDevice::Stream);
connectSocket->setBlocking(false);
socketWriteNotifier = new QSocketNotifier(connectSocket->socket(),
QSocketNotifier::Write,0,”writeNotifier”);
QObject::connect(socketWriteNotifier,SIGNAL(activated(int)),SLOT(slotWriteReady(int)));
socketWriteNotifier->setEnabled(false);
}
socketReadNotifier = new QSocketNotifier(connectSocket->socket(),
QSocketNotifier::Read,0,”SocketNotifier”);
QObject::connect(socketReadNotifier,SIGNAL(activated(int)),SLOT(slotReceiveReady(int)));
if(connectionType == TCP)
socketReadNotifier->setEnabled(false);
}
connectionStatus = Init;
}
void EvaSocket::closeConnection()
{
if(connectSocket->isOpen()) connectSocket->close();
connectionStatus = None;
receivedLength = 0;
}
void EvaSocket::startConnecting()
{
if(connectionStatus != Init) {
emit exceptionEvent(connectionStatus);
return;
}
connectionStatus = Connecting;
if(connectionType == TCP){
if(!connectSocket->connect(server, serverPort)){
fprintf(stderr,”connecting server failed\nError type: “);
connectionStatus = Failed;
switch(connectSocket->error()){
case QSocketDevice::NoError:
fprintf(stderr,”NoError\n”);
break;
case QSocketDevice::AlreadyBound:
fprintf(stderr,”AlreadyBound\n”);
break;
case QSocketDevice::Inaccessible:
fprintf(stderr,”Inaccessible\n”);
break;
case QSocketDevice::NoResources:
fprintf(stderr,”NoResources\n”);
break;
case QSocketDevice::InternalError:
fprintf(stderr,”InternalError\n”);
break;
case QSocketDevice::Impossible:
fprintf(stderr,”Impossible\n”);
break;
case QSocketDevice::NoFiles:
fprintf(stderr,”NoFiles\n”);
break;
case QSocketDevice::ConnectionRefused:
fprintf(stderr,”ConnectionRefused\n”);
break;
case QSocketDevice::NetworkFailure:
fprintf(stderr,”NetworkFailure\n”);
break;
case QSocketDevice::UnknownError:
fprintf(stderr,”UnknownError\n”);
break;
default:
printf(“not listed error\n”);
}
emit exceptionEvent(connectionStatus);
return;
}
}
if(socketReadNotifier) socketReadNotifier->setEnabled(true);
if(connectionType == TCP && socketWriteNotifier) {
socketWriteNotifier->setEnabled(true);
}else{
connectionStatus = Ready;
emit isReady();
}
}
bool EvaSocket::write(const char *buf, const int len)
{
if(connectionStatus != Ready || !buf ) return false;
if(!connectSocket->isValid()){
if(connectionType == TCP && socketReadNotifier && socketWriteNotifier){
socketReadNotifier->setEnabled(false);
socketWriteNotifier->setEnabled(false);
}
emit exceptionEvent(Failed);
return false;
}
QMutex mutex; //写之前,锁一下?锁什么?
mutex.lock();
int BytesSent = 0;
if(socketWriteNotifier) socketWriteNotifier->setEnabled(false);
if(connectionType == UDP){
BytesSent =connectSocket->writeBlock(buf, len, server, serverPort);
}else{
int bytes = 0;
int times = 0;
// printf(“—++++++++– EvaSocket::write — BytesSent:%d, len: %d\n”, BytesSent, len);
while(BytesSent < len){
bytes =connectSocket->writeBlock(buf + BytesSent, len – BytesSent);
if(bytes == -1) {
printf(“EvaSocket::write retry :%d\n”, times);
if(!connectSocket->error()){
if(times>20){
fprintf(stderr, “EvaSocket::write — error : retried %d times\n”, times);
mutex.unlock();
return false;
}
usleep(10000);
//qApp->processEvents();
times++;
continue;
}else
break;
}
BytesSent += bytes;
// while( connectionStatus != WriteReady && BytesSent < len ){
// qApp->processEvents();
// usleep(10 * 1000);
// if(!connectSocket->isValid()){
// connectionStatus = oldStatus;
// mutex.unlock();
// return false;
// }
// }
// printf(” — EvaSocket::write — bytes:%d, len: %d\n”, bytes, len);
}
// printf(” EvaSocket::write — BytesSent:%d, len: %d\n”, BytesSent, len);
}
mutex.unlock();
if(len != BytesSent){
printf(“EvaSocket::write — error code: %d\n”, connectSocket->error());
return false;
}
return true;
}
bool EvaSocket::read(char *buf, int len)
{
if(connectionStatus != Ready || receivedLength != len || !buf ){
printf(“EvaSocket::read — receivedLength: %d, len: %d\n”, receivedLength, len);
return false;
}
memcpy(buf, receivedBuffer, receivedLength);
if(socketReadNotifier) socketReadNotifier->setEnabled(true);
return true;
}
void EvaSocket::setWriteNotifierEnabled( bool enabled )
{
if(socketWriteNotifier) socketWriteNotifier->setEnabled(enabled);
}
void EvaSocket::slotWriteReady(int /*socket */)
{
if(socketWriteNotifier) socketWriteNotifier->setEnabled(false);
if(connectionStatus == Connecting){
connectionStatus = Ready;
emit isReady();
} else{
emit writeReady();
}
}
void EvaSocket::slotReceiveReady(int /*socket*/)
{
if( (socketReadNotifier->type() != QSocketNotifier::Read) || (!connectSocket->isValid()) ){
socketReadNotifier->setEnabled(false);
printf(“EvaSocket::slotReceiveReady — socket not valid or notifier not set to Read \n”);
emit exceptionEvent(Failed);
return;
}
int ByteCount = 0;
ByteCount = connectSocket->bytesAvailable();
if(receivedBuffer!=NULL) delete receivedBuffer;
receivedBuffer = new char[ByteCount * 2];
//read都不锁,write锁的什么
receivedLength = connectSocket->readBlock(receivedBuffer,ByteCount*2);
if(!receivedLength){
printf(“EvaSocket::slotReceiveReady — connection closed due to ZERO byte\n”);
socketReadNotifier->setEnabled(false);//不停的开关这个通知
emit exceptionEvent(Failed);
return;
}
if(receivedLength == -1){
printf(“EvaSocket::slotReceiveReady — readBlock return -1\n”);
emit exceptionEvent(Failed);
return;
}
if(socketReadNotifier) socketReadNotifier->setEnabled(false);
emit receivedData(receivedLength);
if(receivedLength != ByteCount)
printf(“EvaSocket::slotReceiveReady — bytesAvailable() might not be accurate.\n”);
}
/* =========================================================== */
EvaHttpProxy::EvaHttpProxy(const QHostAddress &proxyHost, const short proxyPort, const QString username, const QString password)
: EvaSocket(proxyHost, proxyPort, EvaSocket::TCP),
status(Proxy_None),
destinationAddress(“”),
base64AuthParam(“”),
readBuffer(NULL)
{
if(username!=QString::null && password!= QString::null){
setAuthParameter(username, password);
}
QObject::connect(this, SIGNAL(isReady()), SLOT(tcpReady()));
QObject::connect(this, SIGNAL(writeReady()), SLOT(slotWriteReady()));
QObject::connect(this, SIGNAL(receivedData(int)), SLOT(parseData(int)));
QObject::connect(this, SIGNAL(exceptionEvent(int)), SIGNAL(socketException(int)));
}
void EvaHttpProxy::setDestinationServer(const QString &server, const int port) // server could be IP or URL
{
destinationAddress = server + ‘:’ + QString::number(port);// qq http proxy server port: 443,改成规定的格式
status = Proxy_None;
}
void EvaHttpProxy::setAuthParameter(const QString &username, const QString &password)
{
QCString para = (username + ‘:’ + password).local8Bit(); //规定的格式,QString?qt帮助里看不到这个类
base64AuthParam = QCodecs::base64Encode(para);//这是个什么code?QTextCodec?
status = Proxy_None;
}
bool EvaHttpProxy::doInitConnecting()
{
if(getStatus() != EvaSocket::Ready) return false;
if(destinationAddress == “”) return false;
//这个是关键的格式,哪里知道的
sentBuffer = “CONNECT ” + destinationAddress.local8Bit() + ” HTTP/1.1\r\n” +
“Accept: */*\r\n” + “Content-Type: text/html\r\nProxy-Connection: Keep-Alive\r\n” +
“Content-length: 0\r\n\r\n”;
status = Proxy_Connecting;
return write(sentBuffer.data(), sentBuffer.length());
}
bool EvaHttpProxy::doAuthConnecting()
{
if(getStatus() != EvaSocket::Ready) return false;
if(destinationAddress == “”) return false;
if(base64AuthParam == “”) return false;
sentBuffer = “CONNECT ” + destinationAddress.local8Bit() + ” HTTP/1.1\r\n” +
“Proxy-Authorization: Basic ” + base64AuthParam + “\r\n” +
“Accept: */*\r\nContent-Type: text/html\r\nProxy-Connection: Keep-Alive\r\n” +
“Content-length: 0\r\n\r\n”;
status = Proxy_Connecting;
return write(sentBuffer.data(), sentBuffer.length());
}
void EvaHttpProxy::tcpReady()
{
printf(“EvaHttpProxy::tcpReady — TCP connection ready\n”);
if(destinationAddress == “”) {
emit proxyEvent(Proxy_TCP_Ready);
return;
}
if(base64AuthParam != “”)
doAuthConnecting();
else
doInitConnecting();
}
void EvaHttpProxy::slotWriteReady()
{
if ( status == Proxy_Ready )
emit proxyWriteReady();
}
void EvaHttpProxy::parseData(int len)
{
if(readBuffer!=NULL) free(readBuffer);
readBuffer = (char *)malloc((len+1) * sizeof(char));
if(!read(readBuffer, len)){
emit proxyEvent(Proxy_Read_Error);
return;
}
readBuffer[len]=0x00;
QString replyBuffer(readBuffer);
if(replyBuffer.startsWith(“HTTP/1.”)){ // this is for RedHat 9, the old Qt dosen’t support QString::startsWith(const QString &str, bool cs) const
int replyCode = replyBuffer.mid(9, 3).toInt();
fprintf(stderr, “Proxy Server Reply Code: %d\n”,replyCode);
switch(replyCode){
case 200:
status = Proxy_Ready;
emit proxyEvent(Proxy_Ready);
break;
case 407:
status = Proxy_Need_Auth;
emit proxyEvent(Proxy_Need_Auth);
break;
case 501: // “Not Support”
case 502: // “Proxy Error”
default:
status = Proxy_Error;
emit proxyEvent(Proxy_Error);
break;
}
return;
}
if(status == Proxy_Ready)
dataArrived(len);
}
越看问题越多啊,难道这些用的是qt很早之前的版本,很多类,根本找不到。应该是。
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evaconnecter.h”
#include “evahtmlparser.h”
#include “evanetwork.h”
#include “evapacketmanager.h”
#include “evaresource.h”
#include “evasetting.h”
#include “evasocket.h”
#include “evauser.h”
#include “evausersetting.h”
#include “evaservers.h”
#include “qmdcodec.h”
#include “evaqtutil.h”
#include “evapicmanager.h”
#include “evauhmanager.h”
#include “regiongrabber.h”
#include “filetrans/evafilemanager.h”
封了这么多类,c++,就是包来报去,一个文件里面,没啥具体的实现,包了底层,加了几个函数,浪费这么多代码行。
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef EVARESOURCE_H
#define EVARESOURCE_H
#include <qobject.h>
#include <qfile.h>
#include <qmap.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qmovie.h> //这个movie播放gif的。。。
#include <qsize.h>
#ifndef MaxFaceNumber //最大 脸,头像? 数目
#define MaxFaceNumber 101
#endif
class EvaSetting;
class EvaServers;
class QHttp; //这里又来个http
class EvaImageResource : public QObject
{
Q_OBJECT
public:
EvaImageResource();
~EvaImageResource();
const QString getFacePath() const;
const QString getIconPath() ;
const QString getSmileyPath() const;
const QString getQQShowPath() const;
const int getFaceID(const int fileIndex) const ;
const int getFaceFileIndex(const int faceId);
QPixmap *getFace(const int fileIndex, const bool on = true);
QPixmap *getIcon(QString name);
const QString getIconFullPath(QString name);
const QMovie *getSmiley(const int fileIndex); //gif的动画
const QMovie *getLoginMovie();
const bool loadImage();
const QString &getImageRootPath() const { return imageRoot; }
void setImageRootPath( QString &path) { imageRoot = path; }
const QString getThemePath() const { return themePath; }
void setThemePath( const QString &path) { themePath = path; }
QPixmap *getQQShow(const int id);
void setUserHeadImage(QMap<int, QImage> imageOnList, QMap<int, QImage> imageOffList);
void addUserHeadImage(const int id, QImage imgOn, QImage imgOff);
QPixmap *getUserHeadPixmap(const int id, bool isGrayscale = false);
signals:
void qqShowReady(const int);
public slots:
void requestQQShow(const int id);
private:
bool loadFace();
bool loadIcon();
bool loadSmiley();
QMap<QString, QPixmap> faceList;
QMap<QString, QPixmap> iconList;
QMap<QString, QString> iconFileNameMap;
QMap<QString, QMovie> smileyList;
QMap<int, QPixmap> imgOnList;
QMap<int, QPixmap> imgOffList;
QMovie loginMng;
int faceId[MaxFaceNumber]; // store faceID, index is the fileID
QString imageRoot;
QString themePath;
bool isDownloadingQQShow;
int downloadID;
QFile qqshowFile;
QString qqshowFilename;
QHttp *http;
private slots:
void slotQQShowDone(bool error);
};
//又是声音,又是图像,不错。
class EvaSoundResource
{
public:
EvaSoundResource();
~EvaSoundResource(){}
//const bool loadSound(){ return false; }
void playNewMessage();
void playSysMessage();
void playOnlineSound();
void setSoundDir(const QString &path) { soundRoot = path; }
const QString &getSoundDir() const { return soundRoot; }
private:
void playSound(const QString &filename);
QString soundRoot;
};
//把所有的资源,初始化
class EvaGlobal
{
public:
EvaGlobal();
virtual ~EvaGlobal();
static QString &getDirPath();
const bool loadImage();
//const bool loadSound();
const bool loadEvaSetting();
EvaImageResource *getImageResource() { return imgResource;}
EvaSoundResource *getSoundResource() { return sndResource;}
EvaSetting *getEvaSetting() { return system; }
EvaServers *getEvaServers() { return servers; }
const QSize &getFaceSize() const { return faceSize; }
void setFaceSize( const QSize size) { faceSize = size; }
private:
void initialize();
void initImage();
void initSound();
void initEvaSetting();
void initServers();
static QString dirPath;
EvaSetting *system;
EvaServers *servers;
EvaImageResource *imgResource;
EvaSoundResource *sndResource;
QSize faceSize;
};
#endif
/***************************************************************************
* Copyright (C) 2004 by yunfan *
* yunfan_zg@163.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include “evaresource.h”
#include “evasetting.h”
#include “evaservers.h”
#include <stdlib.h>
#include <qapplication.h>
#include <qhttp.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qdatastream.h>
#include <kaudioplayer.h> //哦。这里又用的谁的库?k开头kDE?
#include <kglobal.h>
#include <kstandarddirs.h>
EvaImageResource::EvaImageResource()
{
//imageRoot = qApp->applicationDirPath() + “/images”;
themePath = “”;
imageRoot = EvaGlobal::getDirPath() + “/image”;
isDownloadingQQShow = false;
http = new QHttp();
connect ( http, SIGNAL(done(bool)), SLOT(slotQQShowDone(bool))); //done什么了?
}
EvaImageResource::~EvaImageResource()
{
}
const QString EvaImageResource::getFacePath() const
{
return imageRoot + “/face”;
}
const QString EvaImageResource::getIconPath()
{
if(themePath == “” )
themePath = imageRoot + “/theme”;
return themePath;
}
const QString EvaImageResource::getSmileyPath() const
{
return imageRoot + “/smiley”;
}
const int EvaImageResource::getFaceID(const int fileIndex) const
{
if(fileIndex<=0 || fileIndex> MaxFaceNumber)
return faceId[0];
return faceId[fileIndex-1];
}
const int EvaImageResource::getFaceFileIndex(const int faceId)
{
int index = (faceId<0)?1:faceId/3 + 1;
if(index<0 || index>101) index = 101;
return index;
}
QPixmap *EvaImageResource::getFace(const int fileIndex, const bool on)
{
QString key = QString::number((fileIndex>0)?fileIndex:1);
if(!on) key+=”off”;
QMap<QString, QPixmap>::Iterator iter = faceList.find(key);
if(iter== faceList.end()) return NULL;
return &(iter.data());
}
QPixmap *EvaImageResource::getIcon(QString name)
{
QMap<QString, QPixmap>::Iterator iter = iconList.find(name);
if(iter== iconList.end()) return NULL;
return &(iter.data());
}
const QString EvaImageResource::getIconFullPath(QString name)
{
QMap<QString, QString>::Iterator iter = iconFileNameMap.find(name);
if(iter== iconFileNameMap.end()) return “”;
return getIconPath() + “/” + iter.data();
}
const QMovie *EvaImageResource::getSmiley(const int fileIndex)
{
QString key = QString::number(fileIndex);
QMap<QString, QMovie>::Iterator iter = smileyList.find(key);
if(iter== smileyList.end()) return NULL;
return &(iter.data());
}
const QMovie *EvaImageResource::getLoginMovie()
{
return &loginMng;
}
const bool EvaImageResource::loadImage()
{
return (loadFace() && loadIcon() && loadSmiley());
}
bool EvaImageResource::loadFace()
{
QString path = getFacePath();
QFile file( path + “/face.theme”);
if(!file.open(IO_ReadOnly)){
return false;
}
QTextStream stream(&file);
QString line, imagePath;
QStringList lineList;
while(!stream.atEnd()){
line = stream.readLine().stripWhiteSpace();
lineList = QStringList::split(“:”, line);
if(lineList.size() != 2)
continue;
lineList[0].stripWhiteSpace();
imagePath = path + “/” + lineList[1].stripWhiteSpace();
QPixmap img(imagePath);
if(!img.isNull())
faceList[lineList[0]] = img;
}
file.close();
for(int i = 0; i < MaxFaceNumber ; i++) {
faceId[i] = i * 3 + 1;
}
return true;
}
bool EvaImageResource::loadIcon()
{
QString path = getIconPath() + “/eva.theme”;
QDir d;
if(!d.exists(path)){
themePath = “”; // if theme not exist, load default one
path = getIconPath() + “/eva.theme”;
}
QFile file( path);
if(!file.open(IO_ReadOnly)){
return false;
}
QTextStream stream(&file);
QString line, imagePath;
QStringList lineList;
while(!stream.atEnd()){
line = stream.readLine().stripWhiteSpace();
lineList = QStringList::split(“:”, line);
if(lineList.size() != 2)
continue;
lineList[0].stripWhiteSpace();
imagePath = getIconPath() + “/” + lineList[1].stripWhiteSpace();
if(lineList[0] == “LOGIN_MNG”){
loginMng = QMovie(imagePath);
continue;
}
QPixmap img(imagePath);
if(!img.isNull()){
iconList[lineList[0]] = img;
iconFileNameMap[lineList[0]] = lineList[1].stripWhiteSpace();
}
}
file.close();
return true;
}
bool EvaImageResource::loadSmiley()
{
QString path = getSmileyPath();
QFile file( path + “/smiley.theme”);
if(!file.open(IO_ReadOnly)){
return false;
}
QTextStream stream(&file);
QString line, imagePath;
QStringList lineList;
while(!stream.atEnd()){
line = stream.readLine().stripWhiteSpace();
lineList = QStringList::split(“:”, line);
if(lineList.size() != 2)
continue;
lineList[0].stripWhiteSpace();
imagePath = path + “/” + lineList[1].stripWhiteSpace();
QMovie m(imagePath);
if(!m.isNull())
smileyList[lineList[0]] = m;
}
file.close();
return true;
}
const QString EvaImageResource::getQQShowPath() const
{
QString evaHome = QDir::homeDirPath() + “/.eva”;//隐藏文件。
QDir d;
if(!d.exists(evaHome)){
return “”;
}
if(!d.cd(evaHome)) return “”;
if(!d.exists(“QQShow”)){
if(!d.mkdir(“QQShow”, false))return “”;
}
return evaHome + “/QQShow”;
}
QPixmap *EvaImageResource::getQQShow(const int id)
{
QString path = getQQShowPath() +”/”+ QString::number(id) + “.gif”;
QDir d;
if(d.exists(path))
return new QPixmap(path);
return NULL;
}
void EvaImageResource::requestQQShow(const int id)
{
if(isDownloadingQQShow) return;
QString path = getQQShowPath();
if(path == “”) return;
qqshowFile.setName(path +”/”+ QString::number(id) + “.gif” );
if(qqshowFile.exists()){
qqshowFile.remove();
}
if ( !qqshowFile.open( IO_WriteOnly ) ) {
printf(“cannot create the image\n”);
return;
}
http->setHost( “qqshow-user.tencent.com” ); //哦,从网站下载下来的。这个网址,连接,永远不变吗?
int picNum = rand()*100;
QString remoteFile = “/”+QString::number(id) + “/10/00/” + QString::number(picNum) +”.gif”;
downloadID = id;
http->get( remoteFile, &qqshowFile );
}
void EvaImageResource::slotQQShowDone( bool error )
{
qqshowFile.close();
if(error){
printf(“download error: %d\n”,error);
isDownloadingQQShow = false;
return;
}
isDownloadingQQShow = false;
emit qqShowReady(downloadID);
}
void EvaImageResource::setUserHeadImage(QMap<int, QImage> imageOnList, QMap<int, QImage> imageOffList)
{
QMap<int, QImage>::Iterator it = imageOnList.begin();
while(it != imageOnList.end()){
imgOnList[it.key()] = QPixmap(it.data());
++it;
}
it = imageOffList.begin();
while(it != imageOffList.end()){
imgOffList[it.key()] = QPixmap(it.data());
++it;
}
}
QPixmap *EvaImageResource::getUserHeadPixmap(const int id, bool isGrayscale)
{
QPixmap * result;
QMap<int, QPixmap>::Iterator it;
if(isGrayscale){
it = imgOffList.find(id);
if(it == imgOffList.end())
result = NULL;
else
result = &(it.data());
}else{
it = imgOnList.find(id);
if(it == imgOnList.end()){
result = NULL;
}else
result = &(it.data());
}
return result;
}
void EvaImageResource::addUserHeadImage(const int id, QImage imgOn, QImage imgOff)
{
imgOnList[id] = QPixmap(imgOn);
imgOffList[id] = QPixmap(imgOff);
}
/* ———————————————————————————————- */
EvaSoundResource::EvaSoundResource()
{
soundRoot = EvaGlobal::getDirPath() + “/sound”;
}
void EvaSoundResource::playNewMessage()
{
playSound(“msg.wav”);
}
void EvaSoundResource::playSysMessage()
{
playSound(“system.wav”);
}
void EvaSoundResource::playOnlineSound()
{
playSound(“online.wav”);
}
void EvaSoundResource::playSound(const QString &filename)
{
QString absPath = soundRoot + “/” + filename;
QDir d;
if(!d.exists(absPath)){
absPath = EvaGlobal::getDirPath() + “/sound” + “/” + filename;
}
if(!d.exists(absPath))return;
KAudioPlayer snd(absPath);
snd.play();
}
/* ———————————————————————————————- */
QString EvaGlobal::dirPath = “~/eva”;
EvaGlobal::EvaGlobal()
{
initialize();
}
EvaGlobal::~EvaGlobal()
{
delete imgResource;
delete sndResource;
delete system;
delete servers;
}
QString &EvaGlobal::getDirPath()
{
return dirPath;
}
const bool EvaGlobal::loadImage()
{
if(!imgResource) return false;
return imgResource->loadImage();
}
/*
const bool EvaGlobal::loadSound()
{
if(!sndResource) return false;
return sndResource->loadSound();
}*/
const bool EvaGlobal::loadEvaSetting()
{
if(!system) return false;
return system->loadSetting();
}
void EvaGlobal::initialize()
{
dirPath = KGlobal::dirs()->findResource(“data”, QString::fromLatin1(“eva/servers”));
// QStringList dirs = KGlobal::dirs()->findDirs(“data”, QString::fromLatin1(“eva”));
// for(uint i=0; i<dirs.size(); i++){
// //printf(“dir %i:%s\n”, i, dirs[i].ascii());
// //dirPath = dirs[0];
// break;
// }
if(dirPath == QString::null){
QFileInfo fi;
fi.setFile(QString(getenv(“_”)));
dirPath = fi.dirPath(true);
}else
dirPath = dirPath.left(dirPath.length() – strlen(“/servers”));
//printf(“found data path: %s\n”, dirPath.ascii());
initImage();
initSound();
initEvaSetting();
initServers();
}
void EvaGlobal::initImage()
{
imgResource = new EvaImageResource();
}
void EvaGlobal::initSound()
{
sndResource = new EvaSoundResource();
}
void EvaGlobal::initEvaSetting()
{
system = new EvaSetting();
}
void EvaGlobal::initServers( )
{
servers = new EvaServers(dirPath);
}
还是只是调用一堆接口的文件。