您的位置:首页 > 编程语言 > Qt开发

QT分析之网络编程(三)

2011-10-10 16:23 337 查看
QT分析之网络编程(三)

程序人生 2010-01-31 21:45:47 阅读229 评论0 字号:大中小

3、读取信息

在QAbstractSocket中,有两个成员是收发数据用的:readData()、writeData()

readData()有两种读取方式:有缓冲和无缓冲方式。基本原理是一致的,简单其见只分析无缓冲直接读取方式。

qint64 QAbstractSocket::readData(char *data, qint64 maxSize)

{

Q_D(QAbstractSocket);

if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())

d->socketEngine->setReadNotificationEnabled(true);

if (!d->isBuffered) {

if (!d->socketEngine)

return -1; // no socket engine is probably EOF

qint64 readBytes = d->socketEngine->read(data, maxSize);

if (readBytes < 0) {

d->socketError = d->socketEngine->error();

setErrorString(d->socketEngine->errorString());

}

if (!d->socketEngine->isReadNotificationEnabled())

d->socketEngine->setReadNotificationEnabled(true);

return readBytes;

}

if (d->readBuffer.isEmpty())

// if we're still connected, return 0 indicating there may be more data in the future

// if we're not connected, return -1 indicating EOF

return d->state == QAbstractSocket::ConnectedState ? qint64(0) : qint64(-1);

// If readFromSocket() read data, copy it to its destination.

if (maxSize == 1) {

*data = d->readBuffer.getChar();

return 1;

}

qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize);

qint64 readSoFar = 0;

while (readSoFar < bytesToRead) {

const char *ptr = d->readBuffer.readPointer();

int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),

d->readBuffer.nextDataBlockSize());

memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);

readSoFar += bytesToReadFromThisBlock;

d->readBuffer.free(bytesToReadFromThisBlock);

}

return readSoFar;

}

从前面(二)可以知道,socketEngine->read()实际调用的是QNativeSocketEngine::read()

qint64 QNativeSocketEngine::read(char *data, qint64 maxSize)

{

Q_D(QNativeSocketEngine);

Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::read(), -1);

Q_CHECK_STATES(QNativeSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1);

qint64 readBytes = d->nativeRead(data, maxSize);

// Handle remote close

if (readBytes == 0 && d->socketType == QAbstractSocket::TcpSocket) {

d->setError(QAbstractSocket::RemoteHostClosedError,

QNativeSocketEnginePrivate::RemoteHostClosedErrorString);

close();

return -1;

}

return readBytes;

}

除了一些相关的检查,就是调用QNativeSocketPrivate::nativeRead()

qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)

{

Q_Q(QNativeSocketEngine);

if (!q->isValid()) {

qWarning("QNativeSocketEngine::unbufferedRead: Invalid socket");

return -1;

}

ssize_t r = 0;

#ifdef Q_OS_SYMBIAN

r = ::read(socketDescriptor, data, maxSize);

#else

r = qt_safe_read(socketDescriptor, data, maxSize);

#endif

if (r < 0) {

r = -1;

switch (errno) {

#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN

case EWOULDBLOCK:

#endif

case EAGAIN:

// No data was available for reading

r = -2;

break;

case EBADF:

case EINVAL:

case EIO:

//error string is now set in read(), not here in nativeRead()

break;

#ifdef Q_OS_SYMBIAN

case EPIPE:

#endif

case ECONNRESET:

#if defined(Q_OS_VXWORKS)

case ESHUTDOWN:

#endif

r = 0;

break;

default:

break;

}

}

#if defined (QNATIVESOCKETENGINE_DEBUG)

qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i",

data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(),

maxSize, r);

#endif

return qint64(r);

}

至此,调用API读取数据。

4、发送数据

同样分有缓存与无缓存方式,对无缓存方式:

qint64 QAbstractSocket::writeData(const char *data, qint64 size)

{

Q_D(QAbstractSocket);

if (d->state == QAbstractSocket::UnconnectedState) {

d->socketError = QAbstractSocket::UnknownSocketError;

setErrorString(tr("Socket is not connected"));

return -1;

}

if (!d->isBuffered) {

qint64 written = d->socketEngine->write(data, size);

if (written < 0) {

d->socketError = d->socketEngine->error();

setErrorString(d->socketEngine->errorString());

} else if (!d->writeBuffer.isEmpty()) {

d->socketEngine->setWriteNotificationEnabled(true);

}

if (written >= 0)

emit bytesWritten(written);

return written;

}

char *ptr = d->writeBuffer.reserve(size);

if (size == 1)

*ptr = *data;

else

memcpy(ptr, data, size);

qint64 written = size;

if (d->socketEngine && !d->writeBuffer.isEmpty())

d->socketEngine->setWriteNotificationEnabled(true);

return written;

}

查看QNativeSocketEngine::write():

qint64 QNativeSocketEngine::write(const char *data, qint64 size)

{

Q_D(QNativeSocketEngine);

Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::write(), -1);

Q_CHECK_STATE(QNativeSocketEngine::write(), QAbstractSocket::ConnectedState, -1);

return d->nativeWrite(data, size);

}

qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)

{

Q_Q(QNativeSocketEngine);

qint64 ret = 0;

// don't send more than 49152 per call to WSASendTo to avoid getting a WSAENOBUFS

for (;;) {

qint64 bytesToSend = qMin<qint64>(49152, len - ret);

WSABUF buf;

buf.buf = (char*)data + ret;

buf.len = bytesToSend;

DWORD flags = 0;

DWORD bytesWritten = 0;

int socketRet = ::WSASend(socketDescriptor, &buf, 1, &bytesWritten, flags, 0,0);

ret += qint64(bytesWritten);

if (socketRet != SOCKET_ERROR) {

if (ret == len)

break;

else

continue;

} else if (WSAGetLastError() == WSAEWOULDBLOCK) {

break;

} else {

int err = WSAGetLastError();

WS_ERROR_DEBUG(err);

switch (err) {

case WSAECONNRESET:

case WSAECONNABORTED:

ret = -1;

setError(QAbstractSocket::NetworkError, WriteErrorString);

q->close();

break;

default:

break;

}

break;

}

}

return ret;

}

至此分析完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: