자료 참고 안내 1. 본 자료실의 모든 자료 저작권은 ㈜에이치앤에스에 있습니다.

본 자료는 개발하시는데 참고자료 용도로 사용하실 수 있으며 저작권 표시 없이 복사,게재, 출판 하실 수 없습니다. 외부 게재 사용 시 반드시 출처 항목에 회사명과 사이트 주소를 반드시 명시해 주시기 바랍니다.
[표기 예] 출처 : ㈜에이치앤에스(www.hnsts.co.kr) 또는 ㈜HNS(www.hnsts.co.kr)

2. 제품 개발 시 내용과 예제 코드는 수정 및 검증작업을 직접 하셔야 하며 문제 발생에 대한 책임은 ㈜HNS사와 무관합니다.

본사는 자료를 최신내용으로 유지하기 위해 노력하고 있으며 제공되는 정보의 오류 및 내용이 정확하지 않을 경우 사전 공지 없이 업데이트 될 수 있습니다. 자료의 문제점 발견 시 본사로 문의주시면 검토하여 자료를 수정하도록 하겠습니다.

[C#] SmartTCPClient-Wrapping Class 를 이용한 TCPClient 프로그램 구현 방법
작성일 2019-12-20 수정일 2022-10-06 조회수 2658
분류 SmartX Framework
적용
플랫폼
키워드 SmartTCPClient, TCPIP, Network
첨부파일 TechNote78_Example.zip

본 자료는
1. SmartTCPClient-Wrapping Class 소개
2. 사용자 수정 영역
3. SmartTCPClient-Wrapping Class 연결(Connect) 구조
4. SmartTCPClient-Wrapping Class 통신 구조
[CASE-1] 요청(Request/Send) and 응답(Response/Receive) 구성
[CASE-2] Server Event Data 수신
5. SmartTCPClient-Wrapping Class를 이용한 통신에러 확인
5-1. Connect 실패 유형에 따른 확인 항목
5-2. Send 실패 유형에 확인 항목
6. 예제 설명
6-1. 프로토콜
6-2. Client
6-3. Server

순서로 진행합니다.

1. SmartTCPClient-Wrapping Class 소개

TCP/IP Network Client 측 통신 프로그램 작성시 발생될 수 있는 여러가지 예외 처리 및 프로토콜에 의한 송수신시 필요한 처리를 별도로 작성할 수 있도록 만들어진 Wrapping Class를 제공하고있습니다. 따라서 개발자는 SmartTCPClient-Wrapping Class를 재사용하여 필요한 부분만을 수정 및 적용하므로 프로그램을 편리하게 작성할 수 있습니다. 개발자는 Wrapping Class 적용을 위하여 대부분 사용자 정의 영역의 코드를 재정의 및 수정하시면 됩니다. Wrapping Class는 SmartTCPClient Component를 기반으로 연동하여 동작 합니다.

[SmartTCPClient-Wrapping Class 특징]

1. 초기 Network 가용 상태 확인 기능
2. Connect 시 동기/비동기 지원
3. Connect 실패에 따른 재시도 처리 기능 지원
4. Connect 실패에 따른 Network 상 문제원인을 확인할 수 있는 기능 지원
5. 다양한 프로토콜 적용을 위한 사용자 정의 영역의 코드 지원
6. 요청(Request/Send) and 응답(Response/Receive) 확인 및 상태 값 리턴
7. Server로부터 수신되는 이벤트성 요청 수신 큐(Queue) 지원

본문을 확인하여 프로젝트에 SmartTCPClient-Wrapping Class를 적용해보시기 바라며, 적용이 어려우신 경우 원격으로 적용을 도와드리도록 하겠습니다.

2. 사용자 수정 영역

SmartTCPClient-Wrapping Class는 크게 미리 정의된 영역과, 사용자가 코드를 수정해야 하는 사용자 정의 영역으로 나눌 수 있습니다. 사용자 정의 영역에서 상황 별 사용자가 수정해야 하는 메서드는 다음과 같습니다. 특히, Send, Receive 부분은 반드시 사용자의 프로토콜에 맞도록 코드를 작성해야 합니다.

참고메서드의 호출 구조 및 사용 시점과 예제에 사용된 프로토콜 정보는 본문내용을 참고하시기 바랍니다.
  • ※ Connect 동작 관련
  • 인터페이스 void ConnectRetryFail_User(NetworkConnectStatus eNetworkStatus)
    권장동작 최종적으로 Connect에 실패 한 경우 NetworkConnectStatus 열거값에 따라 Connect 재시도 또는 Connect 실패 원인을 사용자에게 알리는 처리를 하도록 작성합니다.
    현재 동작 ConnectMaxRetryCount로 지정한 횟수 만큼 Connect를 시도했으나, 서버와 연결에 실패한 경우 호출되며, 인자값으로 전달받은 네트워크 상태에 따라 Connect를 재시도 하거나, 네트워크 상태에 따른 처리 방법을 메시지 박스에 출력합니다.
  • ※ Send (Request-Response) 동작 관련
  • 인터페이스 Data_Packet Command_RequestResponse(string strCommand, int iCh, byte[] chData)
    권장동작 사용하는 프로토콜에 따라 인자 형식을 변경하고, Request 결과(SendStatus)에 따라 Response 수신 처리 작성과, Request 실패 처리를 작성합니다.
    현재 동작 Server로 Command에 따른 데이터 전송(Request) 후 Server 의 응답(Response)을 수신받을 때까지 대기하고 Request-Response 과정의 결과(CommandStatus)를 리턴 하도록 처리함
    인터페이스 SendStatus Request_Command(string strCommand, int iCh, byte[] chData)
    권장동작 사용하는 프로토콜에 맞게 인자 형식을 변경하고 프레임을 구성하여 Server로 Request 전송 처리하는 과정을 작성합니다.
    현재 동작 예제 프로토콜에 맞도록 프레임 구성 후 Server로 데이터를 전송(Request)하고, 데이터 전송 상태(SendStatus)를 리턴 하도록 처리함
    인터페이스 Data_Packet Response_Parsing(byte[] chData, bool bAckRecv)
    권장동작 수신받은 Response 데이터나 Server에서 임의의 시점에 수신받은 데이터(Server Event Data)를 사용하는 프로토콜에 맞게 검증 후 파싱하여 구조체 데이터에 저장하는 과정을 작성합니다.
    현재 동작 Request 후 Server로부터 응답(Response)받거나, 임의의 시점에 수신받은(Server Event Data) 데이터를 사용자의 프로토콜에 맞게 검증 및 파싱 후 데이터 패킷(Data_Packet)을 구성하여 (채워넣어) 리턴 하도록 처리함
    인터페이스 void ACK_OnReceiveHandler_User(byte[] receiveData)
    권장동작 Request 전송 후 올바르게 Response 수신 받았을 때의 처리를 작성합니다. Response 수신 완료 처리 및 사용자의 프로토콜에 맞게 처리 코드를 작성합니다.
    현재 동작 현재 코드는 공란입니다.
    ※ 특별한 경우가 아니라면 사용하지 않습니다.
  • ※ Receive (Sever Event Send) 동작 관련
  • 인터페이스 void OnReceiveHandler_User(byte[] receiveData)
    권장동작 서버에서 임의의 시점에 데이터(Server Event Data)를 수신 받았을 때의 처리를 작성합니다.
    Server Event Data 수신 알림 및 사용자의 프로토콜에 맞게 처리 코드를 작성합니다.
    현재 동작 현재 코드는 공란입니다.
    ※ 특별한 경우가 아니라면 사용하지 않습니다.
참고SmartTCPClient-Wrapping Class 생성자의 차이점 및 사용시점

SmartTCPClient-Wrapping Class는 네트워크 체크를 위해 SmartConfigs 컴포넌트를 이용하여 Ping 통신을 진행합니다. 이때 사용하는 SmartConfigs는 생성자에서 생성 또는 참조를 받게 됩니다. 따라서 생성자는 2가지가 존재하며 인자값에 따른 생성자의 차이점 및 사용시점은 다음과 같습니다.

[표] 생성자 CSmartTCPClientWrapping 의 인자값에 따른 차이점 및 사용시점
생성자 CSmartTCPClientWrapping
인자값 SmartTCPClient
pSmartTCPClient
SmartTCPClient
pSmartTCPClient,
SmartConfigs
pSmartConfig
차이점 클래스 내부에
SmartConfigs를
생성함
메인 프로젝트의
SmartConfigs 컴포넌트의
참조를 전달받음
사용시점 메인 프로젝트에서
SmartConfigs 컴포넌트를
사용하지 않음
메인 프로젝트에서
SmartConfigs 컴포넌트를
사용함
3. SmartTCPClient-Wrapping Class 연결(Connect) 구조

SmartTCPClient-Wrapping Class에서 연결 방식은 동기/비동기 방식이 있으며, Connect 실패 시 재시도 회수와 간격을 설정할 수 있습니다. 또한 Network 상태를 확인하는 기능을 이용하여 현재 Network가 가용 상태인지 확인할 수 있습니다. 서버 연결 구조는 아래 그림과 같습니다.

connect
A) 사용자 수정 영역

서버와 연결에 실패한 경우 ConnectRetryFail_User() 메서드는 Network_Check() 메서드로부터 연결실패 원인을 인자값으로 전달받아 호출됩니다.
예제의 ConnectRetryFail_User() 메서드 코드는 연결실패 원인에 따른 처리 사항을 메시지박스로 출력하게 되어있으며, 다르게 처리하려는 경우 직접 코드를 수정하여 적용하시기 바랍니다.

[기본로직]

서버와 연결에 실패한 경우 ConnectRetryFail_User() 메서드는 Network_Check() 메서드로부터 연결실패 원인을 인자값으로 전달받아 호출됩니다.
예제의 ConnectRetryFail_User() 메서드 코드는 연결실패 원인에 따른 처리 사항을 메시지박스로 출력하게 되어있으며, 다르게 처리하려는 경우 직접 코드를 수정하여 적용하시기 바랍니다.

[기본 로직]
※ 메서드(함수)
인터페이스명 ConnectRetryFail_User
설명 ConnectMaxRetryCount로 지정한 횟수 만큼 Connect를 시도했으나, 서버와 연결에 실패한 경우 호출되는 메서드로, 인자값으로 전달받은 네트워크 상태에 따라 Connect를 재시도 하거나, Connect를 중단하도록 하는 메서드

[NetworkConnectStatus 인자 값]
• Available : 서버와 연결 가능한 상태
• NetworkDeviceProblems : 네트워크 장비(공유기, 허브) 문제 발생. Ping 통신 실패
• ServerProblems : 서버 확인. Ping 통신 실패
• ServerProcessProblems : 서버 프로그램 확인. Ping 통신은 성공했으나, Connect 에 실패함

⊙ void ConnectRetryFail_User(NetworkConnectStatus eNetworkStatus)
B) 미리 정의된 영역 [기본 로직]
명칭 리턴값 설명
Connect
RetryTimer_
Tick
void
(Event
Method)
Connect 재시도 타이머
smartTCPClient_
OnConnected
void
(Event
Method)
연결방식이 비동기 방식인 경우, 연결상태 확인 이벤트
Connect
RetryTimer_
Tick
void
(Event
Method)
Connect 재시도 타이머
Network_
Check
Network
Connect
Status
통신에러 원인을 확인
IPAddress
Available
Check
bool 공유기(허브) 연결 확인 : Ping 체크 후 결과를 리턴합니다.
Server
Available
Check
bool 서버 연결 확인 : Ping 체크 후 결과를 리턴합니다. 단, 서버에서 Ping 을 막은 경우 확인 불가
Server
Process
Check
bool 서버 프로그램 확인 : Connect 체크
Connect
ReTry
void Connect 재시도
[외부 인터페이스]
※ 프로퍼티(속성)
인터페이스명 IsNetworkAvailable
설명 공유기(허브)의 연결상태를 체크
• IPAddressAvailableCheck() 의 리턴값을 반환합니다.
인터페이스명 ConnectMaxRetryCount
설명 연결 재시도 횟수를 설정
인터페이스명 ConnectRetryInterval
설명 연결 재시도 간격을 설정
인터페이스명 Synchronous_Connect
설명 서버 연결 모드를 설정(동기, 비동기)
인터페이스명 Synchronous_Receive
설명 서버 수신 모드를 설정(동기, 비동기)
인터페이스명 NetworkDeviceIP
설명 공유기(허브) IP를 설정
인터페이스명 ServerAddress
설명 서버 IP를 설정
인터페이스명 IsConnected
설명 서버와 연결 상태를 확인
[ConnectionStatus 리턴 값]
• Connected: 서버와 연결됨
• DisConnected: 서버와 연결이 해제됨
• Connecting: 서버와 연결중인 상태
※ 메서드(함수)
인터페이스명 Connect
설명 서버와 연결을 시도합니다 .
⊙ void Connect(int iPort, int iTimeoutInterval)
인터페이스명 Disconnect
설명 서버와 연결을 해제 합니다 .
⊙ void Disconnect()
4. SmartTCPClient-Wrapping Class 통신 구조

SmartTCPClient-Wrapping Classs에서 기본적인 통신 구조는 두가지 모델을 지원하고있습니다.

[CASE-1] 요청(Request/Send) and 응답(Response/Receive) 구성

요청-응답(Request-Response)구조는 Client에서 Server로 데이터를 요청하면 Server는 반드시 Client로 응답을 전송해야 하는 구조로, 송/수신 구조는 아래 그림과 같습니다.

send
A) 사용자 수정 영역

Command_RequestResponse() 메서드는 사용자의 프로토콜에 따른 Request-Response 동작을 하는 메서드로, 내부에서 Request_Command() 메서드를 호출하여 서버로 프로토콜에 따른 Request 프레임 전송 후 미리 정의 된 상수 ACKTIMEOUT 시간동안 서버의 Response 프레임 수신을 대기하며 Command_RequestResponse() 메서드로 데이터 전송 상태를 리턴합니다.
서버로부터 Response 프레임이 수신되었다면, ACK_OnReceiveHandler_User() 메서드가 호출되어 사용자가 원하는 처리를 할 수 있습니다.
또한 Command_RequestResponse() 메서드 내부에서 Response_Parsing() 메서드가 호출되어 수신받은 Response 프레임을 프로토콜에 맞게 파싱(Parsing)작업을 진행합니다.
따라서 사용자는 Command_RequestResponse(),Request_Command(),Response_Parsing() 메서드의 코드를 사용자의 프로토콜에 맞도록 수정하는 작업이 반드시 필요합니다.

[기본 로직]
※ 메서드(함수)
인터페이스명 Request_Command
설명 사용자의 프로토콜에 맞는 프레임 구성 후 Server로 데이터를 전송하고, 데이터 전송 상태(SendStatus)를 리턴하는 메서드

[SendStatus 리턴 값]
• Success : 데이터 전송 후 서버로부터 응답을 받음
• ConnectionFailed : 서버와 연결되지 않음
• SendFailed : 데이터 전송에 실패 (Send관련 메서드에서 False리턴)
• AckFailed : 데이터 전송에 성공했으나, 서버로부터 응답이 오지 않음

SendStatus Request_Command(string strCommand, int iCh, byte[] chData)
인터페이스명 Response_Parsing
설명 Request 후 Server로부터 응답(Response)받거나, 임의의 시점에 수신받은 (Server Event Data) 데이터를 사용자의 프로토콜에 맞게 검증 및 파싱 후 데이터 패킷(Data_Packet)을 구성하여 리턴하는 메서드

[Data_Packet 구조체 멤버]
public byte[] chCommand: 송수신한 Command를 저장
public byte chChannel: 송수신한 Channel을 저장
public byte[] chData: 송수신한 Data를 저장
public CommandStatus chCommandStatus: 수신받은 데이터의 상태를 저장

Data_Packet Response_Parsing(byte[] chData, bool bAckRecv)
인터페이스명 ACK_OnReceiveHandler_User
설명 서버로 Request 후 정상적으로Response 받은 경우 발생하는 메서드
⊙ void ACK_OnReceiveHandler_User(byte[] receiveData)
[외부 인터페이스]
※ 메서드(함수)
인터페이스명 Command_RequestResponse
설명 Server로 Command에 따른 데이터 전송(Request) 후 Server 의 응답(Response)을 수신받을 때까지 대기하고 Request-Response 과정의 결과(CommandStatus)를 리턴하는 메서드

[Data_Packet 구조체 멤버]
public byte[] chCommand : 송수신한 Command를 저장
public byte chChannel : 송수신한 Channel을 저장
public byte[] chData : 송수신한 Data를 저장
public CommandStatus chCommandStatus : 수신받은 데이터의 상태를 저장

Data_Packet Command_RequestResponse(string strCommand, int iCh, byte[] chData)
B) 미리 정의된 영역 [기본 로직]
명칭 리턴값 설명
SmartTCPClient_SendData() bool 실제 Server로 데이터를 전송하는 메서드로 데이터 전송 후 ACK 응답 (Response)이 수신될 때 까지 대기 합니다.
SmartTCPClient_OnReceiveHandler() void
(Event
Method)
Server로부터 데이터를 수신받을 때 발생하는 이벤트로 수신받은 데이터를 List에 저장하고 ACK응답 수신성공 처리를 합니다.
[외부 인터페이스]
※ 메서드(함수)
인터페이스명 SendData
설명 Server로 데이터 전송 후 전송 상태를 리턴합니다.

[SendStatus 리턴 값]
• Success : 데이터 전송 후 서버로부터 응답을 받음
• ConnectionFailed : 서버와 연결되지 않음
• SendFailed : 데이터 전송에 실패 (Send관련 메서드에서 False리턴)
• AckFailed : 데이터 전송에 성공했으나, 서버로부터 응답이 오지 않음

SendStatus SendData(byte[] sendData)
[CASE-2] Server Event Data 수신

Client의 Request 전송과 관계없이 Server로부터 임의의 시점에 데이터를 수신받는 경우이며, 수신 구조는 아래 그림과 같습니다.

receive
A) 사용자 수정 영역

서버로부터 임의의 시점에 데이터가 수신되면 OnReceiveHandler_User() 메서드가 호출되어 사용자가 원하는 처리를 할 수 있으며, 수신받은 데이터는 Response_Parsing() 메서드에서 사용자의 프로토콜에 맞게 파싱되어 Data Queue인 m_EventResponsePacket 에 저장(Enqueue)됩니다.
사용자는 GetServerEventReceiveQueueCount 프로퍼티(속성)을 확인하여 Queue에 데이터가 있다면 GetServerEventReceiveQueue() 메서드를 호출하여 수신받은 데이터를 가져올(Dequeue) 수 있습니다.

[기본로직] ※ Server Event Data Receive Queue
명칭 자료형 설명
m_EventResponsePacket Data_Packet 서버에서 임의로 송신한 데이터를 저장할 Queue
SmartTCPClient_OnReceiveHandler() void
(Event
Method)
Server로부터 데이터를 수신받을 때 발생하는 이벤트로 수신받은 데이터를 List에 저장하고 ACK응답 수신성공 처리를 합니다.
※ 메서드(함수)
인터페이스명 OnReceiveHandler_User
설명 Server로부터 임의의 시점에 데이터가 수신될 경우 발생하는 메서드(Server Event Data 처리)
void OnReceiveHandler_User(byte[] receiveData)
인터페이스명 Response_Parsing
설명 Request 후 Server로부터 응답(Response)받거나, 임의의 시점에 수신받은 (Server Event Data) 데이터를 사용자의 프로토콜에 맞게 검증 및 파싱 후 데이터 패킷(Data_Packet)을 구성하여 리턴하는 메서드

[Data_Packet 구조체 멤버]
public byte[] chCommand: 송수신한 Command를 저장
public byte chChannel: 송수신한 Channel을 저장
public byte[] chData: 송수신한 Data를 저장
public CommandStatus chCommandStatus: 수신받은 데이터의 상태를 저장

Data_Packet Response_Parsing(byte[] chData, bool bAckRecv)
[외부 인터페이스]
※ 프로퍼티(속성)
인터페이스명 GetServerEventReceiveQueueCount
설명 Queue에 저장된 패킷의 수를 읽습니다.
※ 메서드(함수)
인터페이스명 GetServerEventReceiveQueue
설명 Queue에 저장된 패킷을 가져옵니다.(Dequeue)

[Data_Packet 구조체 멤버]
public byte[] chCommand: 송수신한 Command를 저장
public byte chChannel: 송수신한 Channel을 저장
public byte[] chData: 송수신한 Data를 저장
public CommandStatus chCommandStatus: 수신받은 데이터의 상태를 저장

Data_Packet GetServerEventReceiveQueue()
B) 미리 정의된 영역
명칭 자료형 설명
SmartTCPClient_OnReceiveHandler() void
(Event Method)
Server로부터 데이터를 수신받을 때 발생하는 이벤트로 수신받은 데이터를 Queue에 저장 (Enqueue)하고, 사용자 처리 메서드를 발생시킵니다.

5. SmartTCPClient-Wrapping Class를 이용한 통신에러 확인

TCP/IP 통신 중 다양한 통신 에러가 발생할 수 있으며 유형에 따른 확인 항목을 안내합니다.

참고네트워크가 연결되지 않을 때 점검 사항

네트워크가 연결되지 않는 경우에는 “커뮤니티 → 자주하는 질문 → 32. 네트워크가 연결이 되지 않을 때 점검 사항” 내용을 참조하시기 바랍니다.
5-1. Connect 실패 유형에 따른 확인 항목

Connect 실패 시 ConnectRetryFail_User() 메서드의 인자값을 확인하여 통신 에러 원인을 파악할 수 있습니다.

[표] NetworkConnectStatus 열거값에 따른 확인 항목

리턴값 확인 항목
NetworkDeviceProblems 공유기의 상태와, 단선되지 않았는지 확인
ServerProblems 서버로 Ping 통신이 되지 않음. 서버가 네트워크에 연결이 되어있는지 확인
ServerProcessProblems 서버로 Ping 통신이 되어 네트워크는 정상이지만, 서버 프로그램이 정상적으로 동작하는지 확인
5-2. Send/Receive 실패 유형에 따른 확인 항목

Send_Data(), Command_RequestResponse() 메서드 호출 후 또는 이벤트 데이터 수신 Queue의 SendStatus 또는 CommandStatus 열거값을 확인하여 통신 에러 원인을 파악할 수 있습니다.

[표2] SendStatus / CommandStatus 열거값에 따른 확인 항목

리턴값 확인 항목
ConnectionFailed 서버와 연결되지 않음. 서버 연결 후 전송 시도
SendFailed 데이터 전송에 실패. 네트워크 장비 이상 여부와 케이블이 단선되었는지 확인
AckFailed 데이터 전송에 성공했으나, 서버로부터 응답이 오지 않음. 서버 프로그램 확인
CommandInvalid 수신받은 Command가 잘못됨. 서버 프로그램 확인
DataInvalid 수신받은 데이터가 잘못됨. 서버 프로그램 확인
6. 예제 설명
6-1. 프로토콜

예제에 사용된 프로토콜은 Request-Response 통신구조로, Command는 총 8개가 있으며 Channel은 4Ch로 구성되어 있습니다. Data는 Binary 데이터이며 나머지 항목은 ASCII 데이터 입니다.

[Command 코드에 따른 Request 프레임 구조 ]

CMD
코드
STX
(1Byte)
CMD
(3Byte)
Channel
(1Byte)
Data ETX
(1Byte)
온도읽기
(TMR)
0x40 0x54 0x4D 0x52 0Ch : 0x30
1Ch : 0x31
2Ch : 0x32
3Ch : 0x33
None 0x3B
온도쓰기
(TMW)
0x54 0x4D 0x57 4Byte
습도읽기
(HMR)
0x48 0x4D 0x52 None
습도쓰기
(HMW)
0x48 0x4D 0x57 4Byte
수위읽기
(WTR)
0x57 0x54 0x52 None
수위쓰기
(WTW)
0x57 0x54 0x52 4Byte
거리읽기
(DTR)
0x44 0x54 0x52 None
거리쓰기
(DTW)
0x44 0x54 0x57 4Byte

[Sever의 Command별 Response 또는 Event Send 프레임 구조

CMD
코드
STX
(1Byte)
CMD
(3Byte)
Channel
(1Byte)
Data
(4Byte)
ETX
(1Byte)
온도읽기
(TMR)
0x40 0x54 0x4D 0x52 0Ch : 0x30
1Ch : 0x31
2Ch : 0x32
3Ch : 0x33
Response
or
Event Data
0x3B
온도쓰기
(TMW)
0x54 0x4D 0x57
습도읽기
(HMR)
0x48 0x4D 0x52
습도쓰기
(HMW)
0x48 0x4D 0x57
수위읽기
(WTR)
0x57 0x54 0x52
수위쓰기
(WTW)
0x57 0x54 0x52
거리읽기
(DTR)
0x44 0x54 0x52
거리쓰기
(DTW)
0x44 0x54 0x57
6-2. Client

SmartTCPClient-Wrapping Class 예제 프로그램의 동작 순서(구조)는 다음과 같습니다.

1. 프로그램 시작시 IsNetworkAvailable 속성으로 네트워크 디바이스(공유기, 허브)와 연결상태를 확인
2. 네트워크 사용이 가능한 경우 Connect() 메서드를 호출하여 서버와 연결하거나 Disconnect() 메서드를 호출하여 서버와 연결을 해제한다.
3. 서버로 Command에 따른 데이터를 Request 한다.
(Send_Data() 또는 Command_RequestResponse() 메서드 호출)
4. Request 후 서버로부터 Response 응답을 받는다.(ACK_OnReceiveHandler_User() 메서드 발생)
5. 서버에서 임의로 송신한 Event Data를 수신한다.
(m_EventResponsePacket Queue에 데이터 추가 및 OnReceiveHandler_User() 메서드 발생)
6. Queue의 데이터를 확인하여 Dequeue 한다.
(GetServerEventReceiveQueueCount 속성 및 GetServerEventReceiveQueue() 메서드 호출)

6-3. Server

SmartTCPMultiServer를 이용한 예제 프로그램의 동작 순서(구조)는 다음과 같습니다.

1. Start() 메서드를 호출하여 Server를 Open 합니다.
2. smartTCPMultiServer1_OnReceiveHandler 이벤트에서 Request 데이터 수신 후 파싱하여 Response 데이터를 전송합니다.
3. Client로 임의의 시점에 Event Data를 전송합니다.

C# 예제코드

소스코드는 참고 및 학습용으로 버그 및 여러가지 문제가 있을수 있습니다.

class CSmartTCPClientWrapping
{
// 생성자 1 : 프로젝트에서 SmartConfigs를 사용하지 않는 경우
public CSmartTCPClientWrapping(SmartTCPClient pSmartTCPClient)
{
m_pSmartTCPClient = pSmartTCPClient;
m_bConnected = false;
m_bConnectFirst = false;
m_TimerConnectRetry = null;
m_bConnecting = false;
m_bSendData = false;
m_bAckCompletion = false;
m_ListReceiveData = new List<byte>();
smartConfig = new SmartConfigs();
}

// 생성자 2 : 프로젝트에서 SmartConfigs를 사용하는 경우
public CSmartTCPClientWrapping(SmartTCPClient pSmartTCPClient, SmartConfigs pSmartConfig)
{
m_pSmartTCPClient = pSmartTCPClient;
m_bConnected = false;
m_bConnectFirst = false;
m_TimerConnectRetry = null;
m_bConnecting = false;
m_bSendData = false;
m_bAckCompletion = false;
m_ListReceiveData = new List<byte>();
smartConfig = pSmartConfig;
}

// 네트워크 상태를 진단하기 위한 열거값
public enumNetworkConnectStatus : int
{
Available = 0, // 서버와 연결 가능한 상태
NetworkDeviceProblems = 1, // 네트워크 장비(공유기, 허브) 문제 발생. Ping 통신 실패
ServerProblems = 2, // 서버 확인. Ping 통신 실패
ServerProcessProblems = 3, // 서버 프로그램 확인. Ping 통신은 성공했으나, Connect 에 실패함
}

// 데이터 전송 상태 체크를 위한 열거값
public enumSendStatus : int
{
Success = 0, // 데이터 전송 후 서버로부터 응답을 받음
ConnectionFailed = 1, // 서버와 연결되지 않음
SendFailed = 2, // 데이터 전송에 실패 (Send관련 메서드에서 False리턴)
AckFailed = 3, // 데이터 전송에 성공했으나, 서버로부터 응답이 오지 않음.
}

// 데이터 수신 상태 체크를 위한 열거값
public enum CommandStatus : int
{
Success = 0, // 데이터 전송 후 서버로부터 응답을 받음
ConnectionFailed = 1, // 서버와 연결되지 않음
SendFailed = 2, // 데이터 전송에 실패 (Send관련 메서드에서 False리턴)
AckFailed = 3, // 데이터 전송에 성공했으나, 서버로부터 응답이 오지 않음.
CommandInvalid = 4, // 수신받은 Command가 잘못됨
DataInvalid = 5, // 수신받은 데이터가 잘못됨
}

// 연결 상태 체크를 위한 열거값
public enum ConnectionStatus : int
{
Connected = 0, // 서버와 연결됨
DisConnected = 1, // 서버와 연결이 해제됨
Connecting = 2, // 서버와 연결중인 상태
}

// 데이터 송수신 패킷 구조체
public struct Data_Packet
{
public byte [] chCommand; // 송수신한 Command를 저장
public byte chChannel; // 송수신한 Channel을 저장
public byte [] chData; // 송수신한 Data를 저장
public CommandStatus chCommandStatus; // 수신받은 데이터의 상태를 저장
}

#region ********************************* [ 주요 멤버 변수 ] **************************************

private SmartTCPClient m_pSmartTCPClient; // SmartTCPClient 사용을 위한 변수
private SmartConfigs smartConfig; // SmartConfigs 사용을 위한
private Timer m_TimerConnectRetry; // 연결 재시도를 위한 타이머

private int m_iConnectTimeoutInterval; // 동기방식일때 최대 연결시간을 저장할 변수
private bool m_bConnected; // 현재 연결 상태를 확인할 플래그
private bool m_bConnecting; // 현재 연결 시도 중인지 확인할 플래그
private bool m_bConnectFirst; // 최초 연결시 Connect() 메서드를 빨리 호출하기 위한 플래그

private int m_iConnectRetryCount; // 연결 재시도 횟수를 저장할 변수
private bool m_bSynchronous_Connect; // Connect의 동기/비동기 방식을 저장할 변수
private bool m_bSynchronous_Receive; // Receive의 동기/비동기 방식을 저장할 변수
private int m_iConnect_MaxRetryCount; // 연결 재시도 횟수를 저장할 변수
private int m_iConnect_RetryInterval; // 연결 재시도 간격을 저장할 변수

private string m_strNetworkDeviceIPAddress; // 공유기(허브)의 IP를 저장할 변수
private string m_strServerIPAddress; // 서버의 IP를 저장할 변수

private bool m_bSendData; // 클라이언트에서 서버로 Request 했는지 확인할 플래그

private bool m_bAckCompletion; // 서버에서 올바르게 Response 했는지 확인할 플래그
private <List> m_ListReceiveData; // 수신한 데이터를 저장할 List

#endregion

#region ********************************* [ 상수 정의 ] *******************************************

private const int SERVERCONNECT_TIMEOUTINTERVAL = 30000; // 서버 상태 확인 시 사용할 TimeOut 값
private const int SENDDATA_RETRYCOUNT = 3; // 데이터 전송 실패 시 재전송 할 횟수
private const int ACKTIMEOUT = 5000; // Request 후 Response를 대기할 TimeOut 값

#endregion

#region ********************************* [ 기본 로직 ] *******************************************

// Connect 재시도 타이머
private void ConnectRetryTimer_Tick(object sender, EventArgs e)
{
m_TimerConnectRetry.Enabled = false;

// 처음 Connect 하는 경우 다음 Connect 시간을 설정
if (m_bConnectFirst == true)
{
m_TimerConnectRetry.Interval = m_iConnect_RetryInterval;
m_bConnectFirst = false;
}

// Connect 방식에 따른 처리(동기, 비동기)
if (m_bSynchronous == true)
{
bool bRet; // 연결상태를 저장할 변수

// 연결 제한시간 설정값에 따른 처리
if (m_iConnectTimeoutInterval == -1)
{
// 연결 제한시간 없음
bRet = m_pSmartTCPClient.Connect();
}
else
{
// 연결 제한시간 있음
bRet = m_pSmartTCPClient.Connect(m_iConnectTimeoutInterval);
}

// 연결 상태에 따른 처리
if (bRet == true)
{
// 연결 성공 시 플래그 설정
m_TimerConnectRetry.Stop();
m_bConnected = true;
m_bConnecting = false;
return;
}
else
{
// 연결 실패 시 재시도 횟수 증가
m_iConnectRetryCount++;
}

// 재시도 횟수에 따른 처리
if (m_iConnectRetryCount < m_iConnect_MaxRetryCount)
{
m_TimerConnectRetry.Start();
}
else
{
// 재시도 횟수 만료 시 연결 실패 처리
m_TimerConnectRetry.Stop();
ConnectRetryFail();
}
}
else
{
// 비동기 방식
m_pSmartTCPClient.Connect();
}
}

// 연결방식이 비동기 방식인 경우 이벤트로 리턴값을 확인
private void smartTCPClient_OnConnected(bool bConnected)
{
// 연결 상태에 따른 처리
if (bConnected == true)
{
// 연결 성공 시 플래그처리
m_TimerConnectRetry.Enabled = false;
m_bConnected = true;
m_bConnecting = false;
}
else
{
// 연결 실패 시 처리
m_bConnected = false;
m_iConnectRetryCount++;

if (m_iConnectRetryCount < m_iConnect_MaxRetryCount)
{
m_TimerConnectRetry.Enabled = true;
}
else
{
m_TimerConnectRetry.Enabled = false;
ConnectRetryFail();
}
}
}

// 연결 실패한 경우 통신에러 원인을 확인
private void ConnectRetryFail()
{
NetworkConnectStatus eNetworkStatus;
// NetWork Check
eNetworkStatus = Network_Check();

// 네트워크가 사용불가능할 때 사용자가 처리하도록 한다.
if (eNetworkStatus != NetworkConnectStatus.Available)
{
ConnectRetryFail_User(eNetworkStatus);
}
}

// 통신에러 원인을 확인
privateNetworkConnectStatus Network_Check()
{
// 공유기(허브)연결 확인 : Ping 체크
if (IPAddressAvailableCheck() == false)
{
return NetworkConnectStatus.NetworkDeviceProblems;
}

// 서버연결 확인 : Ping 체크
if (ServerAvailableCheck() == false)
{
return NetworkConnectStatus.ServerProblems;
}

// 서버 프로그램 확인 : Connect 체크
if (ServerProcessCheck(SERVERCONNECT_TIMEOUTINTERVAL) == false)
{
return NetworkConnectStatus.ServerProcessProblems;
}

// 모두 정상인 경우
return NetworkConnectStatus.Available;
}

// 서버 프로그램 확인 : Connect 체크
private bool ServerProcessCheck(int iServerConnectTimeout)
{
bool bRet; // 서버 프로그램 상태를 저장

// 비동기 방식인 경우 동기 방식으로 변경하여 테스트
if (m_bSynchronous_Connect == false)
{
m_pSmartTCPClient.ConnectCallBackType = SmartTCPClient.CALLBACKTYPE.Sync;
}

// Connect 시도 후 결과를 저장
bRet = m_pSmartTCPClient.Connect(iServerConnectTimeout);

// 비동기 방식인 경우 변경한 연결방식을 재설정
if (m_bSynchronous_Connect == false)
{
m_pSmartTCPClient.ConnectCallBackType = SmartTCPClient.CALLBACKTYPE.Async;
}

// Connect 결과가 성공인경우 서버를 닫고 값을 리턴
if (bRet == true)
{
m_pSmartTCPClient.Close();
return true;
}

// 실패한 경우 False 리턴
return false;
}

// 공유기(허브) 연결 확인 : Ping 체크
private bool IPAddressAvailableCheck()
{
// 공유기(허브) IP 설정이 안되있는 경우 False 리턴
try
{
if (smartConfig.IPSettings.DeviceIP == "")
{
return false;
}
}
catch (InvalidCastException)
{
return false;
}

// Ping 정보 확인을 위한 변수 생성
SmartX. CIPSetting.PINGRESULTINFO pingResultInfo = new SmartX. CIPSetting.PINGRESULTINFO ();

// 공유기(허브)로 Ping 통신
if (smartConfig.IPSettings.PingIP(m_strNetworkDeviceIPAddress, ref pingResultInfo) == true)
{
// Ping 성공 시 true 리턴
return true;
}

// Ping 실패 시 false 리턴
return false;
}

// 서버 연결 확인 : Ping 통신(서버에서 Ping을 막은 경우 확인 불가)
private bool ServerAvailableCheck()
{
// Ping 정보 확인을 위한 변수 생성
SmartX. CIPSetting.PINGRESULTINFO pingResultInfo = new SmartX. CIPSetting.PINGRESULTINFO ();
// 서버로 Ping 통신
if (smartConfig.IPSettings.PingIP(m_strServerIPAddress, ref pingResultInfo) == true)
{
// Ping 성공 시 true 리턴
return true;
}

// Ping 실패 시 false 리턴
return false;
}

// Connect 재시도
private void ConnectReTry()
{
// 현재 연결이 되있는 경우 연결해제
if (m_bConnected == true)
{
m_pSmartTCPClient.Close();
m_bConnected = false;
}
// 값 재설정 후 timer 시작
m_bConnectFirst = true;
m_iConnectRetryCount = 0;
m_bConnecting = true;
m_TimerConnectRetry.Start();
}

// 데이터를 실제로 전송하는 메서드
private bool SmartTCPClient_SendData(byte[] datas)
{
bool bRet; // 전송상태를 저장

// 데이터 재전송 횟수(상수)만큼 반복하여 데이터 전송
for (int i = 0; i < SENDDATA_RETRYCOUNT; i++)
{
// 데이터 전송 후 결과를 저장
bRet = m_pSmartTCPClient.SendByte(datas);

// 데이터 전송 성공 시 처리
if (bRet == true)
{
// Request 송신 성공
m_bSendData = true;

return true;
}
System.Threading. Thread.Sleep(100);
}

// 데이터 전송 실패 처리
return false;
}

// 데이터 수신시 발생하는 이벤트
private void SmartTCPClient_OnReceiveHandler(byte[] datas)
{
// 수신데이터를 리스트에 추가
m_ListReceiveData.AddRange(datas);

// Request 요청에 의한 Response 수신인지 확인
if (m_bSendData == false)
{
// 서버에서 임의로 송신한 데이터
// 수신받은 데이터를 큐에 추가
m_EventResponsePacket.Enqueue(Response_Parsing(m_ListReceiveData.ToArray(),false));
// 사용자 정의 코드 실행
OnReceiveHandler_User(m_ListReceiveData.ToArray());
}
else
{
// Request 요청에 의한 Repsonse 응답 수신
// Request 플래그 초기화
m_bSendData = false;
// Response 응답을 받아 플래그 설정
m_bAckCompletion = true;
}
}

#endregion

#region ********************************* [ 외부 인터페이스 ] *************************************

// 연결 재시도 횟수를 설정
public int ConnectMaxRetryCount
{
set { m_iConnect_MaxRetryCount = value; }
get { return m_iConnect_MaxRetryCount; }
}
// 연결 재시도 간격을 설정
public int ConnectRetryInterval
{
set { m_iConnect_RetryInterval = value; }
get { return m_iConnect_RetryInterval; }
}
// 서버 연결 모드를 설정(동기, 비동기)
public bool Synchronous
{
set { m_bSynchronous = value; }
get { return m_bSynchronous; }
}
// 공유기(허브) IP를 설정
public string NetworkDeviceIP
{
set { m_strNetworkDeviceIPAddress = value; }
get { return m_strNetworkDeviceIPAddress; }
}
// 공유기(허브)의 연결상태를 체크
public bool IsNetworkAvailable
{
get { return IPAddressAvailableCheck(); }
}
// 서버 IP를 설정
public string ServerAddress
{
set { m_strServerIPAddress = value; }
get { return m_strServerIPAddress; }
}
// 서버와 연결 상태를 확인
public ConnectionStatus IsConnected
{
get
{
if (m_bConnected == true)
{
return ConnectionStatus.Connected;
}
else if (m_bConnecting == true)
{
return ConnectionStatus.Connecting;
}
else
{
return ConnectionStatus.DisConnected;
}
}
}

// 서버와 연결 시도
public void Connect(int iPort, int iTimeoutInterval)
{
// 현재 연결중이 아닐 경우 진행
if (m_bConnecting == false)
{
m_bConnecting = true;
// IP주소 및 Port 설정
m_pSmartTCPClient.ServerIPAddress = m_strServerIPAddress;
m_pSmartTCPClient.Port = iPort;
// 동기 방식일 경우 최대 연결 대기시간을 설정
m_iConnectTimeoutInterval = iTimeoutInterval;
// 처음 Connect할 경우 빨리 Connect 시도하도록 설정
m_bConnectFirst = true;
m_iConnectRetryCount = 0;

// 동기, 비동기 방식설정
if (m_bSynchronous == true)
{
m_pSmartTCPClient.SetBlocking(true);
}
else
{
m_pSmartTCPClient.SetBlocking(false);

// 비동기 방식일 경우 연결상태를 체크하기 위한 이벤트를 추가
m_pSmartTCPClient.OnConnected -= smartTCPClient_OnConnected;
m_pSmartTCPClient.OnConnected += new SmartTCPClient.ConnectHandler (smartTCPClient_OnConnected);
}

// 연결 재시도시 사용할 Timer 생성
m_TimerConnectRetry = new Timer();
m_TimerConnectRetry.Interval = 10;
m_TimerConnectRetry.Enabled = false;
m_TimerConnectRetry.Tick += new EventHandler(ConnectRetryTimer_Tick);
m_TimerConnectRetry.Enabled = true;

// 데이터 수신 이벤트 추가
m_pSmartTCPClient.OnReceiveHandler -= SmartTCPClient_OnReceiveHandler;
m_pSmartTCPClient.OnReceiveHandler += new SmartTCPClient.ReceiveHandler(SmartTCPClient_OnReceiveHandler);
}
}

// 서버와 연결 해제
public void Disconnect()
{
// m_TimerConnectRetry가 생성되었을 때만 실행
if (m_TimerConnectRetry != null)
{
m_TimerConnectRetry.Enabled = false;
}
// 서버와 연결된 경우에만 실행
if (m_bConnected == true)
{
m_pSmartTCPClient.Close();

m_bConnected = false;
}
}

// 데이터 전송 메서드
public SendStatus SendData(byte[] sendData)
{
bool bRet; // 데이터 송신 결과를 저장할 플래그

// Request 후 Response 체크를 위한 플래그 초기화
m_bAckCompletion = false;

// 서버와 연결되어있지 않다면 ConnectionFailed을 리턴
if (m_bConnected == false)
{
return SendStatus.ConnectionFailed;
}

// 데이터 전송 후 결과를 저장
bRet = SmartTCPClient_SendData(sendData);

// 데이터 전송에 실패했다면 SendFailed를 리턴
if (bRet == false)
{
return SendStatus.SendFailed;
}

// Response 대기시간으로 설정한 시간동안 Response를 대기
for (int i = 0; i < ACKTIMEOUT; i++)
{
// Response 수신시 처리
if (m_bAckCompletion == true)
{
// 플래그 초기화
m_bAckCompletion = false;

// Response 데이터를 처리하는 사용자 함수
ACK_OnReceiveHandler_User(m_ListReceiveData.ToArray());

// Request후 Response 성공시 Success를 리턴
return SendStatus.Success;
}
System.Threading. Thread.Sleep(1);
Application.DoEvents();
}

// Response 수신 실패를 리턴
return SendStatus.AckFailed;
}

#endregion

#region ********************************* [ 사용자 정의 영역 ] *********************************

private const byte m_bSTX = 0x40; // STX : @
private const byte m_bETX = 0x3B; // ETX : ;

private Data_Packet m_NowRequestPacket; // Request한 데이터를 저장할 구조체 변수
private Queue<Data_Packet> m_EventResponsePacket = new Queue<Data_Packet>(); // 서버에서 임의로 송신한 데이터를 저장할 Queue

// Connect 실패 시 사용자가 처리할 함수
private void ConnectRetryFail_User(NetworkConnectStatus eNetworkStatus)
{
SmartX. SmartMessageBox.Size(500, 200);
// 사용자에게 알림
DialogResult ret = SmartX. SmartMessageBox.Show("네트워크 환경을 점검하시기 바랍니다.!!! \n네트워크 점검을 하시려면 예(Yes), \n연결시도를 중지하시려면 아니오(No)를 선택하시기 바립니다.",
"네트워크 점검", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

// 버튼 선택에 따른 처리
if (ret == DialogResult.Yes)
{
// 예 선택시 네트워크 상태에 따른 처리
switch (eNetworkStatus)
{
case NetworkConnectStatus.Available:
ConnectReTry();
break;
case NetworkConnectStatus.NetworkDeviceProblems:
SmartX.SmartMessageBox.Show("내부네트워크 문제 발생 - 공유기확인, 단선확인");
m_bConnecting = false;
break;
case NetworkConnectStatus.ServerProblems:
SmartX.SmartMessageBox.Show("서버연결 문제 발생 - 서버확인, 서버Ping차단확인, 단선확인");
m_bConnecting = false;
break;
case NetworkConnectStatus.ServerProcessProblems:
SmartX.SmartMessageBox.Show("서버프로그램 상태문제 발생 - 서버프로그램확인, 서버 운영체제및 프로그램 확인");
m_bConnecting = false;
break;
}
}
else
{
// 아니오 선택 시 Connect 중단
m_bConnecting = false;
}
}

// < Request and Response Type >
private void ACK_OnReceiveHandler_User(byte[] receiveData)
{
// Request에 따른 Response의 사용자 처리
}

// < Server to Client Event Type >
private void OnReceiveHandler_User(byte[] receiveData)
{
// 서버에서 일방적으로 송신한 데이터의 처리
}

// 전송받은 데이터를 검증 후 파싱하는 메서드. 이벤트에서 태움. bAckRecv 인자로 Ack수신인지 확인
privateData_Packet Response_Parsing(byte[] chData, bool bAckRecv)
{
// 수신 리스트를 클리어
m_ListReceiveData.Clear();

Data_Packet response = new Data_Packet(); // 수신 데이터를 저장할 구조체

// STX, ETX 체크
if ((chData[0] != m_bSTX) || (chData[chData.Length - 1] != m_bETX))
{
// 비정상적인 데이터
response.chCommandStatus = CommandStatus.DataInvalid;
return response;
}

// Request에 의한 Response인 경우
if (bAckRecv == true)
{
// Request한 Command와 Response 한 Command를 비교
if (Encoding.ASCII.GetString(m_NowRequestPacket.chCommand, 0, m_NowRequestPacket.chCommand.Length) != Encoding.ASCII.GetString(chData, 1, 3))
{
// 비정상적인 Command
response.chCommandStatus = CommandStatus.CommandInvalid;
return response;
}

// Channel 값이 전송한 데이터와 같지 않다면
if (m_NowRequestPacket.chChannel != chData[4])
{
// 잘못된 Channel 수신
response.chCommandStatus = CommandStatus.DataInvalid;
return response;
}

// Request 여부에 따른 체크
if (m_NowRequestPacket.chData != null)
{
// Request한 데이터가 있다면. (SetFrame 이라면)
for (int i = 0; i < m_NowRequestPacket.chData.Length; i++)
{
if (m_NowRequestPacket.chData[i] != chData[5 + i])
{
// 잘못된 데이터 수신
response.chCommandStatus = CommandStatus.DataInvalid;
return response;
}
}
}
else
{
// Request한 데이터가 없다면. (GetFrame 이라면)
if (chData.Length - 3 - m_NowRequestPacket.chCommand.Length == 0)
{
// 수신한 데이터가 없는 경우 잘못된 데이터 수신
response.chCommandStatus = CommandStatus.DataInvalid;
return response;
}
}
}
// 정상적인 값이라면 데이터 패킷에 값을 저장
response.chCommand = new byte[3];
System. Buffer.BlockCopy(chData, 1, response.chCommand, 0, response.chCommand.Length);

// 수신받은 Ch를 저장
response.chChannel = new byte();
response.chChannel = chData[1 + response.chCommand.Length];

// 데이터가 정상적으로 수신되어 수신 데이터를 구조체에 저장
response.chData = new byte[chData.Length - response.chCommand.Length - 3];
System.Buffer.BlockCopy(chData, 2 + response.chCommand.Length, response.chData, 0, response.chData.Length);

// 데이터 수신 정상
response.chCommandStatus = CommandStatus.Success;

// 수신 데이터가 저장된 구조체를 리턴
return response;
}

// 서버로 Request 데이터를 전송하는 메서드
privateSendStatus Request_Command(string strCommand, int iCh, byte[] chData)
{
// 전송 패킷 생성
m_NowRequestPacket = new Data_Packet();

// Command 저장
m_NowRequestPacket.chCommand = new byte[strCommand.Length];
m_NowRequestPacket.chCommand = Encoding.ASCII.GetBytes(strCommand);

// Channel 저장
m_NowRequestPacket.chChannel = new byte();
m_NowRequestPacket.chChannel = (byte)Convert.ToChar(iCh.ToString());

// Data 저장
if (chData != null)
{
// Set Frame인 경우 데이터를 패킷에 저장
m_NowRequestPacket.chData = new byte[chData.Length];
}
// Get Frame인 경우 Null 값을 패킷에 저장
m_NowRequestPacket.chData = chData;

// 전송할 데이터를 저장할 List
List<byte> lstSendData = new List<byte>();

// STX 추가
lstSendData.Add(m_bSTX);
// Command 추가
lstSendData.AddRange(m_NowRequestPacket.chCommand);
// Ch 추가
lstSendData.Add(m_NowRequestPacket.chChannel);

// Set Data 추가 : Request 프레임이 Get 일 경우 데이터가 없음(null)
if (m_NowRequestPacket.chData != null)
{
// Set Frame일 경우 프레임에 데이터를 추가
lstSendData.AddRange(m_NowRequestPacket.chData);
}

// ETX 추가
lstSendData.Add(m_bETX);

// 데이터를 전송후 전송 상태를 리턴
return SendData(lstSendData.ToArray());
}

#endregion

#region ********************************* [ 사용자 정의 외부 인터페이스 영역 ] *********************************
// [ Protocol Structure definition ]
//
// < Request and Response Type >
// * Read, Write and Return always set.
// Type - Read : Request Send Command - Client to Server Communication : Get Server Data
// STX[1Byte] + CMD[3Byte] + Channel[1Byte] + ETX[1Byte]
//
// Type - Write : Request Send Command - Client to Server Communication : Set Server Data
// STX[1Byte] + CMD[3Byte] + Channel[1Byte] + DATA[4Byte] + ETX[1Byte]
//
// Type - Return : Response Acknowledge Response - Server to Client Communication
// STX[1Byte] + CMD[3Byte] + Channel[1Byte] + RETURN_DATA[4Byte] + ETX[1Byte]
//
// < Server to Client Event Type >
// Type - Event : Event Response Command - Server to Client Communication
// STX[1Byte] + CMD[3Byte] + Channel[1Byte] + DATA[4Byte] + ETX[1Byte]
//
// STX : 0x40
// ETX : 0x3B
//
// < Command Code Define : ASCII Code >
// TMR : Read Temperature Data
// 0x54, 0x4D, 0x52
// TMW : Write Temperature Data
// 0x54, 0x4D, 0x57
// HMR : Read Humidity Data
// 0x48, 0x4D, 0x52
// HMW : Write Humidity Data
// 0x48, 0x4D, 0x57
// WTR : Read Water Level Data
// 0x57, 0x54, 0x52
// WTW : Write Water Level Data
// 0x57, 0x54, 0x57
// DTR : Read Distance Data
// 0x44, 0x54, 0x52
// DTW : Write Distance Data
// 0x44, 0x54, 0x57
//
// < Channel Code Define : ASCII Code >
// Channel 0 : 0x30
// Channel 1 : 0x31
// Channel 2 : 0x32
// Channel 3 : 0x33
//
// < Data Field Define : Binary Code >
// Float Data



// Queue에 저장된 패킷의 수를 읽는다.
public int GetServerEventReceiveQueueCount
{
get { return m_EventResponsePacket.Count; }
}

// Queue에 저장된 패킷을 가져온다.
public Data_Packet GetServerEventReceiveQueue()
{
if (m_EventResponsePacket.Count == 0)
{
Data_Packet retNull = new Data_Packet();
return retNull;
}
return m_EventResponsePacket.Dequeue();
}

// Request-Response 구조일 때 외부에서 이용하는 메서드 -> 동기 방식이므로 이 메서드 내부에서 리턴까지 처리함
public Data_Packet Command_RequestResponse(string strCommand, int iCh, byte[] chData)
{
// 데이터 전송 후 전송 상태를 받아옴
SendStatus eSendStatus = Request_Command(strCommand, iCh, chData);

// Response 받은 데이터를 저장할 구조체
Data_Packet response = new Data_Packet();
// 전송 상태에 따른 수신 상태 처리
switch (eSendStatus)
{
case SendStatus.ConnectionFailed:
// 서버와 연결이 안된경우
response.chCommandStatus = CommandStatus.ConnectionFailed;
break;
case SendStatus.SendFailed:
// 데이터 전송에 실패한 경우(메서드가 False 리턴)
response.chCommandStatus = CommandStatus.SendFailed;
break;
case SendStatus.AckFailed:
// 서버에서 응답하지 않은 경우
response.chCommandStatus = CommandStatus.AckFailed;
break;
case SendStatus.Success:
// Request 이후 올바르게 Response 된 경우 수신받은 데이터를 변환하여 저장
response = Response_Parsing(m_ListReceiveData.ToArray(),true);
break;
}
return response;
}

#endregion
}

맨 위로
팝업닫기

(주)에이치앤에스('http://hnsts.co.kr/'이하 '(주)에이치앤에스 웹사이트')는 개인정보보호법에 따라 이용자의 개인정보 보호 및 권익을 보호하고 개인정보와 관련한 이용자의 고충을 원활하게 처리할 수 있도록 다음과 같은 처리방침을 두고 있습니다.

(주)에이치앤에스 웹사이트는 개인정보처리방침을 개정하는 경우 웹사이트 공지사항(또는 개별공지)을 통하여 공지할 것입니다.

○ 본 방침은 2011년 4월 1일부터 시행됩니다.

1. 개인정보의 처리 목적 (주)에이치앤에스 웹사이트는 개인정보를 다음의 목적을 위해 처리합니다. 처리한 개인정보는 다음의 목적 이외의 용도로는
사용되지 않으며 이용 목적이 변경될 시에는 사전동의를 구할 예정 입니다.
가. 민원사무 처리
민원인의 신원 확인, 민원사항 확인, 사실조사를 위한 연락 · 통지, 처리결과 통보 등을 목적으로 개인정보를 처리합니다.
2. 개인정보 파일 현황
1. 개인정보 파일명 : 고객의 소리
  • - 개인정보 항목 : 이메일, 휴대전화번호, 자택전화번호, 이름, 서비스 이용 기록, 접속 로그, 쿠키, 접속 IP 정보
  • - 수집방법 : 웹사이트
  • - 보유근거 : 이용자 동의
  • - 보유기간 : 3년
3. 개인정보의 제3자 제공에 관한 사항
① (주)에이치앤에스 웹사이트는 원칙적으로 이용자의 개인정보를 제1조에서 명시한 목적 범위 내에서 처리하며, 본래의 범위를 초과하여 처리하거나 제3자에게 제공하지 않습니다.
다만, 다음의 경우에는 개인정보를 제3자에게 제공할 수 있습니다.
  • – 이용자가 사전에 제3자 제공 및 공개에 동의한 경우
  • – 법령 등에 의해 제공이 요구되는 경우
  • – 서비스의 제공에 관한 계약의 이행을 위하여 필요한 개인정보로서 경제적/기술적인 사유로 통상의 동의를 받는 것이 현저히 곤란한 경우
  • – 개인을 식별하기에 특정할 수 없는 상태로 가공하여 이용하는 경우
4. 정보주체의 권리,의무 및 그 행사방법 이용자는 개인정보주체로서 다음과 같은 권리를 행사할 수 있습니다.
① 정보주체는 (주)에이치앤에스 웹사이트에 대해 언제든지 다음 각 호의 개인정보 보호 관련 권리를 행사할 수 있습니다.
  • 1. 개인정보 열람요구
  • 2. 오류 등이 있을 경우 정정 요구
  • 3. 삭제요구
  • 4. 처리정지 요구
② 제1항에 따른 권리 행사는 (주)에이치앤에스 웹사이트에 대해 개인정보 보호법 시행규칙 별지 제8호 서식에 따라 서면, 전자우편, 모사전송(FAX) 등을 통하여 하실 수 있으며 (주)에이치앤에스 웹사이트는
이에 대해 지체 없이 조치하겠습니다.
③ 정보주체가 개인정보의 오류 등에 대한 정정 또는 삭제를 요구한 경우에는 (주)에이치앤에스 웹사이트는 정정 또는 삭제를 완료할 때까지 당해 개인정보를 이용하거나 제공하지 않습니다.
④ 제1항에 따른 권리 행사는 정보주체의 법정대리인이나 위임을 받은 자 등 대리인을 통하여 하실 수 있습니다. 이 경우 개인정보 보호법 시행규칙 별지 제11호 서식에 따른 위임장을
제출하셔야 합니다.
5. 제3자에게의 개인정보 제공
① (주)에이치앤에스 웹사이트는 다음의 개인정보 항목을 처리하고 있습니다.
<민원사무 처리>
– 필수항목 : 이름, 휴대전화번호, 자택전화번호, 이메일, 서비스 이용 기록, 접속로그, 쿠키, 접속IP 정보
6. 개인정보의 파기
(주)에이치앤에스 웹사이트는 원칙적으로 개인정보 처리목적이 달성된 경우에는 지체없이 해당 개인정보를 파기합니다. 파기의 절차, 기한 및 방법은 다음과 같습니다.
  • –파기절차 이용자가 입력한 정보는 목적 달성 후 별도의 DB에 옮겨져(종이의 경우 별도의 서류) 내부 방침 및 기타 관련 법령에 따라 일정기간 저장된 후 혹은 즉시 파기됩니다. 이 때, DB로 옮겨진 개인정보는 법률에 의한 경우가 아니고서는 다른 목적으로 이용되지 않습니다.-파기기한이용자의 개인정보는 개인정보의 보유기간이 경과된 경우에는 보유기간의 종료일로부터 5일 이내에, 개인정보의 처리 목적 달성, 해당 서비스의 폐지, 사업의 종료 등 그 개인정보가 불필요하게 되었을 때에는 개인정보의 처리가 불필요한 것으로 인정되는 날로부터 5일 이내에 그 개인정보를 파기합니다.
  • –파기방법 전자적 파일 형태의 정보는 기록을 재생할 수 없는 기술적 방법을 사용합니다. 종이에 출력된 개인정보는 분쇄기로 분쇄하거나 소각을 통하여 파기합니다.
7. 개인정보의 안전성 확보 조치
(주)에이치앤에스 웹사이트는 개인정보보호법 제29조에 따라 다음과 같이 안전성 확보에 필요한 기술적/관리적 및 물리적 조치를 하고 있습니다.
1. 정기적인 자체 감사 실시
개인정보 취급 관련 안정성 확보를 위해 정기적(분기 1회)으로 자체 감사를 실시하고 있습니다.
2. 개인정보 취급 직원의 최소화 및 교육
개인정보를 취급하는 직원을 지정하고 담당자에 한정시켜 최소화 하여 개인정보를 관리하는 대책을 시행하고 있습니다.
3. 내부관리계획의 수립 및 시행
개인정보의 안전한 처리를 위하여 내부관리계획을 수립하고 시행하고 있습니다.
4. 해킹 등에 대비한 기술적 대책
(주)에이치앤에스 웹사이트는 해킹이나 컴퓨터 바이러스 등에 의한 개인정보 유출 및 훼손을 막기 위하여 보안프로그램을 설치하고 주기적인 갱신·점검을 하며 외부로부터 접근이 통제된 구역에
시스템을 설치하고 기술적/물리적으로 감시 및 차단하고 있습니다.
5. 개인정보의 암호화
이용자의 개인정보는 비밀번호는 암호화 되어 저장 및 관리되고 있어, 본인만이 알 수 있으며 중요한 데이터는 파일 및 전송 데이터를 암호화 하거나 파일 잠금 기능을 사용하는 등의
별도 보안기능을 사용하고 있습니다.
6. 접속기록의 보관 및 위변조 방지
개인정보처리시스템에 접속한 기록을 최소 6개월 이상 보관, 관리하고 있으며, 접속 기록이 위변조 및 도난, 분실되지 않도록 보안기능 사용하고 있습니다.
7. 개인정보에 대한 접근 제한
개인정보를 처리하는 데이터베이스시스템에 대한 접근권한의 부여,변경,말소를 통하여 개인정보에 대한 접근통제를 위하여 필요한 조치를 하고 있으며 침입차단시스템을 이용하여
외부로부터의 무단 접근을 통제하고 있습니다.
8. 문서보안을 위한 잠금장치 사용
개인정보가 포함된 서류, 보조저장매체 등을 잠금장치가 있는 안전한 장소에 보관하고 있습니다.
9. 비인가자에 대한 출입 통제
개인정보를 보관하고 있는 물리적 보관 장소를 별도로 두고 이에 대해 출입통제 절차를 수립, 운영하고 있습니다.
8. 개인정보 보호책임자 작성
① (주)에이치앤에스 웹사이트는 개인정보 처리에 관한 업무를 총괄해서 책임지고, 개인정보 처리와 관련한 정보주체의 불만처리 및 피해구제 등을 위하여 아래와 같이 개인정보 보호책임자를
지정하고 있습니다.
▶ 개인정보 보호책임자
성명 : 김진효
소속 : (주)에이치앤에스
전화번호 : 02-6402-8001
이메일 : hns@hnsts.co.kr
② 정보주체께서는 (주)에이치앤에스 웹사이트의 서비스(또는 사업)을 이용하시면서 발생한 모든 개인정보 보호 관련 문의, 불만처리, 피해구제 등에 관한 사항을 개인정보 보호책임자 및
담당부서로 문의하실 수 있습니다. (주)에이치앤에스 웹사이트는 정보주체의 문의에 대해 지체 없이 답변 및 처리해드릴 것입니다.
9. 개인정보침해 구제방법
정보주체는 개인정보침해로부터 구제받고자 하는 경우 다음과 같은 기관에 도움을 요청할 수 있습니다.
▶ 개인정보 침해신고센터 (한국인터넷진흥원 운영)
– 소관업무 : 개인정보 침해사실 신고, 상담 신청
– 홈페이지 : privacy.kisa.or.kr
– 전화 : (국번없이) 118
– 주소 : (138-950) 서울시 송파구 중대로 135 한국인터넷진흥원 개인정보침해신고센터
▶ 개인정보 분쟁조정위원회 (한국인터넷진흥원 운영)
– 홈페이지 : privacy.kisa.or.kr
– 전화 : (국번없이) 118
– 주소 : (138-950) 서울시 송파구 중대로 135 한국인터넷진흥원 개인정보침해신고센터
10. 개인정보 처리방침 변경
① 이 개인정보처리방침은 시행일로부터 적용되며, 법령 및 방침에 따른 변경내용의 추가, 삭제 및 정정이 있는 경우에는 변경사항의 시행 7일 전부터 공지사항을 통하여 고지할
것입니다.
팝업닫기

본 웹사이트에 게시된 이메일 주소가 전자우편 수집 프로그램이나 그 밖의 기술적 장치를 이용하여 무단으로 수집되는 것을 거부하며, 이를 위반시 정보통신망법에 의해 형사처벌됨을 유념하시기 바랍니다.

게시일 : 2011.4.1