728x90

먼저 헤더파일입니다. 헤더파일에서는 데이터를 수집하는 함수를 처리하기 위한 쓰레드, QTcpServer, QTcpSocket이 선언되어 있습니다. 

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QtNetwork>
#include "processthread.h"

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = nullptr);
    void tcpInit();		// tcp 소켓 통신 서버 오픈 및 초기화
    ~Dialog();
private slots:
    void newConnection();				// 서버에 소켓이 접속했을 때 실행
    void readData();					// 데이터 수신 함수
    void disConnected();				// 소켓 연결 해제 시 실행
    void sendValue(int temp, int hum, int dust, int human);	// 수집된 센서 데이터 어플리케이션에 송신
private:
    Ui::Dialog *ui;
    processThread* pthread;			// 센서 데이터 수집 프로세스 쓰레드
    
    QTcpServer* tcpServer;			// Tcp 서버
    QTcpSocket* client;				// Tcp socket

    int con; // server 접속한 소켓 수
};

#endif // DIALOG_H

다음으로 ui 생성자 코드입니다. tcpInit()이라는 소켓 서버를 오픈해주고 초기화주는 함수입니다. 아래 쓰레드는 데이터를 수집하는 함수는 쓰레드 처리하기 위해 만들었습니다.

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    tcpInit();	// 소켓 서버 오픈 및 초기화
    
    pthread = new processThread(this);	// 센서 데이터 수집 쓰레드 동적 할당
    pthread->start();	// 쓰레드 run
}

tcpInit() 함수는 listen(ip, port) 함수를 통해 tcp Server를 오픈합니다. 그 후 newConnection() 시그널과 newConnection SLOT을 연결하여 Server에 새로운 소켓이 접속하는것을 감지하면 SLOT의 newConnection()이 실행됩니다.

void Dialog::tcpInit()
{
    QHostAddress hostAddress;
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    for (int i = 0 ; i < ipAddressesList.size() ; ++i)
    {
        if(ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address())
        {
            hostAddress = ipAddressesList.at(i);
            break;
        }
    }
    if(hostAddress.toString().isEmpty())    hostAddress = QHostAddress(QHostAddress::LocalHost);
    tcpServer = new QTcpServer(this);
    if(!tcpServer->listen(hostAddress, 9999))	// 서버 오픈 ip : hostaddress, port : 9999
    {
        std::cout << "connect Failed\n";
        close();
    }
    else std::cout << "Tcp Server Open\n";
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));	
    // 서버에 소켓이 접속했을 때 newConnection() 실행
} // tcp 소켓 통신 서버 오픈 및 초기화

newConnection() 함수는 새로운 클라이언트 접속 시 실행됩니다. tcpSocket에 클라이언트의 정보를 nextPendingConnection()을 이용해 넘겨줍니다. 다음으로 소켓에 readyRead() 시그널과 disconnected() 시그널을 연결해줍니다.

그리고 위 코드는 서버에 한 개의 클라이언트만 접속하기 위한 코드입니다. disconnect newConnection()을 하게 되면 서버에 클라이언트가 접속하게 되도 newConnection()함수가 실행되지 않습니다.

void Dialog::newConnection()
{
    std::cout << "connected" << con << std::endl;
    if(con == 0)
    {
        client = tcpServer->nextPendingConnection();
        con++;
        connect(pthread, SIGNAL(setValue(int, int, int, int)), this, SLOT(sendValue(int, int, int, int)));    
        // 수집된 센서 데이터 송신
        connect(client,SIGNAL(readyRead()),this,SLOT(readData()));
        connect(client,SIGNAL(disconnected()),this,SLOT(disConnected()));
        disconnect(tcpServer, SIGNAL(newConnection()),this,SLOT(newConnection()));
    }
} // 서버에 소켓이 접속했을 때 실행

클라이언트에서 데이터를 보내주게 되면 readyRead 시그널이 발생해 readData() 함수가 실행됩니다. 데이터는 QByteArray 형태로 수신하게 됩니다.

void Dialog::readData()
{
    std::cout << "readData\n";
    if(client->bytesAvailable()>=0)
    {
        QByteArray data = client->readAll();
    }
} // 데이터 수신 함수

클라이언트가 접속을 끊게 된다면 disconnected 시그널이 발생해 disConnected() 함수가 실행됩니다. disConnected()함수에서는 클라이언트 소켓을 닫아주게 됩니다.

void Dialog::disConnected()
{
    std::cout << "disconnected\n";
    client->close();
    --con;
    disconnect(pthread, SIGNAL(setValue(int, int, int, int)), this, SLOT(sendValue(int, int, int, int)));    
    // 수집된 센서 데이터 송신
    if(con==0)
        connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection()));
} // 소켓 연결 해제

마지막으로 데이터를 보내는 함수입니다. QByteArray 형태의 변수를 socket에 write해 보내는 방식입니다. 

void Dialog::sendValue(int temp, int hum, int dust,int human)
{
    std::cout << "sendData\n";
    QByteArray tempbyte = QByteArray::number(temp);
    QByteArray humbyte = QByteArray::number(hum);
    QByteArray dustbyte = QByteArray::number(dust);
    QByteArray humanbyte = QByteArray::number(human);
    client->write(tempbyte+","+humbyte+","+dustbyte+","+humanbyte);
} // 수집된 센서 데이터 어플리케이션에 송신

 

728x90

+ Recent posts