📄 q3socket.cpp
字号:
}#endif#if defined(QT_CHECK_STATE) if ( !isOpen() ) { qWarning( "Q3Socket::writeBlock: Socket is not open" ); return -1; }#endif#if defined(QT_CHECK_STATE) if ( d->state == Closing ) { qWarning( "Q3Socket::writeBlock: Cannot write, socket is closing" ); }#endif if ( len == 0 || d->state == Closing || d->state == Idle ) return 0; QByteArray *a = d->wba.last(); // next bit is sensitive. if we're writing really small chunks, // try to buffer up since system calls are expensive, and nagle's // algorithm is even more expensive. but if anything even // remotely large is being written, try to issue a write at once. bool writeNow = ( d->wsize + len >= 1400 || len > 512 ); if ( a && a->size() + len < 128 ) { // small buffer, resize int i = a->size(); a->resize( i+len ); memcpy( a->data()+i, data, len ); } else { // append new buffer a = new QByteArray( len ); memcpy( a->data(), data, len ); d->wba.append( a ); } d->wsize += len; if ( writeNow ) flush(); else if ( d->wsn ) d->wsn->setEnabled( true );#if defined(Q3SOCKET_DEBUG) qDebug( "Q3Socket (%s): writeBlock %d bytes", name(), (int)len );#endif return len;}/*! Reads a single byte/character from the internal read buffer. Returns the byte/character read, or -1 if there is nothing to be read. \sa bytesAvailable(), putch()*/int Q3Socket::getch(){ if ( isOpen() && d->rba.size() > 0 ) { uchar c; d->rba.consumeBytes( 1, (char*)&c ); // After we read data from our internal buffer, if we use the // setReadBufferSize() to limit our buffer, we might now be able to // read more data in our buffer. So enable the read socket notifier, // but do this only if we are not in a slot connected to the // readyRead() signal since this might cause a bad recursive behavior. // We can test for this condition by looking at the // sn_read_alreadyCalled flag. if ( d->rsn && Q3SocketPrivate::sn_read_alreadyCalled.findRef(this) == -1 ) d->rsn->setEnabled( true ); return c; } return -1;}/*! Writes the character \a ch to the output buffer. Returns \a ch, or -1 if an error occurred. \sa getch()*/int Q3Socket::putch( int ch ){ char buf[2]; buf[0] = ch; return writeBlock(buf, 1) == 1 ? ch : -1;}/*! This implementation of the virtual function QIODevice::ungetch() prepends the character \a ch to the read buffer so that the next read returns this character as the first character of the output.*/int Q3Socket::ungetch( int ch ){#if defined(QT_CHECK_STATE) if ( !isOpen() ) { qWarning( "Q3Socket::ungetch: Socket not open" ); return -1; }#endif return d->rba.ungetch( ch );}/*! Returns true if it's possible to read an entire line of text from this socket at this time; otherwise returns false. Note that if the peer closes the connection unexpectedly, this function returns false. This means that loops such as this won't work: \code while( !socket->canReadLine() ) // WRONG ; \endcode \sa readLine()*/bool Q3Socket::canReadLine() const{ if ( ((Q3Socket*)this)->d->rba.scanNewline( 0 ) ) return true; return ( bytesAvailable() > 0 && (((Q3Socket*)this)->d->rba.scanNewline( 0 ) || QIODevice::canReadLine()) );}/*! \internal Internal slot for handling socket read notifications. This function has can usually only be entered once (i.e. no recursive calls). If the argument \a force is true, the function is executed, but no readyRead() signals are emitted. This behaviour is useful for the waitForMore() function, so that it is possible to call waitForMore() in a slot connected to the readyRead() signal.*/void Q3Socket::sn_read( bool force ){ Q_LONG maxToRead = 0; if ( d->readBufferSize > 0 ) { maxToRead = d->readBufferSize - d->rba.size(); if ( maxToRead <= 0 ) { if ( d->rsn ) d->rsn->setEnabled( false ); return; } } // Use Q3SocketPrivate::sn_read_alreadyCalled to avoid recursive calls of // sn_read() (and as a result avoid emitting the readyRead() signal in a // slot for readyRead(), if you use bytesAvailable()). if ( !force && Q3SocketPrivate::sn_read_alreadyCalled.findRef(this) != -1 ) return; Q3SocketPrivate::sn_read_alreadyCalled.append( this ); char buf[4096]; Q_LONG nbytes = d->socket->bytesAvailable(); Q_LONG nread; QByteArray *a = 0; if ( state() == Connecting ) { if ( nbytes > 0 ) { tryConnection(); } else { // nothing to do, nothing to care about Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; } } if ( state() == Idle ) { Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; } if ( nbytes <= 0 ) { // connection closed? // On Windows this may happen when the connection is still open. // This happens when the system is heavily loaded and we have // read all the data on the socket before a new WSAAsyncSelect // event is processed. A new read operation would then block. // This code is also useful when Q3Socket is used without an // event loop. nread = d->socket->readBlock( buf, maxToRead ? QMIN((Q_LONG)sizeof(buf),maxToRead) : sizeof(buf) ); if ( nread == 0 ) { // really closed if ( !d->socket->isOpen() ) {#if defined(Q3SOCKET_DEBUG) qDebug( "Q3Socket (%s): sn_read: Connection closed", name() );#endif d->connectionClosed(); emit connectionClosed(); } Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; } else { if ( nread < 0 ) { if ( d->socket->error() == Q3SocketDevice::NoError ) { // all is fine Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; }#if defined(Q3SOCKET_DEBUG) qWarning( "Q3Socket::sn_read (%s): Close error", name() );#endif if ( d->rsn ) d->rsn->setEnabled( false ); emit error( ErrSocketRead ); Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; } a = new QByteArray( nread ); memcpy( a->data(), buf, nread ); } } else { // data to be read#if defined(Q3SOCKET_DEBUG) qDebug( "Q3Socket (%s): sn_read: %ld incoming bytes", name(), nbytes );#endif if ( nbytes > (int)sizeof(buf) ) { // big a = new QByteArray( nbytes ); nread = d->socket->readBlock( a->data(), maxToRead ? QMIN(nbytes,maxToRead) : nbytes ); } else { a = 0; nread = d->socket->readBlock( buf, maxToRead ? QMIN((Q_LONG)sizeof(buf),maxToRead) : sizeof(buf) ); if ( nread > 0 ) { // ##### could setRawData a = new QByteArray( nread ); memcpy( a->data(), buf, nread ); } } if ( nread == 0 ) {#if defined(Q3SOCKET_DEBUG) qDebug( "Q3Socket (%s): sn_read: Connection closed", name() );#endif // ### we should rather ask the socket device if it is closed d->connectionClosed(); emit connectionClosed(); Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); delete a; return; } else if ( nread < 0 ) { delete a; if ( d->socket->error() == Q3SocketDevice::NoError ) { // all is fine Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; }#if defined(QT_CHECK_RANGE) qWarning( "Q3Socket::sn_read: Read error" );#endif if ( d->rsn ) d->rsn->setEnabled( false ); emit error( ErrSocketRead ); Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this ); return; } if ( nread != (int)a->size() ) { // unexpected#if defined(CHECK_RANGE) && !defined(Q_OS_WIN32) qWarning( "Q3Socket::sn_read: Unexpected short read" );#endif a->resize( nread ); } } d->rba.append( a ); if ( !force ) { if ( d->rsn ) d->rsn->setEnabled( false ); emit readyRead(); if ( d->rsn ) d->rsn->setEnabled( true ); } Q3SocketPrivate::sn_read_alreadyCalled.removeRef( this );}/*! \internal Internal slot for handling socket write notifications.*/void Q3Socket::sn_write(){ if ( d->state == Connecting ) // connection established? tryConnection(); flush();}void Q3Socket::emitErrorConnectionRefused(){ emit error( ErrConnectionRefused );}void Q3Socket::tryConnection(){ if ( d->socket->connect( d->addr, d->port ) ) { d->state = Connected;#if defined(Q3SOCKET_DEBUG) qDebug( "Q3Socket (%s): sn_write: Got connection to %s", name(), peerName().ascii() );#endif if ( d->rsn ) d->rsn->setEnabled( true ); emit connected(); } else { d->state = Idle; QTimer::singleShot( 0, this, SLOT(emitErrorConnectionRefused()) ); return; }}/*! Returns the socket number, or -1 if there is no socket at the moment.*/int Q3Socket::socket() const{ if ( d->socket == 0 ) return -1; return d->socket->socket();}/*! Sets the socket to use \a socket and the state() to \c Connected. The socket must already be connected. This allows us to use the Q3Socket class as a wrapper for other socket types (e.g. Unix Domain Sockets).*/void Q3Socket::setSocket( int socket ){ setSocketIntern( socket ); d->state = Connection; d->rsn->setEnabled( true );}/*! Sets the socket to \a socket. This is used by both setSocket() and connectToHost() and can also be used on unconnected sockets.*/void Q3Socket::setSocketIntern( int socket ){ if ( state() != Idle ) { clearPendingData(); close(); } Q_ULONG oldBufferSize = d ? d->readBufferSize : 0; delete d; d = new Q3SocketPrivate; if (oldBufferSize) d->readBufferSize = oldBufferSize; if ( socket >= 0 ) { Q3SocketDevice *sd = new Q3SocketDevice( socket, Q3SocketDevice::Stream ); sd->setBlocking( false ); sd->setAddressReusable( true ); d->setSocketDevice( this, sd ); } d->state = Idle; // Initialize the IO device flags resetStatus(); open( IO_ReadWrite ); // hm... this is not very nice. d->host.clear(); d->port = 0;#ifndef QT_NO_DNS delete d->dns4; d->dns4 = 0; delete d->dns6; d->dns6 = 0;#endif}/*! Returns the host port number of this socket, in native byte order.*/Q_UINT16 Q3Socket::port() const{ if ( d->socket == 0 ) return 0; return d->socket->port();}/*! Returns the peer's host port number, normally as specified to the connectToHost() function. If none has been set, this function returns 0. Note that Qt always uses native byte order, i.e. 67 is 67 in Qt; there is no need to call htons().*/Q_UINT16 Q3Socket::peerPort() const{ if ( d->socket == 0 ) return 0; return d->socket->peerPort();}/*! Returns the host address of this socket. (This is normally the main IP address of the host, but can be e.g. 127.0.0.1 for connections to localhost.)*/QHostAddress Q3Socket::address() const{ if ( d->socket == 0 ) { QHostAddress tmp; return tmp; } return d->socket->address();}/*! Returns the address of the connected peer if the socket is in Connected state; otherwise an empty QHostAddress is returned.*/QHostAddress Q3Socket::peerAddress() const{ if ( d->socket == 0 ) { QHostAddress tmp; return tmp; } return d->socket->peerAddress();}/*! Returns the host name as specified to the connectToHost() function. An empty string is returned if none has been set.*/QString Q3Socket::peerName() const{ return d->host;}/*! Sets the size of the Q3Socket's internal read buffer to \a bufSize. Usually Q3Socket reads all data that is available from the operating system's socket. If the buffer size is limited to a certain size, this means that the Q3Socket class doesn't buffer more than this size of data. If the size of the read buffer is 0, the read buffer is unlimited and all incoming data is buffered. This is the default. If you read the data in the readyRead() signal, you shouldn't use this option since it might slow down your program unnecessary. This option is useful if you only need to read the data at certain points in time, like in a realtime streaming application. \sa readBufferSize()*/void Q3Socket::setReadBufferSize( Q_ULONG bufSize ){ d->readBufferSize = bufSize;}/*! Returns the size of the read buffer. \sa setReadBufferSize()*/Q_ULONG Q3Socket::readBufferSize() const{ return d->readBufferSize;}/*! \fn bool Q3Socket::isSequential() const \internal*/#endif //QT_NO_NETWORK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -