Qt/Network

Qt Network 예제1

2023. 8. 24. 20:20

  • -

예제 실행

예제 파일 (주석 있음)

01_TcpServer_Commented.zip
0.00MB
01_TcpClient_Commented.zip
0.00MB

예제 파일 (주석 없음)

01_TcpServer.zip
0.00MB
01_TcpClient.zip
0.00MB

Serv. 소스 코드

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // [01] Widget w 위젯 객체 생성
    Widget w;
    w.setWindowTitle("TCP 서버");
    w.show();

    return a.exec();
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QtWidgets>
#include <QDebug>

// [02.1] Widget class 생성자 실행
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    // [02.3] Server Network 초기화
    initServ();
}

// Widget class 파괴자
Widget::~Widget()
{
    delete ui;
}

// [02.3] Widget 생성자 실행시, Server 초기화 (Server 클래스로 독립 되어야 할 부분)
void Widget::initServ()
{

    // [02.3.1] hostAddress (이 소스코드가 실행될 프로그램(서버)의 ip 찾기) 찾기
    QHostAddress hostAddress = Widget::getMyIP();

    // [02.3.2] tcpServer 서버 소켓 세팅
    //// [1] 생성 : 서버 소켓 생성
    //// [2] 결합 : 서버 IP 결합
    tcpServer = new QTcpServer(this);

    //// [3] 대기 : 클라이언트의 연결 요청 대기
    if (!tcpServer->listen(hostAddress, 25000))
    {
        QMessageBox::critical(this, tr("TCP Server"),
                              tr("서버를 시작할 수 없습니다. 에러메세지 : %1.")
                              .arg(tcpServer->errorString()));
        close();
        return; // 실패시 종료
    }


    // [02.3.3]
    // tcpServer 소켓이 정상적으로 생성되면, 서버 정보를 lable widget에 표시
    ui->labelStatus->setText(tr("서버 동작 중 \n\n"
                                "IP : %1\n"
                                "PORT : %2\n")
                                .arg(hostAddress.toString()).arg(tcpServer->serverPort()));

    // [02.3.4]
    // tcpServer 객체에 클라이언트의 연결 요청 Signal 이 생기면, slot_newConnection연결
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(slot_newConnection()));

    ui->connMsgEdit->clear();
}

// [02.4] Server가 클라리언트의 연결 요청이 받아들인 후 동작할 로직 (Server 클래스로 독립 되어야 할 부분)
void Widget::slot_newConnection()
{
    // [02.4.1] 연결된 소켓 생성
    //// [4] 수락 : tcpServer 소켓 + 연결 요청시 전달 받은 클라이언트 정보를 기반
    ////           새로운 연결 QTcpSocket 생성
    QTcpSocket *connectedSocket = tcpServer->nextPendingConnection();

    connect(connectedSocket, SIGNAL(disconnected()),
            connectedSocket, SLOT(deleteLater()));

    // [02.4.2] 서버에 연결 상태 정보 출력
    QString clnt_addr = connectedSocket->peerAddress().toString();
    QString currTime = QTime::currentTime().toString("hh시 mm분 ss초 zzz밀리초");
    QString text_conn = QString("<-클라이언트 연결 성공 (%1, %2)").arg(currTime, clnt_addr);
    ui->connMsgEdit->append(text_conn);

    // [02.4.3] 데이터 송수신
    //// [5] 송수신
    QByteArray message = QByteArray("Hello Client ~ (서버에서 보낸 인사)");
    currTime = QTime::currentTime().toString("hh시 mm분 ss초 zzz밀리초");
    // 문장 전송
    connectedSocket->write(message);
    // 전송 완료 상태 위젯 표시
    QString text_send = QString("->클라이언트 문장 전송 (%1)").arg(currTime);
    ui->connMsgEdit->append(text_send);

    // [02.4.5] 연결된 클라이언트로 메시지를 보내고, 서버에서 클라이언트와의 연결을 종료한다.
    //// [6] 닫음
    connectedSocket->disconnectFromHost();

    // [02.4.6] 서버에 연결 해제 상태 출력 (이미 연결 끊긴 상태)
    currTime = QTime::currentTime().toString("hh시 mm분 ss초 zzz밀리초");
    QString text_close = QString("->클라이언트 접속 종료 (%1, %2)").arg(currTime, clnt_addr);
    ui->connMsgEdit->append(text_close);
}


// [02.7]
QHostAddress Widget::getMyIP()
{

    QHostAddress myAddress;
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    // localhost(127.0.0.1) 가 아닌 것을 사용
    for (int i = 0; i < ipAddressesList.size(); ++i) {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
            ipAddressesList.at(i).toIPv4Address()) {
            //qDebug() << ipAddressesList.at(i);
            myAddress = ipAddressesList.at(i);
            break;
        }
    }

    // 인터넷이 연결되어 있지 않다면, localhost(127.0.0.1) 사용
    if (myAddress.toString().isEmpty())
        myAddress = QHostAddress(QHostAddress::LocalHost);

    return myAddress;
}

Clnt. 소스 코드

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    // [01] 위젯 객체 생성
    QApplication a(argc, argv);
    Widget w;
    QString title ="TCP 클라이언트 (" + w.getMyIP().toString() + ")";
    w.setWindowTitle(title);
    w.show();

    return a.exec();
}

widget.cpp

#include <QHostAddress>
#include <QtNetwork>
#include <QDebug>
#include <QString>

#include "widget.h"
#include "ui_widget.h"

// [02.1] Widget 생성자 실행
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    // [02.3] Client Network 초기화
    initClnt();

    // [02.1.1]
    // UI connectButton 시그널과, slot_connectButton 슬롯 연결
    //// [2] 연결
    connect(ui->connectButton, SIGNAL(clicked()),
            this,                SLOT(slot_connectButton()));
}

// Widget class 파괴자
Widget::~Widget()
{
    delete ui;
}

// [02.3]
void Widget::initClnt()
{

    // [02.3.1] tcpCocket 클라이언트 소켓 생성
    //// [1] 생성 : 클라이언트 소켓 생성
    tcpSocket = new QTcpSocket(this);

    // [02.3.2] 서버에서 전송된 데이터가 있으면 slot_readMessage() 슬롯 연결
    //// [3] 송수신 : 데이터 수신
    connect(tcpSocket, SIGNAL(readyRead()),
            this,      SLOT(slot_readMessage()));

    // [02.3.3] 서버에서 연결 종료 시그널이 전달되면 slot_disconnected 슬롯 연결
    connect(tcpSocket, SIGNAL(disconnected()),
            this,      SLOT(slot_disconnected()));
}

// [02.4]
//// [2] 연결 : 서버 IP로 연결 요청, Port 는 qint16 자료형
void Widget::slot_connectButton()
{
    // [02.4.1] QLineEdit 에 입력된 Server IP, Server Port를 가져온다.
    QString serverIP = ui->serverIP->text().trimmed();
    QString serverPort = ui->serverPort->text().trimmed();
    QHostAddress serverAddress(serverIP);

    // [02.4.2] 서버로 연결 요청을 보낸다.
    tcpSocket->connectToHost(serverAddress, serverPort.toUShort());
    ui->textEdit->append("<- 서버에게 연결 요청");
}

// [02.5] 서버에서 전송 받은 데이터를 읽어들인다.
//// [3] 송수신 : 데이터 송수신
void Widget::slot_readMessage()
{
    // 바이트를 읽어들여 textEdit에 출력한다.
    if(tcpSocket->bytesAvailable() >= 0)
    {
        QByteArray readData = tcpSocket->readAll();
        ui->textEdit->append("-> "+readData);
    }
}

// [02.6] 소켓 연결 종료 정보를 표시한다.
void Widget::slot_disconnected()
{
    ui->textEdit->append("-> 서버로부터 연결 해제");
    qDebug() << Q_FUNC_INFO << "서버로부터 접속 종료.";
}

// [02.7]
QHostAddress Widget::getMyIP()
{

    QHostAddress myAddress;
    // 장치에 연결된 모든 ip를 가져와서
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    // localhost(127.0.0.1) 가 아닌 것을 사용하기 위해 찾음
    for (int i = 0; i < ipAddressesList.size(); ++i) {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
            ipAddressesList.at(i).toIPv4Address()) {
            //qDebug() << ipAddressesList.at(i);
            myAddress = ipAddressesList.at(i);
            break;
        }
    }

    // 인터넷이 연결되어 있지 않다면, localhost(127.0.0.1) 사용
    if (myAddress.toString().isEmpty())
        myAddress = QHostAddress(QHostAddress::LocalHost);

    return myAddress;
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.