如何使用QT5编写一个利用TCP协议的聊天室 (一)编写一个TCP的服务器端

关于TCP协议的知识点

TCP协议是一种基于传输层的协议,具有可靠性,需要连接,工作方式为全双工,传输速度相较于UPD更慢的特点,一般用于传输大量的数据,传输过程不允许丢包的情况.一般情况下聊天类软件均采用UDP协议,此处采用TCP是为了了解TCP的特点,以及保证实验过程不因为丢包影响实验结果.

实验思路

我将服务器端分为三个部分,每个部分分别实现不同的功能.

第一部分:服务器端的外形设计,服务器端应有一个对话框显示客户端的登入登出以及在登入期间所发送的信息,一个文本框显示端口号,一个按钮来开启服务器

第二部分:服务器功能,服务器需要监听一个固定的端口,当有客户端接入该端口时,创建一个TCP套接字对象来为该客户服务(以便在服务端实现与客户端的通信),服务器还需要能存储每一个接入的客户端的信息

第三部分:一个TCP套接字对象的功能,该对象需要能读取套接字中的数据,将其传输给服务器,

具体实现

以下代码为.cpp中的部分代码,代码参考<<Qt5开发及实例(第三版)>>,若内容有错误理解希望能提出指正

第一部分:

 1 Tcpserver::Tcpserver(QWidget *parent,Qt::WindowFlags f)//构造函数
 2     : QDialog(parent,f)
 3 {
 4     setWindowTitle(tr("TCP Server"));//更改名称
 5     ContentListWidget = new QListWidget;//初始化一个对话框,显示相应的信息
 6     PortLabel = new QLabel(tr("端口"));初始化一个标签,让其显示相应的内容
 7     PortLineEdit = new QLineEdit;//初始化一个对话框显示固定的端口号
 8     CreateBtn = new QPushButton(tr("create chat room"));//初始化一个按钮,让其显示相应的内容
 9     mainLayout = new QGridLayout(this);//初始化一个QGridLayout的布局,并将所有部件塞进布局
10     mainLayout->addWidget(ContentListWidget,0,0,1,2);
11     mainLayout->addWidget(PortLabel,1,0);
12     mainLayout->addWidget(PortLineEdit,1,1);
13     mainLayout->addWidget(CreateBtn,2,0,1,2);
14     port = 8010;//监听8010端口
15     PortLineEdit->setText(QString::number(port));//将端口号显示
16     connect(CreateBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer()));//按下按钮发送信号,触发槽函数,该槽函数功能为创建一个服务器
17 }
18 Tcpserver::~Tcpserver()//析构函数
19 {
20 }
21 void Tcpserver::slotCreateServer()//槽函数的实现
22 {
23     server = new Server(this,port);//创建一个Server对象,并将端口号传给该对象,是其对该端口进行监听
24     connect(server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int)));//若server发送updateServer信号,触发tcpserver的槽函数updateServer
25     //使其更新对话框内容
26     CreateBtn->setEnabled(false);//创建服务器之后 无法再点击该按钮
27 }
28 void Tcpserver::updateServer(QString msg,int length)//更新内容的槽函数
29 {
30     ContentListWidget->addItem(msg.left(length));
31 }

第二部分:
 1 Server::Server(QObject *parent,int port) : QTcpServer(parent)
 2 {
 3     listen(QHostAddress::Any,port);//在指定的端口对任意地址监听
 4 }
 5 void Server::incomingConnection(qintptr socketDescriptor)//当出现一个新的连接的时候,TcpServer便会触发incomingConnection()函数,每有一个新的连接都会触发一次,即都创建一个新的对象
 6 {
 7     TcpClientSocket *tcpClientSocket = new TcpClientSocket(this);//创建一个新的TcpClientSocket与客户端通信
 8     //出现一个新连接才会创建一个 TcpClientSocket 的对象,如果连接后有数据传入,该对象将其读下来 通过updateClient信号来发送
 9     connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int)));//连接TcpClientSocket的updateClients信号
10     //当有新数据传入后,TcpClientSocket便会发出updateClients的信号,此时触发Server中的updateClients的槽函数,将信号中的msg与length传入该槽函数
11     connect(tcpClientSocket,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected(int)));//连接TcpClientSocket中的disconnected信号
12     //当TcpClientSocket的对象断开连接后,发出disconnected的信号,此时触发Server中的slotDisconnected的槽函数
13     tcpClientSocket->setSocketDescriptor(socketDescriptor);//将新创建的TcpClientSocket的套接字描述符指定为参数socketDescriptor
14     tcpClientSocketList.append(tcpClientSocket);//将tcpClientSocket这个对象添加入tcpClientSocketList这个列表中
15 }
16 void Server::updateClients(QString msg,int length)
17 {
18     emit updateServer(msg,length);//发出updateServer的信号,通知服务器对话框更新相应的显示状态
19     for(int i = 0;i<tcpClientSocketList.count();i++)//实现广播,即将新发送到服务器中的数据进行广播,发送到每一个连接的对象,进行同步更新对话框
20     {
21         QTcpSocket *item = tcpClientSocketList.at(i);//
22         if(item->write(msg.toLatin1(),length)!=length)
23         {
24             continue;
25         }
26     }
27 }
28 void Server::slotDisconnected(int descriptor)//从tcpClientSocketList列表中将断开连接的TcpClientSocket对象删除
29 {
30     for (int i  = 0;i<tcpClientSocketList.count();i++) {
31         QTcpSocket *item = tcpClientSocketList.at(i);
32         if(item->socketDescriptor()==descriptor)
33         {
34             tcpClientSocketList.removeAt(i);
35             return;
36         }
37     }
38     return;
39 }
第三部分:
 
 1 TcpClientSocket::TcpClientSocket(QObject *parent)
 2 {  
 3     connect(this,SIGNAL(readyRead()),this,SLOT(dateReceived()));//readyRead()是QIODevice的一个信号函数,由QTcpSocket继承而来,在有数据来时发出信号
 4     connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));//disconnected()是QIODevice的一个信号函数,由QTcpSocket,断开连接时发出信号
 5 }
 6 void TcpClientSocket::dateReceived()
 7 {
 8     while(bytesAvailable()>0)//当有数据来时,bytesAvailable()从套接字中检测所来的数据,返回等待读取的传入字节数
 9     {
10         int length = bytesAvailable();
11         char buf[1024];
12         read(buf,length);//将套接字中的数据读取到buf中,读取长度为length
13         QString msg = buf;
14         emit updateClients(msg,length);//发出信号
15     }
16 }
17 void TcpClientSocket::slotDisconnected()
18 {
19     emit disconnected(this->socketDescriptor());//发出disconnected信号
20 }

猜你喜欢

转载自www.cnblogs.com/Emiya-Shirou/p/11261508.html