网络编程OSI开放式系统互联参考模型七层参考模型
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
网络编程,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报文大小,并据此大小分配接收缓冲区,最后读取相应数据。
■、TCP
TCP是一个基于流的协议。对于应用程序,数据表现为一个长长的流,而不是一个大大的平面文件。基于TCP的高层协议通常是基于行的或者基于块的。
●、基于行的协议把数据作为一行文本进行传输,每行都以一个换行符结尾。
●、基于块的协议把数据作为二进制块进行传输,每块是由一个size大小字段和紧跟它的一个size 字节的数据组成。
QTcpSocket通过器父类QAbstractSocket继承了QIODevice,因此他可以通过使用QTextStream 和QDataStream来进行读取和写入。
QTcpServer类在服务器端处理来自TCP客户端连接数据,需要注意的是,该类直接继承于QObject基类,而不是QAbstractSocket抽象套接字类。
下面介绍一个TCP应用示例,示例来自《精通Qt4编程》,感觉十分不错,它也是由客户端和服务器两部分组成,客户端选择本地文件,并通过TCP连接将它上传到服务器端。
由于使用了TCP协议,所以可以轻松的传递大文件,而无需担心传输过程造成文件损坏。
其中客户端程序SendFile从本地文件系统中选中一个已有文件并在成功连接服务器后开始发送,服务器端程序ReceiveFile则将该文件保存在当前目录下,两端均以进度条和数据两种形式分别显示文件传输进度和详细的数据传输字节数。
客户端程序SendFile的用户界面是一个简单的对话框,上面布置一个QProgressBar进度条,一个用于显示状态的QLabel,三个QPushButton按钮,分别用来选择文件、发送文件和退出程序。
Qt的QFileDialog类提供了一个文件选择对话框,用户使用它可以很容易的进行目录或文件的选择。
下面将Dialog类部分代码陈列出来,它是QDialog的子类,实现客户端的全部功能。
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
public slots:
void start();
void startTransfer();
void updateClientProgress(qint64 numBytes);
void displayError(QAbstractSocket::SocketError socketError);
void openFile();
private:
QProgressBar *clientProgressBar;
QLabel *clientStatusLabel;
QPushButton *startButton;
QPushButton *quitButton;
QPushButton *openButton;
QDialogButtonBox *buttonBox;
QTcpSocket tcpClient; //客户端套接字
qint64 TotalBytes; //总共需发送的字节数