2023/4/10 TCP实现多人聊天室网络

1.客户端执行代码

#include "work.h"
#include "ui_work.h"

Work::Work(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::Work)
{
    ui->setupUi(this);
    ui->btn_2->setEnabled(false);
    //图片设置圈
    /**************************/
    ui->label_2->setPixmap(QPixmap(":/chick.png"));
    ui->label_2->setScaledContents(true);


    ui->label_3->setPixmap(QPixmap(":/chick_1.png"));
    ui->label_3->setScaledContents(true);
    /**************************/

    server = new QTcpServer(this); //给服务器指针申请指针
}

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

//启动服务器连接按钮后的槽函数
void Work::on_btn_1_clicked()
{

    if(ui->btn_1->text()=="创  建  家  族")
    {

    //1.设置端口号,转成网络字节序,toUint
    int num=8888;
    quint16 port=quint16(num);//将主机字节序转变成网络字节序
    //listen 将服务设置监听状态,
    //参数1,连接的主机地址,填写QHostaddress::any 任何主机可以连接
    //参数2.连接的主机端口号,0表示所有
    //返回值bool类型
    if(server->listen(QHostAddress::Any,port))
    {
        QMessageBox::information(this,"服务器","连接成功");
    }else
    {
        QMessageBox::information(this,"服务器","连接失败");
    }

    ui->btn_1->setEnabled(false);//将按钮设置为不可用状态
    ui->btn_2->setEnabled(true);

    //如果有客户端发来连接请求,服务器会触发一个newconnect信号,转到相应的槽函数,进行处理
    connect(server,&QTcpServer::newConnection,this,&Work::newconnect);
    }



}

//接受客户端的信号,以及链表存储客户端的套接字
void Work::newconnect()
{
    //获取客户端的套接字 nextpendingConnection
    QTcpSocket *const s=server->nextPendingConnection();
    //将套接字存储在链表当中
    list.push_back(s);
    //客户端与服务器建立连接成功以后,客户端会发送一个readyRead,转到相应的槽函数,处理与客户端的交互
    //为该套接字添加快速启用端口

    connect(s,&QTcpSocket::readyRead,this,&Work::readyRead);
}


//关闭服务流程
void Work::on_btn_2_clicked()
{
   if(ui->btn_2->text()=="关  闭  家  族")
        {
            //停止监听
            server->close();
            //关闭链表中所有存储的客户端
            for(int i=0;i<list.size();i++)
            {
                if(list[i]->state()==QAbstractSocket::UnconnectedState)//客户端是否点开连接
                {
                    list[i]->deleteLater();//释放客户端的套接字
                }
                else
                {
                list[i]->disconnectFromHost();//关闭与客户端的连接
                list[i]->deleteLater();//释放客户端的套接字
                }
            }
            //释放服务器的资源
            list.clear();//清空链表
            server->deleteLater();//释放服务器的资源
            ui->btn_2->setEnabled(false);//将按钮设置为不可用状态
            ui->btn_1->setEnabled(true);
            QMessageBox::information(this,"服务器","关闭成功");
   }
}

//处理与客户端的交互
void Work::readyRead()
{
    //循环删除已经断开连接的客户端
    for(int i=0;i<list.size();i++)
    {
        if(list.at(i)==0)//表示客户端已经断开
        {
            list[i]->deleteLater();//将元素标记为待删除状态
            QCoreApplication::processEvents();//等待时间循环处理目前时间,包括垃圾回收,防止remove未实现其效果
            list.removeAt(i);//让后续元素前移,填补空缺

        }
    }

    //判断是哪个客户端中有信息
    for(int i=0;i<list.size();i++)
    {
        if(list.at(i)->bytesAvailable()!=0)//表示该客户端中有信息
        {
            QByteArray read_s=list.at(i)->readAll();

            ui->list_1->addItem(QString::fromLocal8Bit(read_s)); //将读取到的信息展示到自身的ui界面


        for(int j=0;j<list.size();j++)
        {
            list.at(j)->write(read_s);//将所有信息展示到客户端界面上
        }
        }
    }
}

 2.客户端示例图

 3.客户端执行 代码

#include "work_cli.h"
#include "ui_work_cli.h"

work_cli::work_cli(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::work_cli)
{
    ui->setupUi(this);

    ui->label_2->setPixmap(QPixmap(":/2.png"));
    ui->label_2->setScaledContents(true);

    ui->label_3->setPixmap(QPixmap(":/4.png"));
    ui->label_3->setScaledContents(true);

    ui->line_1->setEnabled(false);//设置不可用
    ui->btn_1->setEnabled(false);//设置不可用

    //实例化客户端类对象
    socket=new QTcpSocket(this);

    //连接到服务器
    connect(socket,&QTcpSocket::connected,this,&work_cli::connectted);

    //服务器接收到客户端的信息以后,会发出一个readyRead信号
    connect(socket,&QTcpSocket::readyRead,this,&work_cli::readyRead);

}

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

//点击连接服务器后对应的槽函数
void work_cli::on_btn_2_clicked()
{

    if(ui->btn_2->text()=="加入家族")
    {

    QString IP= ui->line_3->text();
    quint16 port=ui->line_4->text().toUInt();
    socket->connectToHost(IP,port);//连接到服务器,如果成功,会发送一个connected信号
    ui->btn_2->setText("离开家族");

    }
    else if(ui->btn_2->text()=="离开家族")
    {
        QString msg=ui->line_2->text()+":离开聊天室";
        socket->write(msg.toLocal8Bit());
        socket->disconnectFromHost();

        QMessageBox::information(this,"家族","成功退出");
         ui->btn_2->setText("加入家族");
        ui->line_2->setEnabled(true);
        ui->line_3->setEnabled(true);
        ui->line_4->setEnabled(true);
        ui->line_1->setEnabled(false);
        ui->btn_1->setEnabled(false);
    }
}

void work_cli::connectted()
{
    qDebug()<<"kkkk";
    QMessageBox::information(this,"家族","成功连接");
    QString msg=ui->line_2->text()+":加入聊天室";
    socket->write(msg.toLocal8Bit());


    ui->line_2->setEnabled(false);
    ui->line_3->setEnabled(false);
    ui->line_4->setEnabled(false);
    ui->line_1->setEnabled(true);//设置不可用
    ui->btn_1->setEnabled(true);
}

//readyRead函数对应的槽函数
void work_cli::readyRead()
{
    //将服务器发给自己的信息全部展示到ui界面上
    QByteArray msg = socket->readAll();
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}

//发送按钮对应的槽函数
void work_cli::on_btn_1_clicked()
{
    QString msg=ui->line_2->text()+":"+ui->line_1->text();
    ui->line_1->clear();
    socket->write(msg.toLocal8Bit());
}

4.客户端示例图

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现一个多人聊天室需要涉及到网络编程以及并发编程。在Python中,可以通过TCP协议来实现多人聊天室。 下面是一个跨主机的Python+TCP实现多人聊天室的简单示例代码: ```python import socket import threading # 服务器IP地址和端口号 SERVER_HOST = '0.0.0.0' SERVER_PORT = 8000 # 客户端列表 clients = [] def broadcast(message): """ 广播消息给所有客户端 """ for client in clients: client.send(message) def handle_client(client): """ 处理客户端连接 """ while True: try: message = client.recv(1024) if message: print(f"[{client.getpeername()}]: {message.decode('utf-8')}") message_to_broadcast = f"[{client.getpeername()}]: {message.decode('utf-8')}".encode('utf-8') broadcast(message_to_broadcast) else: remove(client) except: remove(client) def remove(client): """ 客户端断开连接 """ if client in clients: clients.remove(client) client.close() if __name__ == "__main__": # 创建服务器套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((SERVER_HOST, SERVER_PORT)) server_socket.listen() print(f"[*] Listening on {SERVER_HOST}:{SERVER_PORT}") while True: client_socket, client_address = server_socket.accept() print(f"[*] Accepted connection from {client_address[0]}:{client_address[1]}") clients.append(client_socket) client_thread = threading.Thread(target=handle_client, args=(client_socket,)) client_thread.start() ``` 在上述代码中,我们使用了Python的socket模块来创建TCP服务器和客户端套接字,使用了Python的threading模块来进行并发处理。我们定义了一个`broadcast`函数来广播消息给所有客户端,定义了一个`handle_client`函数来处理客户端连接,定义了一个`remove`函数来处理客户端断开连接。 在`handle_client`函数中,我们使用了一个死循环来持续处理客户端发送的消息。当接收到消息时,我们使用`broadcast`函数将该消息广播给所有客户端。当客户端断开连接时,我们使用`remove`函数将该客户端从客户端列表中移除。 在`__main__`函数中,我们创建服务器套接字,监听客户端连接。当有新的客户端连接时,我们将其添加到客户端列表中,并使用一个新的线程来处理该客户端连接。 这是一个简单的跨主机Python+TCP实现多人聊天室的示例代码,你可以在此基础上进行扩展和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值