主题:基于QT平台利用TCP协议实现的通信

基于QT平台利用TCP协议实现两个应用程序进行通信,是典型的c/s架构,这里仅仅使用单线程,目的是为了了解QT下socket套接字的使用,其实与linux中的套接字使用流程很接近。QT提供QTcpServer类和QTcpSocket类用于建立Tcp通信,服务器端的程序必须使用QTcpServer用于端口监听;使用QTcpSocket用于建立连接后使用套接字可以进行通信。

首先列出框架:

      服务器端(server):                                                                                          客户端(client):

  • 获取主机名称(HostName)                                                                   在设置好需要连接的服务器ip和port之后,使用                                                                                                                             connectToHost()来连接服务器                                                   
  • 获取主机信息(HostInfo)                                                                       建立QTcpSocket各种信号的槽,尤其是readyRead()信号
  • 根据HostInfo获得QList                                                                        
  • 根据QList获得主机的 ip 地址                                                               可以使用read,write进行读写       
  • 使用QTcpServer对象进行监听(listen)
  • 建立QTcpServer的newConnection()信号的槽newConnectionSlot()
  • 在newConnectionSlot()中使用nextPendingConnection() 获得建立连接的QTcpSocket
  • 对QTcpSocket的各个信号建立槽,尤其是readyRead()信号
  • 可以使用read(),write()进行读写

源代码及窗口如下:

服务器:

#ifndef SERVER_H
#define SERVER_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DEBUG
#define BUFSIZE 10000
using namespace std;

namespace Ui {
class Server;
}

class Server : public QWidget
{
    Q_OBJECT

public:
    explicit Server(QWidget *parent = 0);
    ~Server();
    void getHostInfo();

public slots:
    void newConnectSlot();//对应于 QTcpServer中有客户端连接会触发newConnect()信号
//    void newClientConnectSlot();//对应于 有客户端使用connectToHost()函数连接服务器之后,会发出connect()信号
    void readyReadSlot();//对应于 缓冲区中有数据,会发生readyRead信号
    void clientDisconnectSlot();
    void initUI();//初始化窗口控件
    void setIpAndPort(QString ip,QString port);

private slots:
    void on_btn_Send_clicked();

private:
    Ui::Server *ui;
    QTcpServer *server;//服务器
    QTcpSocket *currentClient;//临时建立连接的客户端
    QString    serverIP;//服务器ip
    uint       serverPort = 9999;//服务器port
    char       *readBuf; //读缓冲区
    QString    writeBuf;//写缓冲区
    int        serverReceiveBufSize = 1000;
protected:
    void closeEvent(QCloseEvent *event);
};

#endif // SERVER_H

 

#include "server.h"
#include "ui_server.h"


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

    /* 1.获取主机ip
     * 2.创建QTcpServer
     * 3.建立连接,还要开始监听
     * 4.一旦有连接之后,会发出newConnect信号,立马获取currentClient
     */

    /* 初始化串口控件 */
    initUI();

    /* 1.获取主机ip */
    getHostInfo();

    /* 创建QTcpServer */
    server = new QTcpServer(this);

    /* 3.建立连接,还要开始监听 */
    server->listen(QHostAddress::Any,serverPort);//开始侦听
    connect(server,SIGNAL(newConnection()),this,SLOT(newConnectSlot()));//有新的client连接会触发newConnetSlot槽
    readBuf = (char*)calloc(BUFSIZE,sizeof(char));
}

Server::~Server()
{
    delete ui;
    free(readBuf);
}

/* 初始化串口控件 */
void Server::initUI()
{
   /* 设置服务器端每次最多只能读取多少个Bytes */
   ui->receiver_num->setValue(serverReceiveBufSize);
   ui->receiver_num->setMaximum(BUFSIZE);//一次最多可以读多少

//   ui->comboBox_ip->addItem("0.0.0.0");
//   ui->comboBox_port->addItem("0000");
}

/* 设置服务器Ip和port */
void Server::setIpAndPort(QString ip,QString port)
{
    ui->comboBox_ip->addItem(ip);
    ui->comboBox_port->addItem(port);
}

/* 1.获取主机ip */
void Server::getHostInfo()
{
    QString pcHostName = QHostInfo::localHostName();//获取主机名
    QHostInfo pcHostInfo = QHostInfo::fromName(pcHostName);//获取主机host信息

    QList addList = pcHostInfo.addresses();//本机ip地址列表
    if(!addList.isEmpty())//如果是空,isEmpty()返回true,flase表示非空
    {
        for(int i=0; i < addList.count(); i++)
        {
            QHostAddress hostIP = addList.at(i);//依次遍历出addList中的每一项,也就是ip信息
            if(QAbstractSocket::IPv4Protocol == hostIP.protocol())//需要ipv4
            {
                serverIP = hostIP.toString();//把获取的ip信息从QHostAddress转到QString类型
                qDebug() << "\nserverIP" << serverIP;
                qDebug() << "port    " << serverPort;
                setIpAndPort(serverIP,QString::number(serverPort));
            }
        }
    }
}

/* 一旦有新的client来连接server之后
 * QTcpServer内部的incomingConnection()函数
 * 会创建一个与客户端连接的QTcpSocket对象然后会
 * 发newConnect信号 */
void Server::newConnectSlot()
{
#ifdef DEBUG
    cout << "new client connect" << endl;
#endif
    currentClient = new QTcpSocket(this);
    currentClient = server->nextPendingConnection();//获取临时连接的客户端socket
//    QHostAddress clientip = this->currentClient->peerAddress();
//    QString ip = clientip.toString();
//    qDebug() << " ------------ client ip = " << ip;
    //仅仅在客户端使用connectToHost()之后才会触发connected()信号,服务器端并不会触发这个信号
//    connect(currentClient,SIGNAL(connected()),this,SLOT(newClientConnectSlot()));

    connect(currentClient,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));
    connect(currentClient,SIGNAL(disconnected()),this,SLOT(clientDisconnectSlot()));

    ui->client_status->setText("client connected");
    int originalReadBufSize =  currentClient->readBufferSize();
    qDebug() << "originalReadBufSize = " << originalReadBufSize << endl;
}

/* 有客户端使用connectToHost()函数连接服务器之后,会发出connect()信号
 * newClientConnectSlot()这个槽就是接收连接信号的
 */


void Server::clientDisconnectSlot()
{
    ui->client_status->setText("no connected! ");
}

/* 缓冲区中有数据,会发生readyRead信号,此槽函数读出缓冲区中数据 */
void Server::readyReadSlot()
{
    /* 设置内部读缓冲区大小:5 Bytes,如果不设置好像会无限大(至于是不是无线大,反正qt帮助文档是这么说的)
     * currentClient->setReadBufferSize(5*sizeof(char));
     */
    currentClient->read(readBuf,ui->receiver_num->value());//这里的数字5是我需要读出的个数

    /* 如果客户端发送的数据多余我需要读取的数量,也就是5个,那么把剩余的不要的全部读出去丢掉。
     * 不然剩余的数量任何在缓冲区中,再次在读取接着读而不会读新来的数据,新来的数量排在后面 */
    currentClient->readAll();
    ui->receive_info->setText(readBuf);//在控件中显示接收到的数据

    ui->receive_info->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);//可垂直滚动
    ui->receive_info->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);//可水平滚动
    QTextCursor text_cursor(ui->receive_info->textCursor());//设置光标的位置
    text_cursor.movePosition(QTextCursor::End);
    ui->receive_info->setTextCursor(text_cursor);

#ifdef DEBUG
    qDebug() << "new data:" << readBuf;
#endif

    memset(readBuf,0,BUFSIZE);
}

void Server::on_btn_Send_clicked()
{
    this->writeBuf = (ui->send_info->toPlainText());
    this->currentClient->write(writeBuf.toUtf8().data(),this->writeBuf.length());
}

/* 窗口关闭事件 */
void Server::closeEvent(QCloseEvent *event)
{
    if(this->server->isListening())
        this->server->close();
    if(this->currentClient->isOpen())
    {
        this->currentClient->abort();
    }
}

 主题:基于QT平台利用TCP协议实现的通信_第1张图片

客户端

#ifndef CLIENT_H
#define CLIENT_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DEBUG
#define BUFSIZE 10000

namespace Ui {
class client;
}

class client : public QWidget
{
    Q_OBJECT

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

    void initUi();//初始化UI
public slots:
//    void connectedSlot();//用于接收connectToHost()之后发送的connected()信号
    void on_btn_connect_clicked();
    void readData();//当客户端socket缓冲区有数据,会触发readRead()信号,该槽用于接收此信号
private slots:
    void on_btn_Send_clicked();

    void on_btn_abort_clicked();

private:
    Ui::client *ui;
    QTcpSocket *myclient;//用于连接服务器

    QString    serverIp = "192.168.1.104";
    int        serverPort = 9999;

    char       *readBuf;
    QString    writeBuf;

protected:
    void closeEvent(QCloseEvent *event);
};

#endif // CLIENT_H
#include "client.h"
#include "ui_client.h"

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

    initUi();//初始化UI

    myclient = new QTcpSocket(this);//实例化一个QTcpSocket对象
//    connect(myclient,SIGNAL(connected()),this,SLOT(connectedSlot()));//用于接收connectToHost()之后发送的connected()信号
    connect(this->myclient,SIGNAL(readyRead()),this,SLOT(readData()));//客户端有缓冲区时,会触发readyRead()

    this->readBuf  = (char *)calloc(BUFSIZE,sizeof(char));

}

client::~client()
{
    delete ui;

    free(this->readBuf);
}

void client::initUi()
{
    ui->server_ip->setText(this->serverIp);
    ui->server_port->setText(QString::number(this->serverPort));

    /* 设置按钮状态 */
    ui->btn_abort->setEnabled(false);
    ui->btn_connect->setEnabled(true);

    /* 设置服务器端每次最多只能读取多少个Bytes */
    ui->receive_num->setValue(100);
    ui->receive_num->setMaximum(BUFSIZE);//一次最多可以读多少
}


/* 用于接收readyRead信号 */
void client::readData()
{
    /* 如果客户端发送的数据多余我需要读取的数量,比如就是5个,那么把剩余的不要的全部读出去丢掉。
     * 不然剩余的数量任何在缓冲区中,再次在读取接着读而不会读新来的数据,新来的数量排在后面 */
    int len = ui->receive_num->value();//界面限制的数量
    this->myclient->read(this->readBuf,len);//接收设置的数量
    this->myclient->readAll();//把剩余的全部丢掉

    ui->receive_info->setText(this->readBuf);//在控件中显示接收到的数据

    ui->receive_info->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);//可垂直滚动
    ui->receive_info->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);//可水平滚动
    QTextCursor text_cursor(ui->receive_info->textCursor());//设置光标的位置
    text_cursor.movePosition(QTextCursor::End);
    ui->receive_info->setTextCursor(text_cursor);
}

/* 连接按钮 */
void client::on_btn_connect_clicked()
{
    /* 从界面获取服务器ip和port */
    this->serverIp = ui->server_ip->text();
    this->serverPort = ui->server_port->text().toInt();

    /* 设置按钮显示状态 */
    ui->btn_abort->setEnabled(true);
    ui->btn_connect->setEnabled(false);

    this->myclient->connectToHost(this->serverIp,this->serverPort);//连接到服务器
    if(this->myclient->waitForConnected(1500))//连接失败,返回false
    {
        ui->server_status->setText("Yes !");
    }
}

/* 发送按钮 */
void client::on_btn_Send_clicked()
{
    /* 设置按钮状态 */
    ui->btn_abort->setEnabled(true);
    ui->btn_connect->setEnabled(false);

    this->writeBuf = ui->send_info->toPlainText();//从文本框中获取数据
    myclient->write(writeBuf.toUtf8().data(),this->writeBuf.length());//通过socket写
}

/* 关闭连接按钮 */
void client::on_btn_abort_clicked()
{
    /* 断开客户端的连接 */
    this->myclient->abort();
    /* 设置按钮状态 */
    ui->btn_abort->setEnabled(false);
    ui->btn_connect->setEnabled(true);
    ui->server_status->setText("No !");
}

/* 窗口关系事件 */
void client::closeEvent(QCloseEvent *event)
{
    /* 断开客户端的连接 */
    if(this->myclient->isOpen())
        this->myclient->abort();
}

主题:基于QT平台利用TCP协议实现的通信_第2张图片 

 

 

你可能感兴趣的:(QT小代码)