제조 현장에서는 설비, 계측기, 검사기, PLC 연동 장비 등에서 발생하는 데이터를 실시간으로 수집해야 하는 경우가 많습니다.
이때 가장 기본적이면서도 많이 사용되는 방식이 TCP/IP 소켓 통신입니다.
이번에 개발한 eIOT Socket Server는 기존 VB6.0으로 운영하던 소켓 서버 프로그램의 구조를 참고하여 C# WinForms 기반으로 재구성한 서버형 프로그램입니다.
목표는 단순합니다.
설비나 클라이언트 장비에서 보내는 데이터를 안정적으로 수신하고, 화면에 즉시 표시하며, 일자별 로그 파일로 저장하는 것입니다.
1. 프로그램 개요
eIOT Socket Server는 PC에서 실행되는 TCP 소켓 서버 프로그램입니다.
서버 PC는 지정된 포트를 열고 대기하다가, 클라이언트 장비가 접속하면 해당 접속 정보를 화면에 표시합니다.
클라이언트가 데이터를 전송하면 서버는 수신 내용을 실시간 로그 화면에 표시하고, 동시에 텍스트 파일로 저장합니다.
주요 기능은 다음과 같습니다.
- TCP/IP 소켓 서버 실행
- 서버 IP와 Port 표시
- 클라이언트 접속 상태 표시
- 클라이언트별 수신 데이터 실시간 표시
- 최근 30라인 화면 로그 유지
- 일자별 텍스트 로그 저장
- 클라이언트 접속 시 버튼 자동 생성
- 접속 종료 시 버튼 자동 제거
- 테스트 메시지 전송 기능
- PC 재부팅 후 자동 실행
- 멀티 클라이언트 동시 처리
- 오류 발생 시 프로그램 종료 방지
2. 화면 구성
화면은 현장 운영자가 쉽게 확인할 수 있도록 단순하면서도 명확하게 구성했습니다.
상단에는 일자와 수신 건수, 서버 상태를 표시합니다.
중앙에는 검은색 배경의 로그 영역을 배치하고, 녹색 글자로 수신 내용을 한 줄씩 표시합니다.
이는 기존 VB6.0 시절의 장비 모니터링 화면과 유사한 느낌을 유지하면서도, C# WinForms에서 보다 안정적으로 동작하도록 구성한 것입니다.
하단에는 테스트 메시지를 입력할 수 있는 TextBox를 두고, 그 아래에는 서버 정보와 클라이언트 접속 정보를 버튼 형태로 표시합니다.
기본적으로 서버 정보 버튼에는 다음 정보가 표시됩니다.
서버IP:포트_현재일시
예를 들면 다음과 같은 형태입니다.
192.168.0.65:7099_2026-06-17 오전 11:56:07
클라이언트가 접속하면 노란색 버튼이 자동으로 추가됩니다.
버튼에는 상대 IP, Port, 접속 일시 등의 정보가 표시됩니다.
클라이언트 접속이 끊어지면 해당 버튼은 자동으로 사라집니다.
3. TCP 소켓 서버 구조
이 프로그램의 핵심은 TcpListener입니다.
서버는 지정된 포트를 열고 클라이언트 접속을 기다립니다.
_listener = new TcpListener(IPAddress.Any, _port);
_listener.Start();
IPAddress.Any를 사용하면 PC의 모든 네트워크 인터페이스에서 접속을 받을 수 있습니다.
즉, 내부 IP가 여러 개이거나 유선/무선 네트워크가 함께 있는 환경에서도 서버가 지정된 포트를 기준으로 접속 요청을 받을 수 있습니다.
클라이언트가 접속하면 AcceptTcpClientAsync()로 접속을 수락합니다.
tcpClient = await _listener.AcceptTcpClientAsync(token);
이 방식은 비동기 방식이므로 UI 화면이 멈추지 않습니다.
WinForms 프로그램에서 소켓 서버를 만들 때 가장 중요한 부분 중 하나가 바로 UI 멈춤 방지입니다.
4. 멀티 클라이언트 처리
제조 현장에서는 여러 장비가 동시에 데이터를 보내는 경우가 많습니다.
예를 들어 다음과 같은 상황이 있을 수 있습니다.
- 검사기 5대가 동시에 검사 결과 전송
- 설비 10대가 생산 실적 전송
- 계측 장비 여러 대가 주기적으로 측정값 전송
- 작업 단말기와 장비가 동시에 접속
이런 상황에서 단일 스레드 방식으로 처리하면 수신 지연이나 화면 멈춤이 발생할 수 있습니다.
그래서 클라이언트가 접속할 때마다 독립적인 Task를 생성하여 수신 루프를 실행하도록 구성했습니다.
_ = Task.Run(() => ReceiveLoopAsync(session, serverToken));
각 클라이언트는 서로 독립적으로 데이터를 수신합니다.
즉, A 장비가 많은 데이터를 보내고 있어도 B 장비의 데이터 수신이 막히지 않습니다.
이 구조는 IoT 서버, 설비 데이터 수집 서버, 생산 실적 수집 서버에서 매우 중요한 구조입니다.
5. 클라이언트 세션 관리
접속한 클라이언트는 ConcurrentDictionary로 관리합니다.
private readonly ConcurrentDictionary<int, ClientSession> _clients = new();
일반 Dictionary가 아니라 ConcurrentDictionary를 사용한 이유는 멀티스레드 환경에서 안전하게 클라이언트 정보를 추가, 조회, 삭제하기 위해서입니다.
소켓 서버에서는 여러 클라이언트가 동시에 접속하거나 종료될 수 있습니다.
이때 일반 컬렉션을 사용하면 데이터 충돌이나 예외가 발생할 수 있습니다.
ConcurrentDictionary를 사용하면 다음 작업을 비교적 안전하게 처리할 수 있습니다.
- 클라이언트 추가
- 클라이언트 제거
- 접속 상태 조회
- 특정 클라이언트로 테스트 데이터 전송
- 접속 종료 시 리소스 정리
6. 수신 데이터 처리
클라이언트가 데이터를 보내면 서버는 NetworkStream을 통해 데이터를 읽습니다.
int bytesRead = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length), linked.Token);
수신 버퍼는 기본적으로 8192바이트를 사용했습니다.
수신된 바이트 배열은 문자열로 변환한 뒤 화면에 표시하고 로그 파일에 저장합니다.
string receiveText = DecodeReceiveData(buffer, bytesRead);
데이터 인코딩은 우선 UTF-8 기준으로 처리합니다.
필요한 경우 장비 환경에 따라 EUC-KR, ASCII, 기본 인코딩 방식으로 조정할 수 있습니다.
현장 장비 중에는 오래된 장비가 아직도 ASCII 또는 ANSI 기반으로 데이터를 보내는 경우가 있기 때문에, 실제 적용 시에는 장비 프로토콜에 맞는 인코딩 확인이 필요합니다.
7. 화면 로그 표시
수신 데이터는 화면 중앙의 로그 영역에 표시됩니다.
표시 형식은 다음과 같습니다.
HH:mm:ss_클라이언트번호_수신내용
예를 들면 다음과 같습니다.
11:57:27_1_수신: 123,44,123,223
화면 로그는 최근 30라인까지만 유지합니다.
이유는 단순합니다.
수신 데이터가 많을 경우 화면 컨트롤에 너무 많은 데이터가 쌓이면 프로그램이 느려질 수 있습니다.
따라서 화면에는 최근 상태만 보여주고, 전체 이력은 파일 로그로 저장하는 구조가 더 안정적입니다.
while (lstLog.Items.Count >= MaxLogLineCount)
{
lstLog.Items.RemoveAt(0);
}
이 구조를 통해 운영자는 최근 수신 상태를 쉽게 확인하고, 상세 이력은 로그 파일에서 확인할 수 있습니다.
8. 일자별 로그 저장
수신 데이터는 실행 파일 폴더 아래 Log 폴더에 저장됩니다.
파일명은 다음과 같은 형식입니다.
eIOT_yyyyMMdd.txt
예를 들면 다음과 같습니다.
eIOT_20260617.txt
로그 내용은 다음 형식으로 저장됩니다.
[2026-06-17 11:57:27] 192.168.0.120:50123 수신데이터
일자별로 파일이 나누어지기 때문에 추후 데이터 확인, 장애 분석, 설비 통신 이력 확인에 유용합니다.
운영 환경에서는 이 로그 파일을 기준으로 다음과 같은 작업도 확장할 수 있습니다.
- 수신 데이터 DB 저장
- 오류 데이터 별도 분류
- 생산 실적 자동 등록
- 검사 결과 자동 등록
- 설비 가동 이력 분석
- FEMS/EMS 에너지 데이터 수집
- MES 실적 연동
9. 클라이언트 접속 표시
클라이언트가 접속하면 화면 하단에 노란색 버튼이 자동으로 생성됩니다.
이 버튼은 단순 표시용이 아니라, 접속된 클라이언트 식별용입니다.
표시 정보는 다음과 같습니다.
- 클라이언트 IP
- 클라이언트 Port
- 접속 일시
- 내부 세션 번호
접속이 끊어지면 해당 버튼은 자동으로 제거됩니다.
이 구조의 장점은 현장 운영자가 현재 몇 대의 장비가 서버에 붙어 있는지 쉽게 확인할 수 있다는 점입니다.
10. 테스트 메시지 전송
하단 TextBox에 메시지를 입력한 후 클라이언트 버튼을 클릭하면 해당 클라이언트로 테스트 메시지를 전송할 수 있습니다.
이 기능은 다음과 같은 상황에서 유용합니다.
- 장비와 서버 간 통신 상태 확인
- 클라이언트 응답 테스트
- 간단한 명령 전송
- 개발 중 프로토콜 테스트
- 현장 설치 후 통신 점검
실제 운영에서는 이 기능을 확장하여 장비 제어 명령을 보낼 수도 있습니다.
예를 들면 다음과 같은 명령 구조를 만들 수 있습니다.
PING
RESET
STATUS?
START
STOP
다만 실제 설비 제어 명령을 사용할 경우에는 반드시 권한, 로그, 이중 확인 절차를 넣는 것이 좋습니다.
11. PC 재부팅 후 자동 실행
현장 서버 프로그램은 PC가 재부팅되더라도 자동으로 다시 실행되어야 합니다.
특히 다음과 같은 상황에서는 자동 실행이 중요합니다.
- 정전 후 PC 재시작
- Windows 업데이트 후 재부팅
- 작업자 실수로 PC 재시작
- 원격 유지보수 후 재부팅
- 야간 무인 운영
이번 프로그램은 Windows의 현재 사용자 Run 영역에 자동 등록되도록 구성했습니다.
즉, 서버 프로그램이 한 번 실행되면 이후 PC 재부팅 시 자동으로 다시 실행됩니다.
운영 PC에서 사용하는 경우에는 Windows 로그인 자동화 또는 서비스 방식 전환까지 함께 검토하면 더 안정적인 구성이 가능합니다.
12. 오류 발생 시 프로그램 종료 방지
소켓 서버는 장시간 실행되는 프로그램입니다.
따라서 일시적인 오류 때문에 프로그램이 종료되면 안 됩니다.
예를 들어 다음과 같은 오류가 발생할 수 있습니다.
- 클라이언트 강제 종료
- 랜선 분리
- 네트워크 장애
- 장비 전원 차단
- 비정상 데이터 수신
- 로그 파일 접근 오류
- 포트 충돌
- 예외적인 소켓 종료
이런 경우에도 프로그램이 죽지 않도록 주요 구간에 예외 처리를 넣었습니다.
오류 발생 시에는 화면 로그에 오류 내용을 표시하고, 가능한 경우 오류 로그 파일에도 저장합니다.
오류 로그 파일은 다음 형식으로 관리할 수 있습니다.
eIOT_ERROR_yyyyMMdd.txt
운영 중 장애가 발생했을 때 이 오류 로그는 원인 분석에 매우 중요합니다.
13. 기존 VB6.0 방식과 C# 방식의 차이
기존 VB6.0 프로그램은 단순하고 직관적이라는 장점이 있습니다.
하지만 최신 Windows 환경, 멀티스레드 처리, 비동기 소켓 처리, 예외 안정성 측면에서는 C# 기반이 더 유리합니다.
C# WinForms로 전환하면 다음과 같은 장점이 있습니다.
- 비동기 소켓 처리 가능
- 멀티 클라이언트 처리 용이
- 예외 처리 구조 개선
- 파일 로그 관리 편리
- UI와 통신 로직 분리 가능
- 향후 DB 연동 확장 용이
- MES, ERP, FEMS 연동 가능
- Windows 최신 환경 대응 용이
특히 Task, async/await, ConcurrentDictionary, CancellationToken 등을 활용하면 장시간 운영되는 서버 프로그램을 훨씬 안정적으로 구성할 수 있습니다.
14. 향후 확장 방향
현재 버전은 수신 데이터를 화면과 텍스트 파일로 저장하는 구조입니다.
향후에는 다음과 같은 기능을 추가할 수 있습니다.
1) MariaDB 또는 MS SQL 저장
수신 데이터를 DB에 저장하면 MES, ERP, FEMS와 직접 연동할 수 있습니다.
예를 들면 다음과 같은 테이블 구조를 만들 수 있습니다.
iot_receive_log
- id
- receive_time
- client_ip
- client_port
- raw_data
- parse_status
- created_at
2) 프로토콜 파싱
현재는 수신된 원문 데이터를 그대로 저장합니다.
향후 장비별 프로토콜을 정의하면 다음과 같이 데이터를 분리할 수 있습니다.
장비ID, 품목코드, LOT, 측정값, 판정, 발생시간
이렇게 분리하면 단순 로그가 아니라 생산 데이터로 활용할 수 있습니다.
3) 장비별 상태 모니터링
접속된 클라이언트별로 마지막 수신 시간을 관리하면 장비 상태를 판단할 수 있습니다.
예를 들면 다음과 같습니다.
- 정상: 1분 이내 데이터 수신
- 지연: 5분 이상 미수신
- 끊김: 소켓 연결 종료
- 오류: 비정상 데이터 수신
4) Windows Service 전환
현재는 WinForms 화면이 있는 서버 프로그램입니다.
운영 안정성을 더 높이려면 Windows Service 방식으로 전환하고, 별도의 모니터링 화면을 붙이는 구조도 가능합니다.
추천 구조는 다음과 같습니다.
Windows Service
- 소켓 수신
- 로그 저장
- DB 저장
- 장비 상태 관리
WinForms 관리자
- 상태 조회
- 로그 조회
- 접속 장비 확인
- 수동 명령 전송
5) Web Dashboard 연동
Flask, ASP.NET Core, React 등을 이용하면 웹 대시보드로 확장할 수 있습니다.
이를 통해 현장 PC뿐 아니라 사무실, 태블릿, 모바일에서도 장비 수신 상태를 확인할 수 있습니다.
15. 제조 현장에서의 활용 예
이 소켓 서버는 다음과 같은 업무에 활용할 수 있습니다.
- 설비 생산 실적 수집
- 검사기 측정 결과 수신
- 바코드 리더기 데이터 수신
- 계량기, 온도계, 전력량계 데이터 수집
- PLC 또는 장비 PC 연동
- MES 실적 자동 등록
- LOT 추적 데이터 수집
- FEMS 에너지 데이터 수집
- ESG 관련 에너지 사용량 데이터 수집
단순히 데이터를 받는 프로그램처럼 보이지만, 제조 시스템에서는 이런 데이터 수집 서버가 매우 중요한 역할을 합니다.
현장의 데이터가 실시간으로 수집되어야 MES, ERP, FEMS, ESG 시스템이 제대로 동작할 수 있기 때문입니다.
마무리
이번에 구성한 C# WinForms 기반 eIOT 소켓 서버는 기존 VB6.0 방식의 단순하고 직관적인 운영 화면은 유지하면서, 내부 구조는 최신 C# 방식으로 개선한 프로그램입니다.
핵심은 다음과 같습니다.
- TCP/IP 기반 실시간 수신
- 멀티 클라이언트 동시 처리
- 화면 로그와 파일 로그 분리
- 클라이언트 접속 상태 시각화
- PC 재부팅 후 자동 실행
- 오류 발생 시 프로그램 종료 방지
- 향후 MES, ERP, FEMS 연동 가능
제조 현장에서 가장 중요한 것은 데이터가 끊기지 않고 안정적으로 수집되는 것입니다.
작은 소켓 서버 하나라도 안정적으로 구성하면, 이후 생산관리, 설비관리, 에너지관리, 품질관리 시스템으로 확장할 수 있는 중요한 기반이 됩니다.
#조그만기술로세상을이롭게
#CSharp #WinForms #SocketServer #TCPIP #MES #IoT #FEMS #제조데이터수집 #스마트팩토리
'IT > C#' 카테고리의 다른 글
| C#의 MAUI란 무엇인가? (0) | 2026.06.22 |
|---|---|
| C#에서 WinForms 디자인 방식과 XAML은? (0) | 2026.06.18 |
| 인쇄툴로 SyncFusion 사용 가능해? (0) | 2026.06.04 |
| Syncfusion이란? (0) | 2026.06.04 |
| 라벨 프린터 종류와 블루투스 통신 이해하기 (0) | 2026.05.24 |