728x90
10명의 사용자가 내부 네트워크를 통해 특정 PC의 HSQLDB에 정보를 저장하는 TCP/IP 프로그램을 구현하려면, 다음과 같은 구성 요소가 필요합니다.
✅ 전체 구조
[Client] x10 <--TCP/IP--> [Server] --> [HSQLDB (in-process or server mode)]✅ 1. HSQLDB 설정 (서버 PC)
옵션 1: HSQLDB Server Mode (권장)
-
여러 클라이언트가 동시에 접속 가능
-
server.properties 예시:
properties
复制
server.database.0=file:./mydb;user=sa;password=1234
server.dbname.0=mydb
server.port=9001
-
실행 명령어:
bash
复制
java -cp hsqldb.jar org.hsqldb.server.Server
✅ 2. 서버 프로그램 (Java 예시)
java
复制
import java.io.*;
import java.net.*;
import java.sql.*;
public class DBServer {
private static final String DB_URL = "jdbc:hsqldb:hsql://localhost:9001/mydb";
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(5000)) {
System.out.println("서버 대기 중...");
while (true) {
Socket client = serverSocket.accept();
new ClientHandler(client).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
static class ClientHandler extends Thread {
Socket client;
ClientHandler(Socket client) {
this.client = client;
}
public void run() {
try (
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
Connection conn = DriverManager.getConnection(DB_URL, "sa", "1234")
) {
String data = in.readLine();
if (data == null) return;
String[] parts = data.split(",");
String name = parts[0];
int age = Integer.parseInt(parts[1]);
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, name);
stmt.setInt(2, age);
stmt.executeUpdate();
System.out.println("저장 완료: " + name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
✅ 3. 클라이언트 프로그램 (Java 예시)
java
复制
import java.io.*;
import java.net.*;
public class DBClient {
public static void main(String[] args) {
String name = "홍길동";
int age = 30;
try (
Socket socket = new Socket("192.168.0.100", 5000); // 서버 IP
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)
) {
out.println(name + "," + age);
System.out.println("전송 완료");
} catch (IOException e) {
e.printStackTrace();
}
}
}
✅ 4. DB 테이블 생성 (최초 1회)
CREATE TABLE users (
id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(50),
age INTEGER
);
✅ 5. 실행 순서
-
HSQLDB 서버 실행 (server.properties 설정 후)
-
DBServer.java 실행
-
10대의 PC에서 DBClient.java 실행 (또는 Python/C# 등으로 대체 가능)
✅ 6. 보안 및 안정성 고려사항
-
내부 네트워크만 허용 (방화벽 설정)
-
TCP 포트 5000, 9001 개방
-
SQL 인젝션 방지 (PreparedStatement 사용)
-
동시 접속 제한 (필요 시 세마포어 또는 큐 사용)
✅ 7. 다른 언어로의 전환
-
Python 클라이언트 가능:
Python
import socket
s = socket.socket()
s.connect(("192.168.0.100", 5000))
s.sendall("홍길동,30".encode())
필요하다면 Python 서버, C# 클라이언트, GUI, 로그 기록, 중복 확인 등도 추가해드릴 수 있습니다.
"10명의 사용자가 내부 네트워크에서 특정 PC의 HSQLDB에 정보를 저장하는 TCP/IP 프로그램(C++ Qt)"
1. 개발 환경
-
Qt 6.5 이상 (Qt 5.15 도 가능)
-
JDK 11 이상
-
HSQLDB 2.7 서버 모드 (포트 9001, 별명 mydb, 계정 SA/1234)
-
hsqldb.jar 는 C:/hsqldb/hsqldb.jar 에 두고 진행
2. HSQLDB 서버 시작 스크립트 (start_hsqldb.bat)
bat
复制
rem start_hsqldb.bat
set JDK=%JAVA_HOME%\bin
set HSQL=C:\hsqldb
%JDK%\java -cp %HSQL%\hsqldb.jar org.hsqldb.server.Server ^
--database.0 file:%HSQL%\data\mydb;user=sa;password=1234 ^
--dbname.0 mydb --port 9001
실행 후 Server 1.7.2 is running on port 9001 메시지 확인
3. 테이블 생성 (최초 1회)
sql
复制
CREATE TABLE users (
id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(50),
age INTEGER
);
4. Qt 프로젝트 파일 (TcpHsqlServer.pro)
pro
复制
QT += core network sql
CONFIG += console c++17
SOURCES += main.cpp tcpserver.cpp dbwriter.cpp
HEADERS += tcpserver.h dbwriter.h
5. 서버 소스 (한글 주석)
tcpserver.h
cpp
复制
#pragma once
#include <QTcpServer>
#include <QTcpSocket>
class DbWriter;
class TcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit TcpServer(QObject *parent = nullptr);
protected:
void incomingConnection(qintptr socketDescriptor) override;
private:
DbWriter *m_db; // DB 삽입 담당 객체
};
tcpserver.cpp
cpp
复制
#include "tcpserver.h"
#include "dbwriter.h"
TcpServer::TcpServer(QObject *parent)
: QTcpServer(parent), m_db(new DbWriter(this))
{
listen(QHostAddress::AnyIPv4, 5000); // 5000 포트 대기
qInfo() << "TCP 서버가 5000 포트에서 대기 중...";
}
void TcpServer::incomingConnection(qintptr socketDescriptor)
{
QTcpSocket *s = new QTcpSocket(this);
s->setSocketDescriptor(socketDescriptor);
// 클라이언트가 보낸 줄 단위 데이터를 읽어 DB 에 넣기
connect(s, &QTcpSocket::readyRead, this, [=] {
while (s->canReadLine()) {
QByteArray line = s->readLine().trimmed(); // "Tom,25"
m_db->insertUser(line);
}
});
connect(s, &QTcpSocket::disconnected, s, &QTcpSocket::deleteLater);
}
dbwriter.h
cpp
复制
#pragma once
#include <QObject>
#include <QSqlDatabase>
class DbWriter : public QObject
{
Q_OBJECT
public:
explicit DbWriter(QObject *parent = nullptr);
void insertUser(const QByteArray &csv); // "이름,나이" 형식
};
dbwriter.cpp
cpp
复制
#include "dbwriter.h"
#include <QSqlQuery>
#include <QSqlError>
DbWriter::DbWriter(QObject *parent) : QObject(parent)
{
QSqlDatabase db = QSqlDatabase::addDatabase("QHSQL", "hsql-con");
db.setHostName("localhost");
db.setPort(9001);
db.setDatabaseName("mydb"); // HSQLDB 별명
db.setUserName("sa");
db.setPassword("1234");
if (!db.open())
qFatal() << "HSQLDB 연결 실패:" << db.lastError().text();
qInfo() << "HSQLDB 연결 성공";
}
void DbWriter::insertUser(const QByteArray &csv)
{
QList<QByteArray> cols = csv.split(',');
if (cols.size() != 2) return;
QString name = QString::fromUtf8(cols[0]);
int age = cols[1].toInt();
QSqlQuery q(QSqlDatabase::database("hsql-con"));
q.prepare("INSERT INTO users(name, age) VALUES (?, ?)");
q.addBindValue(name);
q.addBindValue(age);
if (!q.exec())
qWarning() << "삽입 오류:" << q.lastError().text();
else
qInfo() << "삽입 완료:" << name << age;
}
main.cpp
cpp
复制
#include <QCoreApplication>
#include "tcpserver.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TcpServer srv; // 서버 시작
return a.exec();
}
6. 클라이언트 예제 (단일 파일)
cpp
复制
#include <QCoreApplication>
#include <QTcpSocket>
#include <QTest> // for qSleep
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTcpSocket sock;
sock.connectToHost("192.168.0.100", 5000); // 서버 IP
if (!sock.waitForConnected(3000)) {
qFatal("연결 실패");
}
QStringList names{"Alice","Bob","Cathy","Dave","Eve",
"Frank","Grace","Henry","Ivy","Jack"};
for (int i = 0; i < 10; ++i) {
QString msg = QString("%1,%2\n").arg(names[i]).arg(20 + i);
sock.write(msg.toUtf8());
sock.flush();
QTest::qSleep(200); // 0.2 초 간격
}
sock.waitForBytesWritten();
qInfo() << "모든 데이터 전송 완료";
return 0;
}
7. 빌드 & 실행 순서
-
hsqldb.jar 경로를 시스템 CLASSPATH 에 추가
-
qmake && cmake --build . --config Release (또는 Qt Creator 빌드)
-
start_hsqldb.bat 실행 → 서버 프로세스 띄우기
-
서버 exe 실행
-
원하는 PC에서 클라이언트 exe 10대(또는 더 많이) 실행
-
DBeaver 등으로 jdbc:hsqldb:hsql://localhost:9001/mydb 접속 → users 테이블 확인
8. 자주 발생하는 문제와 해결
-
QHSQL 드라이버 로드 실패
→ plugins/sqldrivers/qhsql.dll (또는 .so) 를 실행 파일 옆에 복사 & hsqldb.jar 가 CLASSPATH 에 있어야 함 -
한글 깨짐
→ 클라이언트 toUtf8(), 서버 QString::fromUtf8() 로 통일, HSQLDB 기본 인코딩은 UTF-8 -
포트 충돌
→ listen() 포트(5000) 또는 HSQLDB 포트(9001) 변경 후 사용 -
다중 클라이언트 동시 접속
→ 위 코드는 Qt 신호/슬롯 기반 비동기 I/O 이므로 10명 동시 접속에도 문제 없음.
대량 동시 삽입이 필요하면 DbWriter 내부에 큐 + 워커 스레드 추가 권장
이제 C++/Qt 로 작성된 TCP 서버가 10명(또는 그 이상)의 클라이언트로부터 데이터를 받아 HSQLDB 에 저장하는 전체 한글 설명이 완성되었습니다.
더 필요한 기능(GUI, 로그, 중복 확인 등)이 있으면 말씀해 주세요!
더 필요한 기능(GUI, 로그, 중복 확인 등)이 있으면 말씀해 주세요!
728x90
'컴퓨터 활용(한글, 오피스 등) > 기타' 카테고리의 다른 글
| DW와 OLAP의 관계 (0) | 2025.09.12 |
|---|---|
| 혼동하기 쉬운 띄어쓰기 (0) | 2025.09.09 |
| 논문편집양식규정 대한아동복지학회 (0) | 2025.09.08 |
| DW(데이터웨어하우스) 구축 전 BPR(Business Process Reengineering) 수행 여부 (0) | 2025.09.08 |
| 예산 이관에 대한 자료 조사 - 초안 (0) | 2025.09.05 |