1. 程式人生 > >C++ Qt多執行緒 TcpSocket伺服器例項

C++ Qt多執行緒 TcpSocket伺服器例項

伺服器:
incomming
incomming.pro
#-------------------------------------------------
#
# Project created by QtCreator 2016-04-08T09:25:22
#
#-------------------------------------------------


QT       += core gui
QT        +=network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets


TARGET = incomming
TEMPLATE = app




SOURCES += main.cpp\
        mainwindow.cpp \
    myserver.cpp \
    socketthread.cpp \
    mytcpsocket.cpp


HEADERS  += mainwindow.h \
    myserver.h \
    socketthread.h \
    mytcpsocket.h


FORMS    += mainwindow.ui




mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QMainWindow>
class QTcpSocket;
class myserver;
namespace Ui {
class MainWindow;
}


class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
  myserver * server;
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();


private:
    Ui::MainWindow *ui;
};


#endif // MAINWINDOW_H



myserver.h
#ifndef MYSERVER
#define MYSERVER
#include<QObject>
#include<QTcpServer>
#include<QWidget>
class myserver :public QTcpServer{
    Q_OBJECT
public:
    myserver(QWidget * parent);
protected:
    virtual void incomingConnection(qintptr socketDescriptor);


};
//|定義的結束 必須加;
#endif // MYSERVER




mytcpsocket.h
#ifndef MYTCPSOCKET
#define MYTCPSOCKET
#include<QTcpSocket>


class mytcpsocket :public QTcpSocket
{
    Q_OBJECT
public:
    mytcpsocket(QWidget * parent,qintptr p);
private slots:
    void on_discon();


public:
    void on_connected();


};
#endif // MYTCPSOCKET




socketthread.h


#ifndef SOCKETTHREAD
#define SOCKETTHREAD
#include<QThread>
#include<QTcpSocket>
#include<QWidget>
class mytcpsocket;
class socketThread :public QThread
{
private:
    qintptr ptr;
    mytcpsocket * socket;
public:
    socketThread(QWidget * parent,qintptr p);
protected:
    virtual void run();




};
#endif // SOCKETTHREAD




mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"myserver.h"
#include<QHostAddress>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->server=new myserver(this);
    this->server->listen(QHostAddress::LocalHost,520);
}


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


myserver.cpp
#include"myserver.h"
#include<QMessageBox>
#include"mytcpsocket.h"
#include"socketthread.h"
myserver::myserver(QWidget * parent):QTcpServer(parent){


}
void myserver::incomingConnection(qintptr socketDescriptor)
{
    QMessageBox::about(0,"提示","有新連線");
     socketThread * thread=new socketThread(0,socketDescriptor);
    thread->start();


    /*
    mytcpsocket * socket=new mytcpsocket(0,socketDescriptor);
    QThread * thread=new QThread();
    socket->moveToThread(thread);
    thread->start();
    */




}


mytcpsocket.cpp
#include"mytcpsocket.h"
#include<QByteArray>
#include<QDataStream>
#include<QString>
#include<QMessageBox>
#include<QDebug>
mytcpsocket::mytcpsocket(QWidget *parent,qintptr p):QTcpSocket(0)
{


  //connect(this,SIGNAL(),this,SLOT(on_connected()));
    this->setSocketDescriptor(p);
    this->on_connected();
 this->connect(this,SIGNAL(disconnected()),this,SLOT(on_discon()));


}
void mytcpsocket::on_connected()
{


    QByteArray arr;
    QDataStream dts(&arr,QIODevice::WriteOnly);
    dts<<QString("這是資料");
    this->write(arr);
    //QMessageBox::about(0,"x","傳送成功!");
    qDebug()<<"傳送成功";


}
void mytcpsocket::on_discon()
{
    qDebug()<<"有一個客戶端斷開!";
}


socketthread.cpp
#include"socketthread.h"
#include<QString>
#include<QByteArray>
#include<QDataStream>
#include<QMessageBox>
#include<QDebug>
#include"mytcpsocket.h"
socketThread::socketThread(QWidget *parent,qintptr p):QThread(parent)
{


    qDebug()<<"QThread建構函式依然在 舊執行緒";
    this->ptr=p;
}


void socketThread::run(){


    /*1.QObject->moveToThread(Thread *)會把一個Qt物件移動到一個新執行緒中執行 預設在run()中呼叫了 exec()這樣 run()執行完後不會
     * 直接關閉 執行緒 還會讓它 進入訊息迴圈 直到呼叫了 結束 槽
     * 2.QtcpSocket 的write()函式是非同步的 也就是 呼叫了 後不會立即 傳送資料,它會直接往下執行 直到run()的尾部,如果run()沒有
     * 呼叫exec()進行訊息迴圈等待,那麼 這個執行緒 直接就結束了,不會再發送。(傳送資料失敗)
     *3.如果在run()中呼叫了 exec()(傳送成功)
     *4.如果在 write(QByteArray);後面加一句 socket->waitForBytesWritten();這裡就會阻塞等待 直到資料開始傳送,這樣
     * 不需要exec()在 執行緒結束之前直接就傳送完了
     *socket->waitForConnected()
     * socket->waitForDisconnected()
     * socket->waitForReadyRead()都是一個道理
     */
    qDebug()<<"開始新執行緒";
   /* QTcpSocket * socket=new QTcpSocket();
    socket->setSocketDescriptor(this->ptr);


    QByteArray arr;
    QDataStream dts(&arr,QIODevice::WriteOnly);
    dts<<QString("這是資料");
    socket->write(arr);
    */
    mytcpsocket * socket=new mytcpsocket(0,this->ptr);
    socket->waitForBytesWritten();
  // this->exec();
    /*
1.  連線伺服器
m_tcpSocket->connectToHost("127.0.0.1", 9877);
connected = m_tcpSocket->waitForConnected();
只有使用waitForConnected()後,QTcpSocket才真正嘗試連線伺服器,並返回是否連線的結果。


2. 寫資料
m_tcpSocket->write(str.toStdString().c_str(), strlen(str.toStdString().c_str()));
m_tcpSocket->waitForBytesWritten();
當使用waitForBytesWritten()後,QTcpSocket才真正傳送資料。
m_tcpSocket->write(str1.toStdString().c_str(), strlen(str1.toStdString().c_str()));
m_tcpSocket->write(str2.toStdString().c_str(), strlen(str2.toStdString().c_str()));
的結果是傳送了str1str2


3. 斷開與伺服器的連線
m_tcpSocket->disconnectFromHost()
m_tcpSocket->waitForDisconnected()


4. 善於使用QTcpSocket的SIGNAL:connected(), disconnected(), error(QAbstractSocket::SocketError)
    配合自定義私有開關變數bool connected, QTimer
   可以實現自動重連線等邏輯。


      */
}


main.cpp
#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();


    return a.exec();
}












/***********************/










客戶端
useincomming
useincomming.pro
#-------------------------------------------------
#
# Project created by QtCreator 2016-04-08T09:36:28
#
#-------------------------------------------------


QT       += core gui
QT       +=network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets


TARGET = useincomming
TEMPLATE = app




SOURCES += main.cpp\
        mainwindow.cpp


HEADERS  += mainwindow.h


FORMS    += mainwindow.ui


mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QMainWindow>
class QTcpSocket;
namespace Ui {
class MainWindow;
}


class MainWindow : public QMainWindow
{
    Q_OBJECT


public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    QTcpSocket * socket;
private:
    Ui::MainWindow *ui;
private slots:
    void on_readyread();
    void on_conn();
};


#endif // MAINWINDOW_H


mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QTcpSocket>
#include<QHostAddress>
#include<QString>
#include<QByteArray>
#include<QDataStream>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->socket=new QTcpSocket(this);
    this->socket->connectToHost(QHostAddress::LocalHost,520);
    connect(this->socket,SIGNAL(connected()),this,SLOT(on_conn()));
    connect(this->socket,SIGNAL(readyRead()),this,SLOT(on_readyread()));
}


MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::on_readyread()
{
    QMessageBox::about(this,"提示","開始接受");
    QByteArray array=this->socket->readAll();
    QDataStream dts(&array,QIODevice::ReadOnly);
    QString data;
    dts>>data;
    QMessageBox::about(this,"提示",data);


}
void MainWindow::on_conn()
{
    QMessageBox::about(this,"提示","連線成功");
}


main.cpp
#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();


    return a.exec();
}