QT基于TCP实现网络聊天室程序

本文实例为大家分享了QT学习:基于TCP的网络聊天室程序,供大家参考,具体内容如下

TCP与UDP的差别如图:

一、TCP工作原理

如下图所示,TCP能够为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错 地送达网络上的其他计算机。因此,对可靠性要求高的数据通信系统往往使用TCP传输数据,但在正式收发数据前,通信双方必须首先建立连接。

二、TCP编程模型

下面介绍基于TCP的经典编程模型,TCP客户端与服务器间的交互时序如下图所示:

三、TCP服务器端编程实例

TCP服务器端的具体实现如下:

建立工程TcpServer.pro,文件代码如下。

(1)头文件“tcpserver.h”中声明了需要的各种控件,TcpServer继承自QDialog,实现了服务器端的对话框显示与控制。其具体代码如下:

#include <QDialog> 
#include <QListWidget> 
#include <QLabel> 
#include <QLineEdit> 
#include <QPushButton> 
#include <QGridLayout> 
class TcpServer : public QDialog 
{ 
Q_OBJECT 
public: 
TcpServer(QWidget *parent = 0,Qt::WindowFlags f=0); 
~TcpServer(); 
private: 
QListWidget *ContentListWidget; 
QLabel *PortLabel; 
QLineEdit *PortLineEdit; 
QPushButton *CreateBtn; 
QGridLayout *mainLayout; 
}; 

(2)在源文件“tcpserver.cpp”中,TcpServer类的构造函数主要实现窗体各控件的创建、布局等,其具体代码如下:

#include "tcpserver.h" 
TcpServer::TcpServer(QWidget *parent,Qt::WindowFlags f) : QDialog(parent,f) 
{ 
setWindowTitle(tr("TCP Server")); 
ContentListWidget = new QListWidget; 
PortLabel = new QLabel(tr("端口:")); 
PortLineEdit = new QLineEdit; 
CreateBtn = new QPushButton(tr("创建聊天室")); 
mainLayout = new QGridLayout(this); 
mainLayout->addWidget(ContentListWidget,0,0,1,2); 
mainLayout->addWidget(PortLabel,1,0); 
mainLayout->addWidget(PortLineEdit,1,1); 
mainLayout->addWidget(CreateBtn,2,0,1,2); 
} 

(3)服务器端界面如下图所示:

以上完成了服务器端界面的设计,下面将详细完成聊天室的服务器端功能。

(1)在工程文件“TcpServer.pro”中添加如下语句:

QT += network

(2)在工程“TcpServer.pro”中添加C++类文件“tcpclientsocket.h”及“tcpclientsocket.cpp”,TcpClientSocket 继承自QTcpSocket,创建一个TCP套接字,以便在服务器端实现与客户端程序的通信。
头文件“tcpclientsocket.h”的具体代码如下:

#include <QTcpSocket> 
#include <QObject> 
class TcpClientSocket : public QTcpSocket 
{ 
Q_OBJECT //添加宏(Q_OBJECT)是为了实现信号与槽的通信 
public: 
TcpClientSocket(QObject *parent=0); 
signals: 
void updateClients(QString,int); 
void disconnected(int); 
protected slots: 
void dataReceived(); 
void slotDisconnected(); 
}; 

(3)在源文件“tcpclientsocket.cpp”中,构造函数(TcpClientSocket)的内容(指定了信号与槽的
连接关系)如下:

#include "tcpclientsocket.h" 
TcpClientSocket::TcpClientSocket(QObject *parent) 
{ 
connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived())); // readyRead()是QIODevice的signal,由 QTcpSocket继承而来。QIODevice是所有输入/输出设备的一个抽象类,其中定义了基本的接口,在Qt中, QTcpSocket也被看成一个QIODevice,readyRead()信号在有数据到来时发出。  
connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); // disconnected()信号在断开连接时发出。 
} 

在源文件“tcpclientsocket.cpp”中,dataReceived()函数的具体代码如下:

void TcpClientSocket::dataReceived() 
{ 
while(bytesAvailable()>0) 
{ 
int length = bytesAvailable(); 
char buf[1024]; 
read(buf,length); 
QString msg=buf; 
emit updateClients(msg,length); 
} 
}

在源文件“tcpclientsocket.cpp”中,槽函数slotDisconnected()的具体代码如下:

void TcpClientSocket::slotDisconnected() 
{ 
emit disconnected(this->socketDescriptor()); 
} 

(4)在工程“TcpServer.pro”中添加C++类文件“server.h”及“server.cpp”,Server继承自QTcpServer,实现一 个TCP协议的服务器。利用QTcpServer,开发者可以监听到指定端口的TCP连接。其具体代码如下:

#include <QTcpServer> 
#include <QObject> 
#include "tcpclientsocket.h" //包含TCP的套接字 
class Server : public QTcpServer 
{ 
Q_OBJECT 
//添加宏(Q_OBJECT)是为了实现信号与槽的通信 
public: 
Server(QObject *parent=0,int port=0); 
QList<TcpClientSocket*> tcpClientSocketList; 
signals: 
void updateServer(QString,int); 
public slots: 
void updateClients(QString,int); 
void slotDisconnected(int); 
protected: 
void incomingConnection(int socketDescriptor); 
}; 

(5)在源文件“server.cpp”中,构造函数(Server)的具体内容如下:

#include "server.h" 
Server::Server(QObject *parent,int port):QTcpServer(parent) 
{ 
listen(QHostAddress::Any,port); 
}

其中,listen(QHostAddress::Any,port)在指定的端口对任意地址进行监听。
QHostAddress定义了几种特殊的IP地址,如QHostAddress::Null表示一个空地址;
QHostAddress::LocalHost表示IPv4的本机地址127.0.0.1;
QHostAddress::LocalHostIPv6表示IPv6的本机地址;
QHostAddress::Broadcast表示广播地址255.255.255.255;
QHostAddress::Any表示IPv4的任意地址0.0.0.0;
QHostAddress::AnyIPv6表示IPv6的任意地址。

在源文件“server.cpp”中,当出现一个新的连接时,QTcpSever触发incomingConnection()函数,参数

socketDescriptor指定了连接的Socket描述符,其具体代码如下:

void Server::incomingConnection(int socketDescriptor) 
{ 
TcpClientSocket *tcpClientSocket=new TcpClientSocket(this); //创建一个新的TcpClientSocket与客户端通信。  
connect(tcpClientSocket,SIGNAL(updateClients(QString,int), this,SLOT(updateClients(QString,int))); //连接TcpClientSocket的updateClients信号。  
connect(tcpClientSocket,SIGNAL(disconnected(int)),this, SLOT(slotDisconnected(int))); //连接 TcpClientSocket的disconnected信号。 
tcpClientSocket->setSocketDescriptor(socketDescriptor); //将新创建的TcpClient Socket的套接字描述符指定为参数socketDescriptor。 
tcpClientSocketList.append(tcpClientSocket); //将tcpClientSocket加入客户端套接字列表以便管理。 
}

在源文件“server.cpp”中,updateClients()函数将任意客户端发来的信息进行广播,保证聊天室的所有成员均能看到其他人的发言。其具体代码如下:

void Server::updateClients(QString msg,int length) 
{ 
emit updateServer(msg,length); //发出updateServer信号,用来通知服务器对话框更新相应的显示状态。
for(int i=0;i<tcpClientSocketList.count();i++) //实现信息的广播,tcpClientSocketList中保存了所有与服务器相连的TcpClientSocket对象。 
{ 
QTcpSocket *item = tcpClientSocketList.at(i); 
if(item->write(msg.toLatin1(),length)!=length) 
{ 
continue; 
} 
} 
} 

在源文件“server.cpp”中,slotDisconnected()函数实现从tcpClientSocketList列表中将断开连接的
TcpClientSocket对象删除的功能。其具体代码如下:

void Server::slotDisconnected(int descriptor) 
{ 
for(int i=0;i<tcpClientSocketList.count();i++) 
{ 
QTcpSocket *item = tcpClientSocketList.at(i); 
if(item->socketDescriptor()==descriptor) 
{ 
tcpClientSocketList.removeAt(i); 
return; 
} 
}
return; 
}

(6)在头文件“tcpserver.h”中添加如下内容:

#include "server.h" 
private: 
int port; 
Server *server; 
public slots: 
void slotCreateServer(); 
void updateServer(QString,int);

(7)在源文件“tcpserver.cpp”中,在构造函数中添加如下代码:

port=8010; 
PortLineEdit->setText(QString::number(port)); 
connect(CreateBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer())); 

其中,槽函数slotCreateServer()用于创建一个TCP服务器,具体内容如下:

void TcpServer::slotCreateServer() 
{ 
server = new Server(this,port); //创建一个Server对象 
connect(server,SIGNAL(updateServer(QString,int)),this, 
SLOT(updateServer(QString,int))); 
CreateBtn->setEnabled(false); 
} 

槽函数updateServer()用于更新服务器上的信息显示,具体内容如下:

void TcpServer::updateServer(QString msg,int length) 
{ 
ContentListWidget->addItem(msg.left(length)); 
}

(8)此时,工程中添加了很多文件,工程文件中的内容已经被改变,需要重新在工程文件
“TcpServer.pro”中添加:

QT += network

此时,运行服务器端工程“TcpServer.pro”编译通过。单击“创建聊天室”按钮,便开通了一个TCP聊天室的服务器,如下图所示:

四、TCP客户端编程实例

TCP客户端编程具体步骤如下:

建立工程“TcpClient.pro”,文件代码如下。

(1)在头文件“tcpclient.h”中,TcpClient类继承自QDialog类,声明了需要的各种控件,其具体代码如下:

#include <QDialog> 
#include <QListWidget> 
#include <QLineEdit> 
#include <QPushButton> 
#include <QLabel> 
#include <QGridLayout> 
class TcpClient : public QDialog 
{ 
Q_OBJECT 
public: 
TcpClient(QWidget *parent = 0,Qt::WindowFlags f=0); 
~TcpClient(); 
private: 
QListWidget *contentListWidget; 
QLineEdit *sendLineEdit; 
QPushButton *sendBtn; 
QLabel *userNameLabel; 
QLineEdit *userNameLineEdit; 
QLabel *serverIPLabel; 
QLineEdit *serverIPLineEdit; 
QLabel *portLabel; 
QLineEdit *portLineEdit; 
QPushButton *enterBtn; 
QGridLayout *mainLayout; 
};

(2)源文件“tcpclient.cpp”的具体代码如下:

#include "tcpclient.h" 
TcpClient::TcpClient(QWidget *parent,Qt::WindowFlags f) 
: QDialog(parent,f) 
{ 
setWindowTitle(tr("TCP Client")); 
contentListWidget = new QListWidget; 
sendLineEdit = new QLineEdit; 
sendBtn = new QPushButton(tr("发送")); 
userNameLabel = new QLabel(tr("用户名:")); 
userNameLineEdit = new QLineEdit; 
serverIPLabel = new QLabel(tr("服务器地址:")); 
serverIPLineEdit = new QLineEdit; 
portLabel = new QLabel(tr("端口:")); 
portLineEdit = new QLineEdit; 
enterBtn= new QPushButton(tr("进入聊天室")); 
mainLayout = new QGridLayout(this); 
mainLayout->addWidget(contentListWidget,0,0,1,2); 
mainLayout->addWidget(sendLineEdit,1,0); 
mainLayout->addWidget(sendBtn,1,1); 
mainLayout->addWidget(userNameLabel,2,0); 
mainLayout->addWidget(userNameLineEdit,2,1); 
mainLayout->addWidget(serverIPLabel,3,0); 
mainLayout->addWidget(serverIPLineEdit,3,1); 
mainLayout->addWidget(portLabel,4,0); 
mainLayout->addWidget(portLineEdit,4,1); 
mainLayout->addWidget(enterBtn,5,0,1,2); 
}

(3)客户端界面如下图所示:

以上完成了客户端界面的设计,下面将完成客户端的真正聊天功能。

(1)在客户端工程文件“TcpClient.pro”中添加如下语句:

QT += network

(2)在头文件“tcpclient.h”中添加如下代码:

#include <QHostAddress> 
#include <QTcpSocket> 
private: 
bool status; 
int port; 
QHostAddress *serverIP; 
QString userName; 
QTcpSocket *tcpSocket; 
public slots: 
void slotEnter(); 
void slotConnected(); 
void slotDisconnected(); 
void dataReceived(); 
void slotSend(); 

(3)在源文件“tcpclient.cpp”中添加头文件:

#include <QMessageBox> 
#include <QHostInfo> 

在其构造函数中添加如下代码:

status = false; 
port = 8010; 
portLineEdit->setText(QString::number(port)); 
serverIP =new QHostAddress(); 
connect(enterBtn,SIGNAL(clicked()),this,SLOT(slotEnter())); 
connect(sendBtn,SIGNAL(clicked()),this,SLOT(slotSend())); 
sendBtn->setEnabled(false);

在以上代码中,槽函数slotEnter()实现了进入和离开聊天室的功能。具体代码如下:

void TcpClient::slotEnter()
{
    if(!status)    //status表示当前的状态,true表示已经进入聊天室,false表示已经离开聊天室。 这里根据status的状态决定是执行“进入”还是“离开”的操作。
    {
        /* 完成输入合法性检验 */
        QString ip = serverIPLineEdit->text();
        if(!serverIP->setAddress(ip))//用来判断给定的IP地址能否被正确解析。
        {
            QMessageBox::information(this,tr("error"),tr("server ip address error!"));
            return;
        }
        if(userNameLineEdit->text()=="")
        {
            QMessageBox::information(this,tr("error"),tr("User name error!"));
            return;
        }
        userName=userNameLineEdit->text();
        /* 创建了一个QTcpSocket类对象,并将信号/槽连接起来 */
        tcpSocket = new QTcpSocket(this);
        connect(tcpSocket,SIGNAL(connected()),this,SLOT (slotConnected()));
        connect(tcpSocket,SIGNAL(disconnected()),this,SLOT (slotDisconnected()));
        connect(tcpSocket,SIGNAL(readyRead()),this,SLOT (dataReceived()));
        tcpSocket->connectToHost(*serverIP,port);    //与TCP服务器端连接,连接成功后发出connected() 信号
        status=true;
    }
    else
    {
        int length=0;
        QString msg=userName+tr(":Leave Chat Room");//构造一条离开聊天室的消息。
        if((length=tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length())                                                //通知服务器端以上 构造的消息
        {
            return;
        }
        tcpSocket->disconnectFromHost();                    //与服务器断开连接,断开连接后发出disconnected()信号。
        status=false; //将status状态复位
    }
}

在源文件“tcpclient.cpp”中,槽函数slotConnected()为connected()信号的响应槽,当与服务器连接成功后,客户端构造一条进入聊天室的消息,并通知服务器。其具体代码如下:

void TcpClient::slotConnected() 
{ 
sendBtn->setEnabled(true); 
enterBtn->setText(tr("离开")); 
int length=0; 
QString msg=userName+tr(":Enter Chat Room"); 
if((length=tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()) 
{ 
return; 
} 
} 

在源文件“tcpclient.cpp”中,槽函数slotSend()的具体代码如下:

void TcpClient::slotSend() 
{ 
if(sendLineEdit->text()=="") 
{ 
return; 
}
QString msg=userName+":"+sendLineEdit->text(); 
tcpSocket->write(msg.toLatin1(),msg.length()); 
sendLineEdit->clear(); 
}

在源文件“tcpclient.cpp”中,槽函数slotDisconnected()的具体内容如下:

void TcpClient::slotDisconnected() 
{ 
sendBtn->setEnabled(false); 
enterBtn->setText(tr("进入聊天室")); 
} 

当有数据到来时,触发源文件“tcpclient.cpp”的dataReceived()函数,从套接字中将有效数据取出并显示,其代码如下:

void TcpClient::dataReceived() 
{ 
while(tcpSocket->bytesAvailable()>0) 
{ 
QByteArray datagram; 
datagram.resize(tcpSocket->bytesAvailable()); 
tcpSocket->read(datagram.data(),datagram.size()); 
QString msg=datagram.data(); 
contentListWidget->addItem(msg.left(datagram.size())); 
} 
} 

(4)此时运行客户端“TcpClient.pro”工程,结果如下图所示:

最后,同时运行服务器和客户端程序,运行结果如下图所示,这里演示的是系统中登录了两 个用户的状态。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Qt实现网络聊天室的示例代码

    目录 1. 效果演示 2. 预备知识 2.1 QTcpServer 2.2 QTcpServer信号 2.3 QTcpSocket 2.4 QTcpSocket信号 3. 通信流程 3.1 服务器端 3.2 客户端 1. 效果演示 客户端 服务器 连接成功之后 2. 预备知识 在Qt中,实现网络编程的方式比用C++或C实现要方便简单许多,因为Qt已经替我们封装好了,我们会使用就可以了,然后大家还需要了解Qt 的信号槽机制,可以参考我这篇文章,Qt信号槽 2.1 QTcpServer QTcpSe

  • QT实现TCP网络聊天室

    本文实例为大家分享了QT实现TCP网络聊天室的具体代码,供大家参考,具体内容如下 服务器: serverdialog.h #ifndef SERVERDIALOG_H #define SERVERDIALOG_H #include <QDialog> #include <QTcpServer> #include <QTcpSocket> #include <QDebug> #include <QTimer> namespace Ui { clas

  • QT基于TCP网络聊天室

    本文实例为大家分享了QT实现网络聊天室的具体代码,供大家参考,具体内容如下 1.客户端 1.1UI设计 分两个部分,第一部分是消息区里面包含QPlainTextEdit和QListWidget,要显示接收的消息和在线的成员.第二部分QLineEdit发生字符. 1.2 子模块 1.2.1 登录界面 登录界面主要就是要有验证码,防止恶意程序的攻击.通过paintEvent画出一个白色矩形,在白色矩形里面显示四个不同颜色的字母以及随机出现的噪点. 代码: QLoginDialog.h #ifndef

  • QT基于TCP实现网络聊天室程序

    本文实例为大家分享了QT学习:基于TCP的网络聊天室程序,供大家参考,具体内容如下 TCP与UDP的差别如图: 一.TCP工作原理 如下图所示,TCP能够为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错 地送达网络上的其他计算机.因此,对可靠性要求高的数据通信系统往往使用TCP传输数据,但在正式收发数据前,通信双方必须首先建立连接. 二.TCP编程模型 下面介绍基于TCP的经典编程模型,TCP客户端与服务器间的交互时序如下图所示: 三.TCP服务器端编程实例 TCP服务器端的具体实现

  • Java基于UDP协议实现简单的聊天室程序

    最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆. 先看一下效果: 实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理.  "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着. 看一下代码实现: 1.首先是消息服务器的实现,功能很简单: •将客户端的信息(进入了哪一

  • 基于Python socket实现简易网络聊天室

    目录 1.socket_ui.py 服务端 1-1. 依赖引用 1-2. 实现过程 1-3. 实现效果 2.client_ui.py 客户端 2-1. 依赖引用 2-2. 实现过程 2-3. 实现效果 在这个周末刚刚写出来的python桌面应用--网络聊天室,主要通过pyqt5作为桌面应用框架,socket作为网络编程的框架,从而实现包括客户端和服务端的网络聊天室的GUI应用,希望可以一起学习.一起进步! 应用包括服务端server_ui.py.客户端client_ui.py两个python模块

  • java实现基于Tcp的socket聊天程序

    对于步入编程行业不深的初学者或是已经有所领会的人来说,当学习一项新的技术的时候,非常渴望有一个附上注释完整的Demo.本人深有体会,网上的例子多到是很多,但是很杂不完整,写代码这种东西来不得半点马虎,要是错了一点,那也是运行不了的.这对于初学者来说更加的头疼,因为他根本不知道错在哪里,盲目的改只能错上加错.最后不得不去找找看看有没有能够直接运行的例子再加以模仿. 下面是博主在学习Java的socket时写的一个完整的例子,并且带上了完整的注释.它是一个简单的聊天程序,但是它可以设置任意多用户同时

  • java基于TCP协议实现聊天程序

    JAVA程序设计之基于TCP协议的socket聊天程序 ,供大家参考,具体内容如下 一.程序实现的功能 1.进入客户端界面 2.创建昵称 3.群发信息 4.@私聊 5.下线通知 6.在线人数统计 二.整体架构图 三.简单介绍 本程序实现了基于TCP通信的聊天程序: 1 服务器端: 服务器端继承JFrame框架,添加组件.创建服务器端的socket,起一个线程池,每接收到一个客户端的连接,分配给其一个线程处理与客户端的通信,将每个客户端的昵称和服务器分配给其的输出流存储到哈希表中.通过检索哈希表中

  • C++基于socket多线程实现网络聊天室

    本文实例为大家分享了C++基于socket多线程实现网络聊天室的具体代码,供大家参考,具体内容如下 1. 实现图解 2. 聊天室服务端:TCP_Server_Chat.cpp #include <winsock2.h> // winsock2的头文件 #include <iostream> #pragma comment(lib, "ws2_32.lib") using namespace std; // stdcall的线程处理函数 DWORD WINAPI

  • Java实战之基于TCP实现简单聊天程序

    目录 一.如何实现TCP通信 二.编写C/S架构聊天程序 1.编写服务器端程序 - Server.java 2.编写客户端程序 - Client.java 3.测试服务器端与客户端能否通信 4.程序优化思路 - 服务器端采用多线程 一.如何实现TCP通信 要实现TCP通信需要创建一个服务器端程序和一个客户端程序,为了保证数据传输的安全性,首先需要实现服务器端程序,然后在编写客户端程序. 在本机运行服务器端程序,在远程机运行客户端程序 本机的IP地址:192.168.129.222 远程机的IP地

随机推荐