QTcpServer 클래스를 이용한 TCP서버 예제
CMake 기반 프로젝트 생성 후, CMakeLists.txt 파일에 아래와 같이 항목을 수정 및 추가한다.
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network)
...
target_link_libraries(00_TcpServer PRIVATE Qt${QT_VERSION_MAJOR}::Network)
find_package 두줄은 set(CMAKE_CXX_STANDARD_REQUIRED ON) 아래 추가하면되고,
target_link는 widget을 인자로 삼은target_link코드 아래 추가하면 된다.
<widget.h>
#ifndef WIDGET_H
#define WIDGET_H
#include <QObject>
#include <QWidget>
#include <QtNetwork/QTcpServer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QTcpServer *tcpServer;
void initialize();
private slots:
void newConnection();
};
#endif // WIDGET_H
- initialize( ) 함수는 QTcpServer 클래스의 오브젝트를 초기화를위한 함수이다.
- newConnection( ) Slot 함수는 클라이언트가 접속하면 Signal이 발생하면 호출되는 함수
<widget.cpp>
#include "widget.h"
#include "./ui_widget.h"
#include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QTcpSocket>
#include <QMessageBox>
#include <QTime>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
initialize();
}
void Widget::initialize()
{
QHostAddress hostAddr;
QList<QHostAddress> ipList = QNetworkInterface::allAddresses();
// Use something other than localhost (127.0.0.1)
for (int i = 0; i < ipList.size(); ++i) {
if (ipList.at(i) != QHostAddress::LocalHost &&
ipList.at(i).toIPv4Address()) {
hostAddr = ipList.at(i);
break;
}
}
if (hostAddr.toString().isEmpty())
hostAddr = QHostAddress(QHostAddress::LocalHost);
tcpServer = new QTcpServer(this);
if (!tcpServer->listen(hostAddr, 25000)) {
QMessageBox::critical(this, tr("TCP Server"),
tr("Cannot start the server, Error: %1.")
.arg(tcpServer->errorString()));
close();
return;
}
ui->labelStatus->setText(tr("Server running \n\n"
"IP : %1\n"
"PORT : %2\n")
.arg(hostAddr.toString())
.arg(tcpServer->serverPort()));
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
ui->connMsgEdit->clear();
}
void Widget::newConnection()
{
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));
QString currTime = QTime::currentTime().toString("hh:mm:ss");
QString text = QString("Client Connection (%1)").arg(currTime);
ui->connMsgEdit->append(text);
QByteArray message = QByteArray("Hello Client ~ ");
clientConnection->write(message);
clientConnection->disconnectFromHost();
}
Widget::~Widget()
{
delete ui;
}
- 생성자 함수에서 호출되는 initialize( ) 함수는 클라이언트가 접속할 서버의 IP를 시스템으로부터 얻어온다.
- QTcpServer 클래스의 tcpServer 오브젝트를 초기화한다.
- listen( ) 멤버 함수를 이용해 클라이언트 접속 요청 대기 상태가 될 수 있도록 한다.
- listen( ) 함수의 첫 번째 인자는 IP주소이며 두 번째 인자는 서버 Port 번호이다.
- 그리고 initialize( ) 함수 하단의 connect( ) 함수는 클라이언트가 접속하게 되면 호출되는 Signal 과 Slot 함수를 연결하였다.
- 새로운 클라이언트가 접속하게 되면 newConnection( ) 함수가 호출된다.
- 새로운 클라이언트가 접속하게 되면 newConnection( ) 함수가 호출된다.
QTcpSocket 클래스를 이용한 TCP 클라이언트 예제
서버 예제와 동일하게, CMake 기반 프로젝트 생성 후, CMakeLists.txt 파일에 아래와 같이 항목을 수정 및 추가한다.
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network)
...
target_link_libraries(00_TcpServer PRIVATE Qt${QT_VERSION_MAJOR}::Network)
<widget.h>
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtNetwork/QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QTcpSocket *tcpSocket;
void initialize();
private slots:
void connectButton();
void readMessage(); // Called when receiving a message from the server
void disconnected();
};
#endif // WIDGET_H
- connectButton( ) Slot 함수는 [접속] 버튼 클릭 시 호출된다.
- readMessage( ) Slot 함수는 서버로부터 메시지를 받는 Signal 이 발생하면 호출되는 함수이다.
<widget.cpp>
#include "widget.h"
#include "./ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->connectButton, SIGNAL(clicked()),
this, SLOT(connectButton()));
initialize();
}
void Widget::initialize()
{
tcpSocket = new QTcpSocket(this);
connect(tcpSocket, SIGNAL(readyRead()),
this, SLOT(readMessage()));
connect(tcpSocket, SIGNAL(disconnected()),
this, SLOT(disconnected()));
}
void Widget::connectButton()
{
QString serverip = ui->serverIP->text().trimmed();
QHostAddress serverAddress(serverip);
tcpSocket->connectToHost(serverAddress, 25000);
}
void Widget::readMessage()
{
if(tcpSocket->bytesAvailable() >= 0)
{
QByteArray readData = tcpSocket->readAll();
ui->textEdit->append(readData);
}
}
void Widget::disconnected()
{
qDebug() << Q_FUNC_INFO << "Server Connection Close.";
}
Widget::~Widget()
{
delete ui;
}
- initialize( ) 함수는 QTcpSocket 클래스의 tcpSocket 오브젝트를 선언하고 서버로부터 메시지를 받을 발생한 Signal 을 readMessage( ) Slot 함수와 연결한다.
- 서버와 연결 종료 Signal을 받으면 disconnected( ) Slot 함수와 연결한다.
- 서버로부터 메시지를 받으면 readMessage( ) 함수를 호출하고 서버와 연결이 종료되면 disconnect( )Slot 함수가 호출된다.
- readMessage( ) Slot 함수에서 tcpSocket->bytesAvailable() 함수는 서버가 보내온 메시지의 Bytes 수를 구할 수 있다. 그리고 readAll( ) 멤버 함수는 서버가 보내온 메시지를 읽어올 수 있는 기능을 제공한다.
'Qt프로그램' 카테고리의 다른 글
채팅 서버/클라이언트 구현 (0) | 2024.10.11 |
---|---|
TCP 프로토콜 / 동기 방식 비 동기 방식 구현 (0) | 2024.10.10 |
Qt데이터베이스 모듈 (2) | 2024.10.09 |
Model and View (1) | 2024.10.09 |
Container Classes (1) | 2024.10.08 |
댓글