QT之局域网聊天实现

功能:

1.用户注册登录功能

2.群聊功能

3.私聊功能

客户端代码:

//tcpclient.h
#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QMainWindow>
#include <QtNetwork>
#include <QMessageBox>
//#include "userinterface.h"

namespace Ui {
class TcpClient;
}

class TcpClient : public QMainWindow
{
    Q_OBJECT

public:
    explicit TcpClient(QWidget *parent = 0);
    ~TcpClient();

protected:
    void init();
    void connectServer();

private slots:
    void on_sendBtn_clicked();

    void displayError(QAbstractSocket::SocketError);

    void on_signBtn_clicked();

    void readMessages();

private:
    Ui::TcpClient *ui;
    QTcpSocket *tcpSocket;
    int readFlag;
    //UserInterface *user;
};

#endif // TCPCLIENT_H

//tcpclient.cpp
#include "tcpclient.h"
#include "ui_tcpclient.h"
#include "userinterface.h"

#define ip "192.168.1.165"
//#define ip "127.0.0.1"
#define port 8000

TcpClient::TcpClient(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::TcpClient)
{
    readFlag=1;
    ui->setupUi(this);
    ui->passwardLineEdit->setEchoMode(QLineEdit::Password);  //密码方式显示文本
    init();
    connectServer();
}

TcpClient::~TcpClient()
{
    delete ui;
}

void TcpClient::init()
{
    tcpSocket=new QTcpSocket(this);
    connect(tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
            this,SLOT(displayError(QAbstractSocket::SocketError)));   //发生错误时执行displayError函数
}

void TcpClient::connectServer()
{
    tcpSocket->abort();   //取消已有的连接
    tcpSocket->connectToHost(ip,port);
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readMessages()));
}

void TcpClient::on_sendBtn_clicked()
{
    QString userName=ui->userLineEdit->text();
    QString passward=ui->passwardLineEdit->text();
    if(userName=="" || passward=="")
        QMessageBox::information(this,"警告","输入不能为空",QMessageBox::Ok);
    QString bs="b";
    QString data=bs+"#"+userName+"#"+passward;
    tcpSocket->write(data.toLatin1());
}


void TcpClient::on_signBtn_clicked()
{
    QString userName=ui->userLineEdit->text();
    QString passward=ui->passwardLineEdit->text();
    if(userName=="" || passward=="")
        QMessageBox::information(this,"警告","输入不能为空",QMessageBox::Ok);
    QString as="a";
    QString data=as+"#"+userName+"#"+passward;
    tcpSocket->write(data.toLatin1());
}


void TcpClient::displayError(QAbstractSocket::SocketError)
{
    qDebug()<<tcpSocket->errorString();   //输出出错信息
}


void TcpClient::readMessages()
{
    if(readFlag==0)
        return;
    QString data=tcpSocket->readAll();
    QStringList list=data.split("#");
    if(list[0]=="a" && list[2]=="true")
        QMessageBox::information(this,"信息提示","注册成功!",QMessageBox::Ok);
    else if(list[0]=="a" && list[2]=="false")
        QMessageBox::information(this,"信息提示","注册失败,用户名已经被注册!",QMessageBox::Ok);
    else if(list[0]=="b" && list[2]=="true")
        //QMessageBox::information(this,"信息提示","登录成功!",QMessageBox::Ok);
    {
        UserInterface *user=new UserInterface(this,tcpSocket,list[1]);
        this->close();
        user->show();
        readFlag=0;
    }
    else if(list[0]=="b" && list[2]=="false")
            QMessageBox::information(this,"信息提示","登录失败,用户名或密码错误!",QMessageBox::Ok);
    else
        return;
}

//userinterface.h
#ifndef USERINTERFACE_H
#define USERINTERFACE_H

#include <QMainWindow>
#include <QTcpSocket>
#include "personaldialog.h"
#include <QMap>


namespace Ui {
class UserInterface;
}

class UserInterface : public QMainWindow
{
    Q_OBJECT

public:
    explicit UserInterface(QWidget *parent = 0,QTcpSocket *pTcpSocket=0,QString _name="");
    ~UserInterface();

private slots:
    void readMessages();

    void on_pushButton_clicked();

    void on_refreshBtn_clicked();

    void on_listWidget_doubleClicked(const QModelIndex &index);

private:
    Ui::UserInterface *ui;
    QTcpSocket *tcpSocket;
    QString name;
    QStringList onlineUser;

    //PersonalDialog *PD;
    QMap<QString,PersonalDialog*> pdList;
};

#endif // USERINTERFACE_H

//userinterface.cpp
#include "userinterface.h"
#include "ui_userinterface.h"

UserInterface::UserInterface(QWidget *parent,QTcpSocket *pTcpSocket,QString _name) :
    QMainWindow(parent),tcpSocket(pTcpSocket),name(_name),
    ui(new Ui::UserInterface)
{
    ui->setupUi(this);
    this->setWindowTitle("Chat Room");
    ui->textEdit->setReadOnly(true);
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readMessages()));
}

UserInterface::~UserInterface()
{
    delete ui;
}

void UserInterface::readMessages()
{
    QByteArray temp=tcpSocket->readAll();
    QString data=QString::fromLocal8Bit(temp);
    //QString data=tcpSocket->readAll();
    QStringList list=data.split("#");
    if(list[0]=="c")
    {
        QString str1=list[1]+":";
        ui->textEdit->append("<font color=red>"+str1+"</font>");
        ui->textEdit->append(list[2]);
    }
    else if(list[0]=="d")
    {
        ui->listWidget->clear();
        onlineUser.clear();
        for(int i=1;i<list.size();i++)
        {
            if(list[i]==name)
                continue;
            ui->listWidget->addItem(list[i]);
            onlineUser.append(list[i]);
        }
    }
    else if(list[0]=="e")
    {
        //判断发送消息用户名是否在pdList里面,如果不在,新建一个PersonalDialog对象
        if(!pdList.contains(list[1]))
        {
            qDebug()<<list[1]<<name;
            PersonalDialog *temp=new PersonalDialog(this,tcpSocket,list[1],name);
            pdList.insert(list[1],temp);
            temp->show();
        }
        pdList[list[1]]->getMessage(list[1],list[3]);
    }
    else
        return;
}


void UserInterface::on_pushButton_clicked()
{
    QString str=ui->lineEdit->text();
    ui->textEdit->append("<font color=blue> 自己: </font>");
    ui->textEdit->append(str);
    QString message="c#"+name+"#"+str;
    QByteArray data=message.toLocal8Bit();/*******/
    tcpSocket->write(data);
    //tcpSocket->write(message.toLatin1());
    ui->lineEdit->clear();
}

void UserInterface::on_refreshBtn_clicked()
{
    QString message="e#getUserList";
    tcpSocket->write(message.toLatin1());
}

void UserInterface::on_listWidget_doubleClicked(const QModelIndex &index)
{
    QString str=onlineUser.at(index.row());  //获得用户名
    //QString message="f#"+str;
    //tcpSocket->write(message.toLatin1());
    PersonalDialog *temp=new PersonalDialog(this,tcpSocket,str,name);
    pdList.insert(str,temp);
    pdList[str]->show();
    pdList[str]->setNameText(str);
}

//personaldialog.h
#ifndef PERSONALDIALOG_H
#define PERSONALDIALOG_H

#include <QDialog>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QNetworkInterface>

namespace Ui {
class PersonalDialog;
}

class PersonalDialog : public QDialog
{
    Q_OBJECT

public:
    explicit PersonalDialog(QWidget *parent = 0,QTcpSocket *_tcp=0,QString _oppositeName=0,QString _selfName=0);
    ~PersonalDialog();

    QString oppositeName;
    void setNameText(QString name);

    void getMessage(QString name,QString message);

private slots:
    void on_pushButton_send_clicked();

    void on_pushButton_sendFile_clicked();

private:
    Ui::PersonalDialog *ui;
    QTcpSocket *tcp;
    QUdpSocket *udp;

    QString selfName;
};

#endif // PERSONALDIALOG_H

//personaldialog.cpp
#include "personaldialog.h"
#include "ui_personaldialog.h"

PersonalDialog::PersonalDialog(QWidget *parent,QTcpSocket *_tcp,QString _oppositeName,QString _selfName) :
    QDialog(parent),tcp(_tcp),oppositeName(_oppositeName),selfName(_selfName),
    ui(new Ui::PersonalDialog)
{
    ui->setupUi(this);
    this->setWindowTitle(tr("私人聊天..."));
    ui->textEdit->setReadOnly(true);
}

PersonalDialog::~PersonalDialog()
{
    delete ui;
}

void PersonalDialog::on_pushButton_send_clicked()
{
    QString data1=ui->lineEdit->text();
    ui->lineEdit->clear();
    ui->textEdit->append(selfName);
    ui->textEdit->append(data1);
    QString data2="d#"+selfName+"#"+oppositeName+"#"+data1;
    tcp->write(data2.toLatin1());
}

void PersonalDialog::on_pushButton_sendFile_clicked()
{

}


void PersonalDialog::getMessage(QString name, QString message)
{
    setNameText(name);
    ui->textEdit->append(name);
    ui->textEdit->append(message);
}

void PersonalDialog::setNameText(QString name)
{
    ui->lineEdit_name->setText(name);
}

服务端代码:

//mysql.h
#ifndef MYSQL_H
#define MYSQL_H

#include <QSql>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>

class MySql
{
public:
    MySql();
    void initsql();
    void createtable();
    bool loguser(QString name,QString passward);
    bool signup(QString name,QString passward);

private:
    QSqlQuery *query;
};

#endif // MYSQL_H

//mysql.cpp
#include "mysql.h"

MySql::MySql()
{

}

void MySql::initsql()
{
    QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("127.0.0.1");
    db.setUserName("root");
    db.setPassword("******");
    db.setDatabaseName("User");
    if(db.open())
        {
            qDebug()<<"Database connected successfully!";
            createtable();
            return;
        }
    else
        {
            qDebug()<<"Database connected failed!";
            return;
        }
}

void MySql::createtable()
{
    query=new QSqlQuery;

    query->exec("create table user(name VARCHAR(30) PRIMARY KEY UNIQUE NOT NULL,passward VARCHAR(30))");

    /*创建root用户*/
    query->exec("insert into user value('root', 'root')");
}


bool MySql::loguser(QString name, QString passward)
{
    QString str=QString("select * from user where name='%1' and passward='%2'").arg(name).arg(passward);
    query=new QSqlQuery;
    query->exec(str);
    query->last();
    int record=query->at()+1;
    if(record==0)
        return false;
    return true;
}


bool MySql::signup(QString name,QString passward)
{
    QString str=QString("select * from user where name='%1").arg(name);
    query=new QSqlQuery;
    query->exec(str);
    query->last();
    int record=query->at()+1;
    if(record!=0)
        return false;
    str=QString("insert into user value('%1','%2')").arg(name).arg(passward);
    bool ret=query->exec(str);
    return ret;
}

//tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H

#include <QMainWindow>
#include <QtNetwork>
#include <QTimer>
#include <QMap>

namespace Ui {
class TcpServer;
}

class TcpServer : public QMainWindow
{
    Q_OBJECT

public:
    explicit TcpServer(QWidget *parent = 0);
    ~TcpServer();

    bool checkSignIn(QString name,QString passward);
    bool checkSignUp(QString name,QString passward);

signals:
    void userNumChange();

private slots:
    void on_startBtn_clicked();

    void acceptConnection();

    void receiveData();

    void removeUserFormList();

    void sendUserList();

private:
    Ui::TcpServer *ui;
    //QTcpSocket *tcpSocket;
    QTcpServer *tcpServer;
    QTimer *timer;
    //QList<QTcpSocket *> userList;
    QMap<QTcpSocket *,QString> userMessage;
};

#endif // TCPSERVER_H

//tcpserver.cpp
#include "tcpserver.h"
#include "ui_tcpserver.h"
#include "mysql.h"

TcpServer::TcpServer(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::TcpServer)
{
    ui->setupUi(this);
    this->tcpServer=new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));
    connect(this,SIGNAL(userNumChange()),this,SLOT(sendUserList()));
}

TcpServer::~TcpServer()
{
    delete ui;
}


void TcpServer::receiveData()
{
    QTcpSocket *tempTcp=static_cast<QTcpSocket*>(sender());
    QString data=tempTcp->readAll();
    qDebug()<<data;
    QStringList list=data.split("#");
    bool ret=0;
    if(list[0]=="a")     //注册
        ret=checkSignUp(list[1],list[2]);
    else if(list[0]=="b")  //登录
    {
        ret=checkSignIn(list[1],list[2]);
        if (ret)
        {
            userMessage.insert(tempTcp,list[1]);
            connect(tempTcp,SIGNAL(disconnected()),this,SLOT(removeUserFormList()));
        }
    }
    else if(list[0]=="c")
    {
        QMap<QTcpSocket*,QString>::iterator it=userMessage.begin();
        QString message="c#"+list[1]+"#"+list[2];
        while(it!=userMessage.end())
        {
            QTcpSocket *tcp=it.key();
            if(tcp!=tempTcp)
                tcp->write(message.toLatin1());
            ++it;
        }
        return;
    }
    else if(list[0]=="d")
    {
        //userMessage[list[2]]->write(list[1]+"#"+list[3]);
        QMap<QTcpSocket*,QString>::iterator it=userMessage.begin();
        QTcpSocket *tcp=NULL;
        while(it!=userMessage.end())
        {
            if(it.value()==list[2])
            {
                tcp=it.key();
                break;
            }
            ++it;
        }
        if(tcp==NULL)
            return;
        QString mes="e#"+list[1]+"#"+list[2]+"#"+list[3];
        tcp->write(mes.toLatin1());
        return;
    }
    else if(list[0]=="e")
    {
        emit sendUserList();
        return;
    }
    else
        return;
    QString sendData=list[0];
    if(ret)
        sendData+="#"+list[1]+"#true";
    else
        sendData+="#"+list[1]+"#false";
    tempTcp->write(sendData.toLatin1());
}

void TcpServer::on_startBtn_clicked()
{
    ui->startBtn->setEnabled(false);
    if(!tcpServer->listen(QHostAddress::Any,8000))
    {
        qDebug()<<tcpServer->errorString();
        close();
        return;
    }
}


void TcpServer::acceptConnection()
{
    QTcpSocket *tcp=tcpServer->nextPendingConnection();
    //QString ip=tcp->peerAddress().toString();
    //qDebug()<<ip;
    connect(tcp,SIGNAL(readyRead()),this,SLOT(receiveData()));   //**********
}

/*
void TcpServer::displayError(QAbstractSocket::SocketError)
{
    qDebug()<<tcpSocket->errorString();
    tcpSocket->close();
}*/



bool TcpServer::checkSignIn(QString name,QString passward)
{
    MySql *mysql=new MySql();
    bool ret=mysql->loguser(name,passward);
    if(ret)
    {
        ui->listWidget->addItem(name);
    }
    return ret;
}

bool TcpServer::checkSignUp(QString name, QString passward)
{
    MySql *mysql=new MySql();
    bool ret=mysql->signup(name,passward);
    return ret;
}


void TcpServer::removeUserFormList()
{
    QTcpSocket* socket = static_cast<QTcpSocket*>(sender());
    QString name=userMessage[socket];
    QList<QListWidgetItem*> list;
    list=ui->listWidget->findItems(name,Qt::MatchCaseSensitive);
    QListWidgetItem *sel=list[0];
    int r=ui->listWidget->row(sel);
    QListWidgetItem *item=ui->listWidget->takeItem(r);
    ui->listWidget->removeItemWidget(item);
    delete item;


    userMessage.remove(socket);
    emit userNumChange();
}


void TcpServer::sendUserList()
{
    QString message="d";
    QMap<QTcpSocket*,QString>::iterator it=userMessage.begin();
    while(it!=userMessage.end())
    {
        message+="#";
        message+=it.value();
        ++it;
    }
    if(message=="d")
        return;
    it=userMessage.begin();
    while(it!=userMessage.end())
    {
        it.key()->write(message.toLatin1());
        ++it;
    }
    //qDebug()<<message;
}

运行截图:

消息格式:

客户端->服务器端:
注册:a#注册名#注册密码
登录:b#登录名#登录密码
群消息:c#发送者#消息
私人消息:d#发送者#接受者用户名#消息
获得在线用户名单:e#getUserList


服务器端->客户端
注册成功:a#注册名#true
注册失败:a#注册名#false
登录成功:b#登录名#true
登录失败:b#登录名#false
群消息/私人消息:c#发送者#消息
发送在线名单:d#用户名1#用户名2#...
转发私人消息:e#发送者#接收者#消息

  • 9
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: 为了使用Qt框架实现局域网聊天室,我们可以使用UDP协议进行通信。UDP是一种面向无连接的传输协议,适用于传输不需要高可靠性和有序到达的数据。 首先,我们需要创建一个UDP的Socket,并绑定到一个合适的端口。接下来,我们可以使用Qt提供的信号与槽机制来处理接收到的消息。 为了实现聊天室功能,我们需要至少两个应用实例,一个用作服务器,另一个用作客户端。当客户端启动时,它将向服务器发送一个加入聊天室的请求。 当服务器接收到一个加入请求时,它可以将发送者的IP地址和端口存储在一个列表中,以便之后可以将消息广播给所有的聊天室成员。 当一个客户端发送一条消息时,它将将消息发送给服务器,服务器收到消息后,将消息广播给所有已连接的客户端。客户端接收到广播后,可以将消息显示在聊天窗口中。 需要注意的是,UDP是无连接的协议,因此在实现聊天室时,需要处理丢包和乱序的问题。可以使用一些技术,如序列号、心跳检测等来解决这些问题。 此外,为了提高用户体验,我们还可以在聊天室中实现一些额外的功能,如私聊、文件传输等。 总之,通过使用Qt和UDP协议,我们可以很容易地实现一个简单的局域网聊天室。使用UDP协议可以简化通信过程,并提供轻量级的通信方式。不过也要注意到UDP的不可靠性,需要在实现中考虑丢包和乱序问题。 ### 回答2: Qt是一个跨平台的C++应用程序开发框架,可以用于开发各种类型的应用程序,包括局域网聊天室。首先要实现局域网聊天室,需要使用UDP协议进行通信,因为UDP是无连接的、不可靠的传输协议,适合于实时性要求较高的应用。 在Qt中,可以使用QUdpSocket类来实现UDP通信。首先,需要创建一个QUdpSocket对象,并绑定到本地IP和端口上。接下来,可以通过该对象的bind函数将socket绑定到指定的本地IP和端口上。然后,可以使用该对象的readDatagram函数接收其他主机发送过来的消息,并使用writeDatagram函数发送消息给其他主机。 在局域网聊天室中,需要实现多个主机之间的消息传递。可以使用多线程来处理消息接收和发送的操作,以免阻塞主线程。可以创建一个接收线程,通过QUdpSocket来接收其他主机发送的消息,并将接收到的消息发送给主线程进行处理。同时,可以创建一个发送线程,用于向其他主机发送消息。 在主线程中,可以使用Qt的信号和槽机制来处理接收到的消息。当接收线程接收到消息后,可以通过信号将消息传递给主线程,并在主线程中的槽函数中进行处理,例如显示在用户界面上。当用户在界面上输入消息后,可以通过发送线程将消息发送给其他主机。 总结起来,使用Qt的QUdpSocket类可以方便地实现局域网聊天室。通过创建多线程,利用信号和槽机制处理接收和发送的消息,可以实现实时的消息传递。使用UDP协议可以满足聊天室的实时性要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值