📄 qabstractsocket.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtNetwork module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************///#define QABSTRACTSOCKET_DEBUG/*! \class QAbstractSocket \brief The QAbstractSocket class provides the base functionality common to all socket types. \reentrant \ingroup io \module network QAbstractSocket is the base class for QTcpSocket and QUdpSocket and contains all common functionality of these two classes. If you need a socket, you have two options: \list \i Instantiate QTcpSocket or QUdpSocket. \i Create a native socket descriptor, instantiate QAbstractSocket, and call setSocketDescriptor() to wrap the native socket. \endlist TCP (Transmission Control Protocol) is a reliable, stream-oriented, connection-oriented transport protocol. UDP (User Datagram Protocol) is an unreliable, datagram-oriented, connectionless protocol. In practice, this means that TCP is better suited for continuous transmission of data, whereas the more lightweight UDP can be used when reliability isn't important. QAbstractSocket's API unifies most of the differences between the two protocols. For example, although UDP is connectionless, connectToHost() establishes a virtual connection for UDP sockets, enabling you to use QAbstractSocket in more or less the same way regardless of the underlying protocol. Internally, QAbstractSocket remembers the address and port passed to connectToHost(), and functions like read() and write() use these values. At any time, QAbstractSocket has a state (returned by state()). The initial state is UnconnectedState. After calling connectToHost(), the socket first enters HostLookupState. If the host is found, QAbstractSocket enters ConnectingState and emits the hostFound() signal. When the connection has been established, it enters ConnectedState and emits connected(). If an error occurs at any stage, error() is emitted. Whenever the state changes, stateChanged() is emitted. For convenience, isValid() returns true if the socket is ready for reading and writing, but note that the socket's state must be ConnectedState before reading and writing can occur. Read or write data by calling read() or write(), or use the convenience functions readLine() and readAll(). QAbstractSocket also inherits getChar(), putChar(), and ungetChar() from QIODevice, which work on single bytes. For every chunk of data that has been written to the socket, the bytesWritten() signal is emitted. The readyRead() signal is emitted every time a new chunk of data has arrived. bytesAvailable() then returns the number of bytes that are available for reading. Typically, you would connect the readyRead() signal to a slot and read all available data there. If you don't read all the data at once, the remaining data will still be available later, and any new incoming data will be appended to QAbstractSocket's internal read buffer. To limit the size of the read buffer, call setReadBufferSize(). To close the socket, call disconnectFromHost(). QAbstractSocket enters QAbstractSocket::ClosingState, then emits closing(). After all pending data has been written to the socket, QAbstractSocket actually closes the socket, enters QAbstractSocket::ClosedState, and emits disconnected(). If you want to abort a connection immediately, discarding all pending data, call abort() instead. If the remote host closes the connection, QAbstractSocket will emit error(QAbstractSocket::RemoteHostClosedError), during which the socket state will still be ConnectedState, and then the disconnected() signal will be emitted. The port and address of the connected peer is fetched by calling peerPort() and peerAddress(). peerName() returns the host name of the peer, as passed to connectToHost(). localPort() and localAddress() return the port and address of the local socket. QAbstractSocket provides a set of functions that suspend the calling thread until certain signals are emitted. These functions can be used to implement blocking sockets: \list \o waitForConnected() blocks until a connection has been established. \o waitForReadyRead() blocks until new data is available for reading. \o waitForBytesWritten() blocks until one payload of data has been written to the socket. \o waitForDisconnected() blocks until the connection has closed. \endlist We show an example: \quotefromfile snippets/network/tcpwait.cpp \skipto numRead \printuntil /^\s\s\s\s\}/ If \l{QIODevice::}{waitForReadyRead()} returns false, the connection has been closed or an error has occurred. Programming with a blocking socket is radically different from programming with a non-blocking socket. A blocking socket doesn't require an event loop and typically leads to simpler code. However, in a GUI application, blocking sockets should only be used in non-GUI threads, to avoid freezing the user interface. See the \l network/fortuneclient and \l network/blockingfortuneclient examples for an overview of both approaches. QAbstractSocket can be used with QTextStream and QDataStream's stream operators (operator<<() and operator>>()). There is one issue to be aware of, though: You must make sure that enough data is available before attempting to read it using operator>>(). \sa QFtp, QHttp, QTcpServer*//*! \fn void QAbstractSocket::hostFound() This signal is emitted after connectToHost() has been called and the host lookup has succeeded. \sa connected()*//*! \fn void QAbstractSocket::connected() This signal is emitted after connectToHost() has been called and a connection has been successfully established. \sa connectToHost(), disconnected()*//*! \fn void QAbstractSocket::disconnected() This signal is emitted when the socket has been disconnected. \sa connectToHost(), disconnectFromHost(), abort()*//*! \fn void QAbstractSocket::error(QAbstractSocket::SocketError socketError) This signal is emitted after an error occurred. The \a socketError parameter describes the type of error that occurred. QAbstractSocket::SocketError is not a registered metatype, so for queued connections, you will have to register it with Q_REGISTER_METATYPE. \sa error(), errorString()*//*! \fn void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState) This signal is emitted whenever QAbstractSocket's state changes. The \a socketState parameter is the new state. QAbstractSocket::SocketState is not a registered metatype, so for queued connections, you will have to register it with Q_REGISTER_METATYPE. \sa state()*//*! \fn void QAbstractSocket::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) \since 4.3 This signal can be emitted when a \a proxy that requires authentication is used. The \a authenticator object can then be filled in with the required details to allow authentication and continue the connection. \note It is not possible to use a QueuedConnection to connect to this signal, as the connection will fail if the authenticator has not been filled in with new information when the signal returns. \sa QAuthenticator, QNetworkProxy*//*! \enum QAbstractSocket::NetworkLayerProtocol This enum describes the network layer protocol values used in Qt. \value IPv4Protocol IPv4 \value IPv6Protocol IPv6 \value UnknownNetworkLayerProtocol Other than IPv4 and IPv6 \sa QHostAddress::protocol()*//*! \enum QAbstractSocket::SocketType This enum describes the transport layer protocol. \value TcpSocket TCP \value UdpSocket UDP \value UnknownSocketType Other than TCP and UDP \sa QAbstractSocket::socketType()*//*! \enum QAbstractSocket::SocketError This enum describes the socket errors that can occur. \value ConnectionRefusedError The connection was refused by the peer (or timed out). \value RemoteHostClosedError The remote host closed the connection. Note that the client socket (i.e., this socket) will be closed after the remote close notification has been sent. \value HostNotFoundError The host address was not found. \value SocketAccessError The socket operation failed because the application lacked the required privileges. \value SocketResourceError The local system ran out of resources (e.g., too many sockets). \value SocketTimeoutError The socket operation timed out. \value DatagramTooLargeError The datagram was larger than the operating system's limit (which can be as low as 8192 bytes). \value NetworkError An error occurred with the network (e.g., the network cable was accidentally plugged out). \value AddressInUseError The address specified to QUdpSocket::bind() is already in use and was set to be exclusive. \value SocketAddressNotAvailableError The address specified to QUdpSocket::bind() does not belong to the host. \value UnsupportedSocketOperationError The requested socket operation is not supported by the local operating system (e.g., lack of IPv6 support). \value ProxyAuthenticationRequiredError The socket is using a proxy, and the proxy requires authentication. \value UnknownSocketError An unidentified error occurred. \omitvalue UnfinishedSocketOperationError Used by QAbstractSocketEngine only, this error indicates that the last operation could not complete. \sa QAbstractSocket::error()*//*! \enum QAbstractSocket::SocketState This enum describes the different states in which a socket can be. \value UnconnectedState The socket is not connected. \value HostLookupState The socket is performing a host name lookup. \value ConnectingState The socket has started establishing a connection. \value ConnectedState A connection is established. \value BoundState The socket is bound to an address and port (for servers). \value ClosingState The socket is about to close (data may still be waiting to be written). \value ListeningState For internal use only. \omitvalue Idle \omitvalue HostLookup \omitvalue Connecting \omitvalue Connected \omitvalue Closing \omitvalue Connection \sa QAbstractSocket::state()*/#include "qabstractsocket.h"#include "qabstractsocket_p.h"#include <qabstracteventdispatcher.h>#include <qdatetime.h>#include <qhostaddress.h>#include <qhostinfo.h>#include <qmetaobject.h>#include <qpointer.h>#include <qtimer.h>#ifndef QT_NO_OPENSSL#include <QtNetwork/qsslsocket.h>#endif#include <private/qthread_p.h>#ifdef QABSTRACTSOCKET_DEBUG#include <qdebug.h>#endif#include <time.h>#define Q_CHECK_SOCKETENGINE(returnValue) do { \ if (!d->socketEngine) { \ return returnValue; \ } } while (0)#define QABSTRACTSOCKET_BUFFERSIZE 32768#define QT_CONNECT_TIMEOUT 30000#define QT_TRANSFER_TIMEOUT 120000#if defined QABSTRACTSOCKET_DEBUG#include <qstring.h>#include <ctype.h>/* Returns a human readable representation of the first \a len characters in \a data.*/static QByteArray qt_prettyDebug(const char *data, int len, int maxLength){ if (!data) return "(null)"; QByteArray out; for (int i = 0; i < len; ++i) { char c = data[i]; if (isprint(int(uchar(c)))) { out += c; } else switch (c) { case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: QString tmp; tmp.sprintf("\\%o", c); out += tmp.toLatin1(); } } if (len < maxLength) out += "..."; return out;}#endif/*! \internal Constructs a QAbstractSocketPrivate. Initializes all members.*/QAbstractSocketPrivate::QAbstractSocketPrivate() : readSocketNotifierCalled(false), readSocketNotifierState(false), readSocketNotifierStateSet(false), emittedReadyRead(false), emittedBytesWritten(false), closeCalled(false), port(0), localPort(0), peerPort(0), socketEngine(0), cachedSocketDescriptor(-1), readBufferMaxSize(0), readBuffer(QABSTRACTSOCKET_BUFFERSIZE), writeBuffer(QABSTRACTSOCKET_BUFFERSIZE),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -