콘텐츠로 이동
무료 평가 시작

서비스 오류와 시간 초과

서비스 오류는 명령 자체가 실패한 경우입니다. Modbus 예외 응답과 다르며, 결과가 없습니다. 같은 오류가 실행 환경마다 다음처럼 보입니다.

환경 모습
C PDCOMM_MODBUS_SERVICE_ERROR(5)와 오류 버퍼 {"error":"<메시지>","ok":false}
C++, Qt, MFC std::runtime_error. what()은 오류 JSON 전체
.NET ModbusCommandException(InvalidOperationException 파생). Message는 메시지만, Code는 라이선스 오류의 code
헤드리스 {"error":"<메시지>","ok":false} 줄, 종료 코드 1
MCP isError가 true, content[0].text가 메시지
GUI 상태 줄의 <명령> failed: <메시지>

아래 표의 메시지는 실제 출력 그대로입니다. Io(...)의 괄호 안 OS 오류 문구는 운영체제마다 다릅니다.

메시지 원인과 해결
Action is required action 필드가 없습니다.
Unknown service action action 이름이 틀렸습니다. JSON 명령 레퍼런스를 확인합니다.
key must be a string at line 1 column 2, EOF while parsing an object at line 2 column 0 등 JSON 문법 오류입니다. 헤드리스와 MCP는 한 줄에 객체 하나를 씁니다.
Input exceeds one MiB 헤드리스·MCP의 한 줄이 1MiB를 넘었습니다.
missing field `port` , unknown field `extra`, expected one of ... 구성이나 모델에 필드가 빠졌거나 모르는 필드가 있습니다.
PDU is required request, execute에 pdu가 없습니다.
Invalid hex length, Invalid hex 16진수 문자열의 글자 수가 홀수이거나 16진수가 아닌 글자가 있습니다.
Expected a byte array or hex string pdu나 bytes가 문자열도 0~255 배열도 아닙니다.
Invalid unit unit이 0~255 밖입니다.
메시지 원인과 해결
Invalid endpoint configuration 다음 중 하나입니다. transport·role·parity 값이 틀림, unit이 1~247 밖, timeout_ms·ascii_timeout_ms가 0이거나 60000 초과, turnaround_ms가 60000 초과, baud가 0, stop_bits가 1·2가 아님, parity가 none인데 stop_bits가 1
Gateway requires a serial bus transport 게이트웨이의 transport를 rtu나 ascii로 합니다.
Invalid gateway route routes의 키가 0이거나, 값이 0이거나 247을 넘습니다.
Invalid Security configuration security를 직렬 구성에 썼거나, mode가 틀렸거나, chain·private_key·trust 중 빈 값이 있습니다.
invalid type: string "Invalid JSON", expected struct Security GUI Security 탭의 JSON 문법이 틀렸습니다.
Protocol is excluded from this build SDK에 없는 전송이나 Security를 구성했습니다. capabilities로 확인합니다.
Disconnect before changing configuration 연결 중에는 구성을 바꿀 수 없습니다. disconnect 뒤 다시 합니다.
Endpoint is already connected 이미 연결했습니다. 다시 열려면 disconnect부터 합니다.
메시지 원인과 해결
Invalid TCP address address가 IP:포트 형식이 아닙니다. localhost:1502 같은 호스트 이름은 받지 않습니다. 127.0.0.1:1502처럼 씁니다.
Io(ConnectionRefused, "Connection refused (os error 61)") 그 주소에서 기다리는 서버가 없습니다. 서버가 먼저 connect했는지, 포트가 같은지 봅니다.
Io(TimedOut, "connection timed out") timeout_ms 안에 TCP 연결이 되지 않았습니다. 경로, 방화벽, 장비 전원을 확인합니다.
Io(AddrInUse, "Address already in use (os error 48)") 서버 포트를 다른 프로그램이 씁니다. 다른 포트를 쓰거나 그 프로그램을 끝냅니다.
Io(AddrNotAvailable, "Can't assign requested address (os error 49)") 서버 address의 IP가 이 PC의 주소가 아닙니다. 0.0.0.0이나 PC의 실제 주소를 씁니다.
InvalidConfig 직렬 구성의 port가 비어 있습니다.
Io(Other, "No such file or directory") 직렬 port 경로가 없습니다.
Io(Other, "Unable to acquire exclusive lock on serial port") 다른 프로그램이 직렬 포트를 열고 있습니다.
Security(...), Config(...), Crypto(...) Modbus/TCP Security 오류입니다. 보안 연결 문제를 봅니다.

SDK 라이브러리(C, C++, .NET, Qt, MFC)는 connect할 때 라이선스를 확인합니다. 헤드리스·MCP 시뮬레이터는 확인하지 않고, 시뮬레이터 GUI는 내장된 도구용 라이선스를 씁니다. 라이선스 오류 응답에는 error 외에 code가 있어 프로그램에서 구분할 수 있습니다.

code 메시지 원인과 해결
license_required PDComm license required for module 'modbus' (<상태>): … connect에 필요한 라이선스가 없습니다. modbus 모듈이 필요하고, 구성에 security가 있으면 modbus-security도 필요합니다. 아무것도 열지 않았습니다. 응답의 license에 module, state, license_id가 있습니다. state를 라이선스 문제 해결에서 찾습니다. 이미 연결된 끝점은 계속 동작합니다.
license_invalid License text is required, license text contains no PDCOMM LICENSE block, license text contains no valid license (<이유>), license text is larger than 1048576 bytes license_install의 text가 없거나, 서명이 맞는 라이선스 블록이 없거나, 1MiB를 넘습니다. 이전에 설치한 라이선스는 그대로입니다. 받은 파일 전체를 그대로 넘깁니다.
host_id_unavailable Host id unavailable: <이유> host_id가 컴퓨터 고유 ID를 읽지 못했습니다. 컨테이너라면 /etc/machine-id를 만듭니다. 호스트 ID를 봅니다.

거부된 connect의 응답은 다음과 같습니다.

{"code":"license_required","error":"PDComm license required for module 'modbus' (missing): no valid license for this module was found. Existing connections keep running. Install a license with the license API, PDCOMM_LICENSE_FILE or a pdcomm.license file.","license":{"license_id":null,"module":"modbus","state":"missing"},"ok":false}
메시지 원인과 해결
Connect a client before sending a request 클라이언트로 연결하지 않았습니다. 서버 역할에서 request를 보내도 이 오류입니다.
Timeout timeout_ms 안에 응답이 오지 않았습니다. 아래 시간 초과를 봅니다.
Closed TCP 연결이 이미 닫혔습니다. 시간 초과 뒤, 상대가 연결을 끊은 뒤, 입출력 오류 뒤에 나옵니다. state의 connected는 false입니다. 다시 connect합니다.
Io(ConnectionReset, "Connection reset by peer (os error 54)") 상대가 연결을 강제로 끊었습니다. 평문 클라이언트가 Security 서버에 붙은 경우에도 나옵니다.
Unsupported TCP 클라이언트로 직렬 전용 기능(07, 08, 11, 12, 17)을 보내려 했습니다.
InvalidConfig 직렬 클라이언트로 유닛 0에 쓰기가 아닌 요청을 보냈거나, 유닛이 247을 넘습니다.
Protocol(Correlation) 응답이 요청과 맞지 않습니다(다른 유닛, 다른 기능 코드, 다른 트랜잭션 식별자). 같은 주소에 여러 장비가 응답하는지, 게이트웨이 설정을 확인합니다.
Protocol(Length), Protocol(Value) 응답의 길이나 값이 기능 정의와 맞지 않습니다. 예외 응답은 코드가 명세에 없어도(예: 07) 오류가 아니라 "status":"exception" 결과입니다.
Protocol(Checksum), Protocol(Encoding), Protocol(Address) 직렬 응답의 CRC·LRC, ASCII 문자, 주소가 틀렸습니다. 직렬 통신 문제를 봅니다.

PDComm 클라이언트는 요청 PDU를 보내기 전에 검사하고, 틀리면 보내지 않습니다. 이때 메시지는 한 단어입니다.

메시지 예
Length 길이가 기능에 맞지 않음. 0700, 빈 PDU
Value 수량이 0이거나 최대 수량을 넘음, 기능 05의 값이 틀림. 0300000000
Address 주소와 수량이 65536을 넘음, 파일 참조가 틀림
Function 지원하지 않는 기능이나 진단 하위 기능

같은 PDU를 execute로 실행하면 서버 쪽 동작인 예외 응답(01, 02, 03)이 나옵니다.

Timeout은 요청은 보냈지만 timeout_ms 안에 응답을 받지 못했다는 뜻입니다. 쓰기 요청이라면 장비가 이미 처리했을 수 있으므로, 다시 쓰기 전에 값을 읽습니다.

TCP에서 확인할 것

  1. 상대가 응답하는 Modbus 서버인지 봅니다. 포트는 열려 있지만 다른 프로토콜의 서비스일 수 있습니다.
  2. 유닛 식별자가 맞는지 봅니다. 일부 장비와 게이트웨이는 모르는 유닛에 응답하지 않습니다.
  3. 상대가 게이트웨이라면 게이트웨이의 직렬 대기 시간보다 timeout_ms를 길게 합니다.
  4. 상대가 SDK로 만든 서버라면 그 애플리케이션이 poll을 계속 호출하는지 봅니다. poll이 멈추면 연결은 받지만 응답하지 않습니다.
  5. 진단 로그의 failed 기록에서 tx_bytes(보낸 바이트), rx_partial_bytes(받다 만 바이트), max_poll_gap_us(SDK 처리 지연)를 봅니다.

시간 초과가 나면 TCP 클라이언트는 연결을 닫습니다. 늦게 온 응답이 다음 요청의 응답으로 잘못 짝지어지지 않게 하기 위해서입니다. 이후 요청은 Closed이므로 connect를 다시 합니다.

직렬 회선의 시간 초과는 직렬 통신 문제를 봅니다.

주소를 잘못 잡으면 오류 없이 다른 레지스터의 값이 돌아오거나, 예외 02가 납니다.

증상 흔한 원인
값이 기대한 것의 옆 레지스터 값 매뉴얼의 1 기반 번호(40001)에서 1을 빼지 않았거나, 이미 0 기반인 주소에서 1을 또 뺐습니다.
예외 02 테이블 접두 숫자를 주소에 넣었습니다. 40001은 주소 40000이 아니라 0입니다.
값이 늘 0이거나 엉뚱함 테이블을 잘못 골랐습니다. 측정값은 입력 레지스터(04)에, 설정값은 보유 레지스터(03)에 있는 경우가 많습니다.
32비트 값이 크게 틀림 두 레지스터의 순서가 장비와 반대입니다(ABCD, CDAB).
음수가 65000대로 보임 부호 있는 16비트 값을 부호 없이 읽었습니다.

확인 방법:

  • 매뉴얼에서 값이 고정된 레지스터(장비 ID, 펌웨어 버전 등)를 찾아 먼저 읽습니다. 기대한 값이 나오면 주소 기준이 맞습니다.
  • 한 칸씩 앞뒤 주소를 읽어 기대한 값의 위치를 찾습니다.
  • 변환 규칙은 데이터 모델과 주소에 있습니다.
메시지 원인과 해결
Table is required, Address is required, Values are required data_set의 필드가 빠졌습니다.
Unknown data table table은 coils, discrete_inputs, holding_registers, input_registers 중 하나입니다.
Invalid data values values가 비었거나, 비트 테이블에 0·1이 아닌 값이 있거나, 주소가 65535를 넘습니다.
Address outside configured table 주소가 모델의 테이블 범위 밖입니다. data_get으로 start와 크기를 확인합니다.
Model is required model_set에 model이 없습니다.
Bit table values must be zero or one 코일이나 이산 입력에 0·1이 아닌 값이 있습니다.
Invalid table range 테이블의 시작 주소와 개수가 16비트 주소 범위를 넘습니다.
Invalid file, FIFO or device identification model 파일 번호 0이나 레코드 10000개 초과, FIFO 값 31개 초과, 객체 0·1·2 누락, 예약 객체 7127, 객체 244바이트 초과, server_id 길이(2251) 위반 중 하나입니다.
Invalid diagnostic register diagnostics_set의 register가 65535를 넘습니다.
Project is required project_import에 project가 없습니다.
Disconnect before loading a project 연결을 끊은 뒤 불러옵니다.
Unsupported Modbus project kind or version kind가 pdcomm.modbus.project, version이 1이어야 합니다. {"ok":true,...} 전체를 저장했다면 result만 저장합니다.
Fault bytes are required, Fault input exceeds limit fault에 bytes가 없거나 4096바이트를 넘었습니다.
Transport is excluded fault의 transport가 빌드에 없습니다.
Serial transports are excluded 직렬 전송이 없는 빌드에서 serial_ports를 불렀습니다.
메시지 원인과 해결
Logging configuration is required logging_configure에 config가 없습니다.
Invalid logging level level은 error, warn, info, debug, trace 중 하나입니다.
Unknown logging option 모르는 설정 필드가 있습니다.
Logging limits are out of range max_bytes(81921GiB)나 files(116)가 범위 밖입니다.
Forensics requires debug or trace logging forensics는 debug, trace 수준에서만 켭니다.
Cannot open logging sink 로그 파일을 열 수 없습니다. 폴더가 있는지, 쓰기 권한이 있는지 봅니다.
Logging flush failed 2초 안에 기록을 마치지 못했거나 쓰기가 실패했습니다. logging_status의 write_errors를 봅니다.
메시지 원인과 해결
Usage: pdcomm-modbus-headless [--scenario path] 인수가 틀렸습니다(종료 코드 2).
Scenario step N field <필드> did not match 시나리오의 기대값과 결과가 다릅니다(종료 코드 1).
Expected fields must be an object expect가 객체가 아닙니다.
Scenario exceeds one MiB 시나리오 파일이 1MiB를 넘습니다.
Endpoint poll failed: <오류> 서버나 게이트웨이의 poll이 실패해 연결을 끊었습니다. 오류 내용을 보고 다시 connect합니다.