用qt实现一个网络服务器

  • 服务器程序
  • 最终结果
  • 客户端程序
  • 成果


服务器程序

//server.h
#pragma once
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QList>
#include <QTimer>
#include <iostream>
class server : public QObject
{
    Q_OBJECT
private:
    QTcpServer tcpServer;
    quint16 port;                      //服务器端口
    QList<QTcpSocket *> tcpClientList; //保存所有和客户端通信的套接字
    QTimer timer;

public:
    void startServer(int port);
    explicit server(QObject *parent = 0);
    ~server();
public slots:
    void onNewConnection(); //响应客户端连接请求的函数
    void onReadyRead();     //接收客户端消息的槽函数
    void sendMessage(const QByteArray &buf);

    //定义时间超出的槽函数
    void onTimeOut(void);
};
//server.cpp
#include "server.h"
void server::onNewConnection() //响应客户端连接请求的函数
{
    //保存套接字到容器
    QTcpSocket *tcpClient = tcpServer.nextPendingConnection();
    tcpClientList.append(tcpClient);
    //当客户端向服务器发送信息时,通信套接字发送信号:readyRead
    connect(tcpClient, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}
void server::onReadyRead() //接收客户端消息的槽函数
{
    //遍历容器哪个客户端给服务器发送了消息
    for (int i = 0; i < tcpClientList.size(); i++)
    {
        // bytesAvailable:获取当前套接字等待读取消息字节数
        //返回0表示没有消息
        //返回大于0说明当前套接字有消息到来
        if (tcpClientList.at(i)->bytesAvailable())
        {
            //读取消息并保存
            QByteArray buf = tcpClientList.at(i)->readAll();
            qDebug() << buf;
            sendMessage(buf);
        }
    }
}
//发送消息的槽函数
void server::sendMessage(const QByteArray &buf)
{
    //发送给所有建立连接的人
    for (int i = 0; i < tcpClientList.size(); i++)
    {
        //发送消息
        tcpClientList.at(i)->write(buf);
    }
}
void server::startServer(int port)
{
    this->port = port;
    if (tcpServer.listen(QHostAddress::Any, port) == true)
    {
        qDebug() << "Server starts success, listening port number is" << port << ".";
        //开启定时器
        timer.start(3000);
    }
    else
    {
        qDebug() << "The server starts failed, please confirm if the port number is occupied.";
    }
}
void server::onTimeOut(void)
{
    unsigned int tcpClientSize = tcpClientList.size();
    qDebug()<<"当前连接数:"<<tcpClientSize;
    //遍历检查容器中保存的客户端通信套接字是否已经断开连接,如果是则删除
    for (unsigned int i = 0; i < tcpClientSize; i++)
    {
        if (tcpClientList.at(i)->state() == QAbstractSocket::UnconnectedState) // state是套接字状态,用来标识连接状态
        {
            tcpClientList.removeAt(i);
            --i;             //保证删除掉一个元素后依旧能遍历全部元素
            --tcpClientSize; //删除掉一个后元素量也少了一个
        }
    }
    //容器
}
server::server(QObject * parent):QObject(parent)
{
    //当有客户端向服务器发送连接请求,发送信号:newConnection
    connect(&tcpServer, SIGNAL(newConnection()),
                     this, SLOT(onNewConnection()));
    //定时器到时发送信号:timeout
    connect(&timer, SIGNAL(timeout()),
                     this, SLOT(onTimeOut()));
}
server::~server()
{
    qDebug()<<"stop server";
}
//main.cpp
#include <QCoreApplication>
#include "dbServer.h"
int main(int argc, char *argv[])
{
    QCoreApplication server(argc,argv);
    dbServer *test = new dbServer();
    test->startServer(8081);
    return server.exec();
}

最终结果

QT 开发ios qt 开发服务器_c++

客户端程序

//dialog.h
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = nullptr);
    ~Dialog();
public slots:
    //发送按钮对应的槽函数
    void on_sendButton_clicked();
    //连接服务器按钮对应的槽函数
    void on_connectButton_clicked();
    //和服务器连接成功的槽函数
    void onConnected();
    //和服务器连接断开时执行的槽函
    void onDisconnected();
    //接收聊天消息的槽函数
    void onReadyRead();
    //网络异常执行的槽函数
    void onError();
private:
    Ui::Dialog *ui;
    bool status;//标识状态:在线还是离线
    QTcpSocket tcpSocket;//和服务器通信的套接字
    QHostAddress serverIP;//服务器地址
    quint16 serverPort;
    QString username;
};
#endif // DIALOG_HA
//dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    status = false;//离线状态
    connect(&tcpSocket,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
    connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
    connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(onError()));
}

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

//发送按钮对应的槽函数
void Dialog::on_sendButton_clicked()
{
    qDebug()<<"1";
    //获取用户输入的聊天消息
    QString msg = ui->messageEdit->text();
    if(msg == "")
    {
        return ;
    }
    msg = username + ":" + msg;
    //发送消息
    tcpSocket.write(msg.toUtf8());
    //清空消息输入框
    ui->messageEdit->clear();
    qDebug()<<"1";
}

//连接服务器按钮对应的槽函数
void Dialog::on_connectButton_clicked()
{
    qDebug()<<"2";
    //如果是离线状态,则建立和服务器连接
    if(status == false)
    {
        //获取服务器IP地址
        serverIP.setAddress(ui->serverIpEdit->text());
        qDebug()<<serverIP;
        //获取服务器端口
        serverPort = ui->serverPortEdit->text().toUShort();
        qDebug()<<serverPort;
        //获取聊天室称呼
        username = ui->usernameEdit->text();
        qDebug()<<username;
        //向服务器发送连接请求
        tcpSocket.connectToHost(serverIP,serverPort);
        //成功发送信号:connected
        //失败发送信号:error
    }
    //如果时在线状态,则断开连接
    else
    {
        qDebug()<<"断开连接";
        //向服务器发送离开聊天室的提示消息
        QString msg = username + "离开聊天室";
        tcpSocket.write(msg.toUtf8());
        //关闭和服务器的连接,同时发送信号:disconnected
        tcpSocket.disconnectFromHost();
    }
    qDebug()<<"2";
}
//和服务器连接成功的槽函数
void Dialog::onConnected()
{
    qDebug()<<"3";
    status = true;//更改状态为在线
    ui->sendButton->setEnabled(true);
    ui->serverIpEdit->setEnabled(false);
    ui->serverPortEdit->setEnabled(false);
    ui->usernameEdit->setEnabled(false);
    ui->connectButton->setText("离开聊天室");
    //向服务器发送进入聊天室提示消息
    QString msg = username + "进入聊天室";
    //toUtf8:QString转换为QByteArray
    tcpSocket.write(msg.toUtf8());
    qDebug()<<"3";

}
//和服务器连接断开时执行的槽函
void Dialog::onDisconnected()
{
    qDebug()<<"4";
    status = false;
    ui->sendButton->setEnabled(false);
    ui->serverIpEdit->setEnabled(true);
    ui->serverPortEdit->setEnabled(true);
    ui->usernameEdit->setEnabled(true);
    ui->connectButton->setText("连接服务器");
    qDebug()<<"4";
}
//接收聊天消息的槽函数
void Dialog::onReadyRead()
{
    qDebug()<<"5";
    if(tcpSocket.bytesAvailable())
    {
        //接收消息
        QByteArray buf = tcpSocket.readAll();
        //显示消息
        ui->listWidget->addItem(buf);
        ui->listWidget->scrollToBottom();
    }
    qDebug()<<"5";
}
//网络异常执行的槽函数
void Dialog::onError()
{
    qDebug()<<"6";
    //errorString():获取网络异常的原因
//    QMessageBox::critical(this,"ERROR",tcpSocket.errorString());
    qDebug()<<"6";
}
//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
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>314</width>
    <height>428</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QWidget" name="">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>40</y>
     <width>258</width>
     <height>360</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QListWidget" name="listWidget"/>
    </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QLineEdit" name="messageEdit"/>
      </item>
      <item>
       <widget class="QPushButton" name="sendButton">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>send</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <layout class="QFormLayout" name="formLayout">
      <item row="0" column="0">
       <widget class="QLabel" name="label">
        <property name="text">
         <string>服务器地址</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QLineEdit" name="serverIpEdit">
        <property name="text">
         <string>192.168.10.94</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
         <string>服务器端口</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QLineEdit" name="serverPortEdit">
        <property name="text">
         <string>8081</string>
        </property>
       </widget>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label_3">
        <property name="text">
         <string>称呼</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QLineEdit" name="usernameEdit">
        <property name="text">
         <string>a</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <widget class="QPushButton" name="connectButton">
      <property name="text">
       <string>连接服务器</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

成果

QT 开发ios qt 开发服务器_python_02