这里用Qt来简单设计实现一个场景,即:
(1)两端:服务器QtServer和客户端QtClient
(2)功能:服务端连接客户端,两者能够互相发送消息,传送文件,并且显示文件传送进度。
环境:VS20013 + Qt5.11.2 + Qt设计师
先看效果:
一、基本概念
客户端与服务器的基本概念不说了,关于TCP通信的三次握手等等,在《计算机网络》里都有详细介绍。这里说下两者是如何建立起通信连接的。
(1)IP地址:首先服务器和每一个客户端都有一个地址,即IP地址。(底层的MAC地址,不关心,因为TCP通信以及IP,是七层架构里面的网络层、传输层了,底层透明)。对于服务器来说,客户端的数量及地址是未知的,除非建立了连接。但是对于客户端来说,必须知道服务器的地址,因为两者之间的连接是由客户端主动发起的。
(1)端口号:软件层面的端口号,指的是 “应用层的各种协议进程与运输实体进行层间交互的一种地址”。简而言之,每一个TCP连接都是一个进程,操作系统需要为每个进程分配一个协议端口(即每一个客户端与服务端的连接,不是两台主机的连接,而是两个端口的连接)。但一台主机通常会有很多服务,很多进程,单靠一个IP地址不能标识某个具体的进程或者连接。所以用端口号来标识访问的目标服务器以及服务器的目标服务类型。端口号也有分类,但这不是本文的重点,详见教材。
(3)TCP连接:总的来说,TCP的连接管理分为单个阶段:建立连接 -> 数据传送 -> 连接释放。在(2)里说到,每个TCP连接的是具体IP地址的主机的两个端口,即TCP连接的两个端点由IP地址和端口号组成,这即是套接字(socket)的概念:套接字socket = IP + 端口号。
因此,我们要通过通过套接字来建立服务端与客户端的通信连接。
二、Qt相关类
QTcpSocket:提供套接字
QTcpServer:提供基于TCP的服务端,看官方文档的解释如下:
This class makes it possible to accept incoming TCP connections. You can specify the port or have QTcpServer pick one automatically. You can listen on a specific address or on all the machine’s addresses.
这个解释里面提到两点:
(1)指定端口:即开通哪一个端口用于建立TCP连接;
(2)监听:监听(1)中指定的端口是否有连接的请求。
三、写服务器和客户端的具体流程
(1)服务器:
创建并初始化 QTcpServer 对象;
启动服务器监听,通过调用成员函数 listen(QHostAddress::Any, 端口号);
连接 QTcpServer 对象的 newConnection 信号槽,当有客户端链接时,客户端会发送 newConnection 信号给服务器,触发槽函数接受链接(得到一个与客户端通信的套接字 QTcpSocket);
QTcpsocket 对象调用成员函数 write,发送数据给客户端;
当客户端有数据发送来,QTcpSocket 对象就会发送 readyRead 信号,关联槽函数读取数据;
连接 QTcpsocket 对象的 disconnected 信号槽,当客户端对象调用成员函数 close,会触发 QTcpsocket 对象的 disconnected 信号,进而触发槽函数进行相应处理。
(2)客户端:
创建并初始化 QTcpSocket 对象;
QTcpSocket 调用 connectToHost(QHostAddress("IP"), 端口号),连接服务器IP和端口号;
QTcpsocket 对象调用成员函数 write,发送数据给服务器;
连接QTcpsocket 对象的 connected() 信号槽,当客服端成功连接到服务器后触发 connected() 信号;
连接QTcpsocket 对象的 readyread() 信号槽,当客户端接收到服务端发来数据时触发 readyread() 信号;
连接 QTcpsocket 对象的 disconnected 信号槽,当客户端对象调用成员函数 close,会触发