먼저 헤더파일입니다. 헤더파일에서는 데이터를 수집하는 함수를 처리하기 위한 쓰레드, 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);
} // 수집된 센서 데이터 어플리케이션에 송신
'Programming > Qt' 카테고리의 다른 글
Qt 클릭 이벤트 만들기 (0) | 2020.04.10 |
---|---|
Qt 데이터베이스(maria db) 연동해서 사용하기 (0) | 2020.03.13 |
Qt QLabel에 사진 넣기 (0) | 2019.11.07 |
Qt QThread 사용하기(화면 실시간 갱신하기) (0) | 2019.10.30 |
Qt 라이브러리 추가하기 (0) | 2019.10.11 |