一:服务器端部署在ubuntu云服务器上。
二:客户端软件运行在windows系统。
一、服务器端
1.在项目的.pro文件里添加QT +=network。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QTcpServer>
#include <QTcpSocket>
#include <QObject>
#include <QList>
class dialog:public QObject
{
Q_OBJECT
public:
dialog(QObject *parent=NULL);
private:
QTcpServer *tcpserver;
QTcpSocket *tcpsocket;
QList <QTcpSocket*> tcpClientList;
private slots:
void onNewConnection();
void slotDataReceived();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include <QByteArray>
//#pragma execution_character_set("utf-8")
#include <QHostInfo>
using namespace std;
dialog::dialog(QObject *parent):QObject (parent)
{
tcpserver=new QTcpServer;
QString name=QHostInfo::localHostName();
QHostInfo ip=QHostInfo::fromName(name);
QList<QHostAddress> alist=ip.addresses();
//ip1=QHostAddress::Any;
//ip=alist.at(0);
if(tcpserver->listen(alist.at(0),6500))
{
qDebug("TCP服务器创建成功");
// qDebug()<<alist.at(0).toString();
for (int i=0;i<alist.count();i++) {
qDebug()<<alist.at(i).toString();
};
}
else
{
qDebug("TCP服务器创建失败");
for (int i=0;i<alist.count();i++) {
qDebug()<<alist.at(i).toString();
};
}
connect(tcpserver,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}
void dialog::onNewConnection()
{
tcpsocket=tcpserver->nextPendingConnection();
tcpClientList.append(tcpsocket);
qDebug("连接成功");
connect(tcpsocket,SIGNAL(readyRead()),
this,SLOT(slotDataReceived()));
}
void dialog::slotDataReceived()
{
//遍历所有的客户端
for(int i=0; i<tcpClientList.count(); i++){
//检查当前客户端是否有数据到来
if(tcpClientList.at(i)->bytesAvailable()){
//接收客户端发送来的消息
QByteArray readbuf =
tcpClientList.at(i)->readAll();
//遍历所有的客户端
for(int i=0; i<tcpClientList.count(); i++){
tcpClientList.at(i)->write(readbuf);
}
qDebug("send data successfully!");
}}
}
main.cpp
#include <QCoreApplication>
#include <dialog.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
dialog d;
return a.exec();
}
二、客户端
1.在项目的.pro文件里添加QT +=network。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QString>
#include <QDialog>
#include <QHostAddress>
#include <QTcpSocket>
#include <QMessageBox>
#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
~Dialog();
private slots:
//发送消息,按钮的槽函数
void on_sendButton_clicked();
//连接服务器,按钮的槽函数
void on_connectButton_clicked();
//和服务器连接时调用的槽函数
void onConnected(void);
//和服务器断开连接调用的槽函数
void onDisconnected(void);
//接收聊天消息的槽函数
void slotDataReceived(void);
//网络异常处理的槽函数
void slotSockError(QAbstractSocket::SocketError);
private:
bool status;//标记客户端的连接状态,true在线,false离线
QTcpSocket tcpSocket;//和服务器通信的套接字
qint16 port;//服务器通信的端口
QHostAddress serverIP;//服务器通信的IP地址
QString userName;//聊天室的昵称
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Dialog)
{
ui->setupUi(this);
status = false;//初始化连接状态
//和服务器连接时发送connected信号
connect(&tcpSocket,SIGNAL(connected()),
this,SLOT(onConnected()));
//断开连接发送disconnected信号
connect(&tcpSocket,SIGNAL(disconnected()),
this,SLOT(onDisconnected()));
//当服务器发送数据过来时发送readyRead信号
connect(&tcpSocket,SIGNAL(readyRead()),
this,SLOT(slotDataReceived()));
//网络异常,发送error
connect(&tcpSocket,
SIGNAL(error(QAbstractSocket::SocketError)),
this,
SLOT(slotSockError(QAbstractSocket::SocketError)));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_connectButton_clicked()
{
if(status == false){//当前没有连接,建立连接
//从界面获取IP、用户名、PORT
QString ip = ui->serverIpEdit->text();
if(serverIP.setAddress(ip) == false){
QMessageBox::information(
this,"错误","请输入正确的IP地址");
return;
}
if(ui->userNameEdit->text() == ""){
QMessageBox::information(
this,"错误","请输入用户名");
return;
}
userName = ui->userNameEdit->text();
if(ui->portEdit->text() == ""){
QMessageBox::information(
this,"错误","请输入正确的端口");
return;
}
port = ui->portEdit->text().toShort();
//连接服务器
tcpSocket.connectToHost(ip,port);
status = true;//标记为在线状态
}
else{
//发送下线消息
QString msg = userName+":离开聊天室";
tcpSocket.write(msg.toUtf8());
//关闭和服务器的连接
tcpSocket.disconnectFromHost();
status = false;//标记为离线状态
}
}
//和服务器连接时调用的槽函数
void Dialog::onConnected(void)
{
//使能发送消息按钮
ui->sendButton->setEnabled(true);
//连接服务器 按钮文本改为 离开服务器
ui->connectButton->setText(tr("离开服务器"));
//禁用:ip port 用户名输入
ui->serverIpEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
ui->userNameEdit->setEnabled(false);
//向服务器发送一条进入聊天室消息
QString msg = userName+":进入聊天室";
// tcpSocket.write(msg.toUtf8());
tcpSocket.write(msg.toUtf8());
}
//和服务器断开连接调用的槽函数
void Dialog::onDisconnected(void)
{
//禁用发送消息按钮
ui->sendButton->setEnabled(false);
//使能ip port 用户 输入
ui->serverIpEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
ui->userNameEdit->setEnabled(true);
ui->connectButton->setText("连接服务器");
}
//接收聊天消息的槽函数
void Dialog::slotDataReceived(void)
{
if(tcpSocket.bytesAvailable()){
QByteArray buf;
buf.resize(tcpSocket.bytesAvailable());
tcpSocket.read(buf.data(),buf.size());
//显示消息到界面
QString msg = buf.data();
ui->listWidget->addItem(msg);
}
}
//网络异常处理的槽函数
void Dialog::slotSockError(
QAbstractSocket::SocketError){
QMessageBox::critical(this,"网络异常",
tcpSocket.errorString());
}
void Dialog::on_sendButton_clicked()
{
//获取用户输入的消息
if(ui->sendEdit->text() == ""){
return;
}
QString msg = userName + ":" + ui->sendEdit->text();
//发送消息到服务器
tcpSocket.write(msg.toUtf8());
//清空消息
ui->sendEdit->clear();
}
main.cpp
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
dialog.ui设计
服务器端不需要UI,客户端的设计只要把dialog.cpp复制到QT,那些有红色下划线的就是按键名字和编辑框名字,注意连接槽。
serverIpEdit、userNameEdit、portEdit、sendButton、connectButton、listWidget、sendEdit