QTcpServer编程
网络编程,OSI(开放式系统互联参考模型)七层参考模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
套接字(Socket)是网络通信的基本构建模块,又分为流式套接字(Stream Socket)和数据报套接字(Datagram Socket)两种类型的套接字。
TCP:传送控制协议(Transmission Control Protocol),这是一种提供给用户的可靠的全双工字节流面向连接的协议。
UDP:用户数据报协议(User Datagram Protocol),这是提供给用户进程的无连接协议,用于传送数据而不执行正确性检查。
当然TCP、UDP都归属于传输层协议。
对所用的网络知识简短的介绍,下面步入正题,开始Qt套接字编程~
在TCP/IP网络中两个进程间的相互作用的主要模式是客户机/服务器模式(Client/Server model),是构造分布式应用程序最常用的模式。
Qt中几乎所有的QtNetwork类都是异步的,一般情况下没有必要Socket使用在多线程中。
■、UDP
UDP是不可信赖的,它是基于包的协议。一些应用程序层的协议使用UDP是因为它比TCP更加小巧,数据是从一个主机到另一个主机以包的形式发送的。这里没有连接到的概念,并且如果一个UDP包没有被正确交付,它不会向系统报告任何错误。
下面写一个简单的广播示例,由客户端和服务器两部分组成。
//客户端发送数据
void Client::sendDatagram()
{
QByteArray datagram;
QDataStream out(&datagram, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_3);
out << QDateTime::currentDateTime() << "vic.MINg!" << 3.14;
QUdpSocket udpSocket(this);
udpSocket.writeDatagram(datagram, QHostAddress::Broadcast, 1981);
}
在QByteArray型局部变量datagram中构建待发送的数据包,然后通过QUdpSocket类的 writeDatagram ( const QByteArray & datagram, const QHostAddress & host, quint16 port );函数将数据包发出。值得注意的是,这里的地址使用了QHostAddress::Broadcast值,它对应IPv4下的广播地址,如果将该值更换 成单机地址(如本机地址QHostAddress::LocalHost),将变成一个普通的点对点的UDP程序。
//服务器接收数据
void Server::initSocket()
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(1981);
connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(readPendingDatagrams()));
}
初始化生成QUdpSocket实例,并绑定与客户端约定的端口(1981)。这里多说几句,在编写网络程序时应该使用1024以上的端口号,1024以 下的端口号通常被系统保留,紧密的绑定了一些服务(如80端口是http服务、21端口是ftp服务)。
void Server::readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
QDateTime dateTime;
QString name;
double data;
QDataStream in(&datagram, QIODevice::ReadOnly);
in.setVersion(QDataStream::Qt_4_3);
in >> dateTime >> name >> data;
}
}
接受数据函数首先调用QUdpSocket类的成员函数hasPendingDatagrams()以判断是否有可供读取的数据。如果有则通过 pendingDatagramSize()获取当前可供读取的UDP报文大小,并据此大小分配接收缓冲区,