1、 QTcpSocket, QTcpServer, C++ GUI Programming
Chapter15-Tripplanner示例中是如何接收socket数据的?
关键接口:
void QIODevice::readyRead () [signal]
This signal is emitted once every time new data is available for reading from the device.
可知,只要有新的数据传来,都会触发该signal。
qint64 QAbstractSocket::bytesAvailable () const [virtual]
Returns the number of incoming bytes that are waiting to be read.
发送socket数据时是按照如下指定的格式来发送的,如server发送:The Trip Server’s blocks,数据的格式如下:
QDate | Departure date |
QTime | Departure time |
quint16 | Duration (in minutes) |
quint8 | |
QString | Train type |
第一个数据表示该datablock的大小,它的类型是quint16;第二个表示Departure date,它的类型是QDate;依次类推。注意,server在发送完有效数据后,会再发送一个0XFFFF,表示该data block结束。(注,表格中红色部分是有效数据)
out << quint16(0xFFFF);
在接收socket数据时,也是按照同样的顺序来接收的。在bytesAvailable后,会触发readyRead,接收函数调用:in >> nextBlockSize;来接收第一个数据,也就是quint16类型的表示有效data block大小的数据。然后用以下接口来做判断:
if(nextBlockSize == 0xFFFF) {
closeConnection();
statusLabel->setText(tr("Found %1 trip(s)").arg(row));
break;
}
if(tcpSocket.bytesAvailable() < nextBlockSize)
break;
它的含义是,如果接收到的数据是0XFFFF,表示此次接收结束;如果tcpSocket.bytesAvailable()< nextBlockSize,说明这个data block的有效数据(指从Departure date到Train type的数据)还没有都read available,则退出函数;直到有新的数据到达,且可bytesAvailable的大小等于有效数据的大小,才能接着往下执行。
2、对TCP和UDP来说,服务器端和客户端的区别是什么?
Chapter15-Tripplanner示例使用TCP的流程如下:
注意,server也是通过建立QTcpSocket对象来和client的QTcpSocket进行通信的。
问题:server在没有client请求的情况下,可以主动向client发送数据吗?
可以,只要建立并保持client和server之间的socket连接,就可以。
3、TCP
TCP is a stream-oriented protocol. For applications, the data appears to be a long stream, rather like a large flat file. The high-level protocols built on top of TCP are typically either line-oriented or block-oriented:
Line-oriented protocols transfer data as lines of text, each terminated by a newline.
Block-oriented protocols transfer data as binary data blocks. Each block consists of a size field followed by that much data.
4、实现QTcpServer向client发送数据的两种方法
1)Chapter15-Tripplanner使用的方法
调用这个接口实现:
void QTcpServer::incomingConnection ( int socketDescriptor) [virtual protected]
This virtual function is called by QTcpServer when a new connection is available. The socket Descriptor argument is the native socket descriptor for the accepted connection.
知:在QTcpServer与一个client建立connect后,会自动调用incomingConnection,并传进一个socketDescriptor,可以用如下代码建立一个QTcpSocket来和client进行通信:
voidTripServer::incomingConnection(int socketId)
{
tcpsocket->setSocketDescriptor(socketId);
}
其中,tcpsocket = new QTcpSocket。这样就建立起server端QTcpSocket与client端QTcpSocket的连接。
2)QT-NetWork-Example里各server例程使用的方法
调用如下两个接口实现:
void QTcpServer::newConnection () [signal]
Thissignal is emitted every time a new connection is available.
QTcpSocket * QTcpServer::nextPendingConnection ()[virtual]
Returnsthe next pending connection as a connected QTcpSocket object.
用如下代码实现:
connect(tcpServer,SIGNAL(newConnection()), this, SLOT(sendFortune()));
voidServer::sendFortune()
{
...
QTcpSocket *clientConnection =tcpServer->nextPendingConnection();
...
}
5、讲解多线程TCP服务器的例程
http://www.bogotobogo.com/Qt/Qt5_QTcpServer_Multithreaded_Client_Server.php,用run函数实现多线程。
http://www.qt-coding.com/category/applications/,用moveToThread实现多线程。