/*************************************************************************** * Copyright (C) 2004 by yunfan * * [email protected] * * * * 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 * * [email protected] * * * * 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很早之前的版本,很多类,根本找不到。应该是。