실습 목표#
- 연결이 끊기면 새 연결을 열고 라우팅을 다시 활성화해 이어 가게 만든다.
- 긴 작업 동안 세션이 만료되지 않도록 주기적으로 신호를 보낸다.
- 큰 데이터를 주고받아 보고 소켓 버퍼가 처리량에 미치는 영향을 확인한다.
실습 1. 연결 끊김 복구#
recv()가 0을 반환하면 연결이 종료된 것으로 판단하고, 새 연결을 열고 라우팅부터 다시 수행한다. 단, 이번 실습 서버는 반복적으로 연결을 끊는 동작을 수행하므로 재시도는 최대 3회로 제한한다.
make
./ecu_faulty drop
make
./tester_session reconnect
[attempt 1/3] connect + activate
-> connection dropped by ECU; reconnecting (+ re-activating routing)
[attempt 2/3] connect + activate
Wireshark 분석#

① 첫 번째 연결에서 TCP 연결과 Routing Activation을 완료한 뒤 VIN 읽기 요청을 전송한다. 그러나 ECU는 진단 응답을 보내지 않고 FIN, ACK로 연결을 종료한다.
② 테스터는 연결 종료를 감지하고 새로운 TCP 연결을 생성한다. 새로운 연결이므로 Routing Activation부터 다시 수행한 뒤 VIN 읽기를 재시도한다.
③ 두 번째 시도에서도 연결이 끊어지면 세 번째 TCP 연결을 열고 같은 과정을 반복한다. 테스터는 이와 같은 방식으로 최대 3회까지 진단 요청을 시도한다.
④ Routing Activation 응답의 결과 코드 0x10은 진단 통신 경로가 정상적으로 활성화되었다는 의미이다.
각 시도마다 새로운 TCP 연결을 열고 Routing Activation을 다시 수행한다. Wireshark 캡처에서 Routing activation request와 Routing activation response 두 줄이 매 시도마다 반복되는 것을 통해 재연결 여부를 확인할 수 있다.
따라서 Routing Activation은 정상적으로 완료되었지만, ECU가 VIN 응답을 보내기 전에 연결을 종료하고 있다. 테스터는 연결 끊김을 감지할 때마다 새로운 연결을 생성하고 진단 요청을 다시 전송한다.
분석 : 재연결 뒤의 재시도 주의#
재연결 후 라우팅을 재활성화하는 것은 표준에 부합하는 동작이다. 그러나, 전송한 요청을 무조건 다시 재전송하는 것은 별개의 문제이다. 실제로는 멱등성이 보장된 요청에 한해서만 재전송을 해야 한다.
| 구분 | 내용 | 실습에서 |
|---|---|---|
| 표준에 맞는 것 | 연결이 바뀌면 라우팅을 다시 활성화해야 함 | 그대로 구현함 |
| 단순화한 것 | 끊기면 무조건 같은 요청을 다시 보냄 | 읽기라서 안전했을 뿐 |
| 실무 원칙 | 재연결은 하되 비멱등 요청은 상태를 먼저 확인 | 쓰기나 리셋은 중복 위험 |
실습 2. 세션 유지#
확장 세션은 5초간 통신이 없으면 만료된다. 이를 방지하기 위해 해당 주기보다 짧은 주기로 신호를 전송하여 세션 타이머를 갱신한다. 소요 시간이 긴 작업(12초)에서도 세션이 유지되는지 확인한다.
./ecu_faulty normal
./tester_session keepalive
[enter extended session]
[ 3s] TesterPresent sent (session kept alive) ... 3초마다 네 번
[write after long job]
-> NRC=0x33 (0x7F=session lost / 0x33=VIN protected)
Wireshark 분석#

① 테스터가 서비스 0x10으로 확장 진단 세션 전환을 요청하고, ECU의 정상 응답을 통해 세션 전환이 완료된 것을 확인할 수 있다.
② 확장 세션이 만료되지 않도록 약 3초마다 Tester Present 요청과 응답이 반복된다. ECU가 Tester Present 요청을 수신할 때마다 S3 타이머가 초기화되므로 확장 세션이 계속 유지된다.
③ 약 12초 동안 세션을 유지한 뒤 테스터가 서비스 0x2E로 VIN 쓰기를 요청한다.
④ 마지막 응답으로 NRC 0x33 Security Access Denied가 반환된다. 이는 확장 세션은 유지됐지만 보안 인증을 통과하지 못했다는 의미이다. 세션이 만료됐다면 NRC 0x7F가 반환됐을 것이다.
따라서 Wireshark에서 주기적으로 반복되는 Tester Present 요청·응답과 마지막 NRC 0x33을 통해 S3 타이머가 계속 초기화되고 확장 세션이 정상적으로 유지됐음을 확인할 수 있다.
실습 3. 작은 데이터와 큰 데이터#
펌웨어 전송을 모사하기 위해 지정한 큰 크기의 데이터를 생성하여 전송한다. VIN은 24 bytes, 100 KB 펌웨어는 102,407 bytes의 한 메시지로 전송한다.
make
./ecu_bigdata 100
./tester_bigdata vin
./tester_bigdata fw
vin DoIP payload length = 24 bytes
fw DoIP payload length = 102407 bytes
-> ONE logical DoIP message, delivered as many chunks
Wireshark 분석#
1. VIN 소용량 데이터 전송 — 단일 TCP 세그먼트#

① TCP 연결이 수립된 후 Routing Activation 요청과 응답을 통해 DoIP 진단 통신 경로가 활성화된다.
② 테스터가 서비스 0x22와 DID 0xF190을 사용하여 VIN 읽기를 요청하고, ECU가 VIN 데이터를 정상적으로 응답한다.
③ UDS 상세 정보에서 응답 서비스, DID 0xF190, 그리고 VIN 값 TESTVIN0123456789를 확인할 수 있다.
④ 원시 데이터의 00 00 00 18은 DoIP Payload Length가 0x18, 즉 24바이트임을 나타낸다. 이어지는 62 F1 90은 VIN 읽기에 대한 정상 응답이며, 이후 바이트는 TESTVIN0123456789를 나타내는 ASCII 데이터이다.
④ 영역에 표시된 세 줄은 서로 다른 패킷이 아니라, 하나의 패킷에 포함된 데이터가 화면 너비에 따라 줄바꿈되어 표시된 것이다. TCP 데이터 길이가 32바이트이며 별도의 분할·재조립 표시가 없으므로, 작은 VIN 응답은 하나의 TCP 세그먼트로 전송된 것을 확인할 수 있다.
2. 펌웨어 대용량 데이터 전송 — TCP 분할 및 재조립#

① 펌웨어처럼 크기가 큰 데이터는 하나의 TCP 세그먼트에 담을 수 없으므로 여러 TCP 세그먼트로 분할되어 전송된다. 패킷 목록의 [TCP PDU reassembled in 113] 표시는 각 데이터가 113번 패킷에서 재조립됨을 의미한다.
② 113번 패킷에서 분할된 데이터의 재조립이 완료되며, Wireshark가 이를 하나의 Read Data By Identifier UDS 응답으로 분석한다. 응답 대상 DID는 0xF200이다.
③ TCP 상세 정보의 30 Reassembled TCP Segments (102415 bytes)를 통해 총 30개의 TCP 세그먼트가 102415바이트의 데이터로 재조립된 것을 확인할 수 있다.
④ DoIP Header의 Length: 102407은 재조립된 DoIP 메시지의 Payload Length가 102407바이트임을 나타낸다. TCP 재조립 길이 102415바이트와의 8바이트 차이는 DoIP Generic Header의 크기이다.
⑤ UDS 상세 정보에서 Data Identifier: 0xF200과 대용량 Data Record를 확인할 수 있다. 이는 재조립된 데이터가 펌웨어 전송에 사용된 하나의 UDS 응답임을 보여준다.
따라서 펌웨어 응답은 논리적으로 하나의 DoIP/UDS 메시지이지만, 실제 TCP 통신에서는 여러 세그먼트로 분할되어 전달된 뒤 수신 측에서 다시 하나의 메시지로 재조립된다. 앞서 확인한 24바이트 VIN 응답이 하나의 TCP 세그먼트로 전송된 것과 비교하면, 데이터 크기에 따른 TCP 분할 및 재조립의 차이를 확인할 수 있다.
실습 4. 소켓 버퍼별 처리량#
1 MB 펌웨어 수신 과정에서 수신 버퍼 크기만 바꿔 처리량을 비교한다. 버퍼가 작을수록 처리량이 크게 떨어진다.
./ecu_bigdata 1024
./tester_bigdata sockbuf 4096
./tester_bigdata sockbuf 65536
./tester_bigdata sockbuf 262144
| 요청한 크기 | 커널이 준 크기 | 처리량 |
|---|---|---|
| 4 KB | 8 KB | 수백 Mbps |
| 64 KB | 128 KB | 수천에서 수만 Mbps |
| 256 KB | 512 KB | 더 높아짐 |


실습 4 분석 : 소켓 버퍼의 크기와 처리량#
TCP는 수신 측의 윈도우 크기에 맞춰 송신량을 조절한다. 수신 버퍼가 작으면 송신 측에서 전송량을 줄이기 때문에 링크 대역폭을 채우지 못한다.
| 확인할 것 | 무엇이 보이는지 |
|---|---|
캡처의 Win 값 |
수신 버퍼가 작으면 광고하는 창 크기도 작아짐 |
| 왕복 시간의 영향 | 지연이 클수록 작은 버퍼의 손해가 커짐 |
| 필요한 버퍼 크기 | 대역폭과 왕복 시간을 곱한 값 정도는 있어야 함 |
실습 4 분석 : 실제 ECU에서의 선택#
실제 진단 장비와 게이트웨이도 소켓 버퍼를 조정한다. 다만 버퍼 크기를 무한정 확장할 수는 없으므로, 제한된 메모리 안에서 균형을 찾아야 한다.
| 선택 | 얻는 것 | 잃는 것 |
|---|---|---|
| 버퍼를 크게 | 대용량 전송이 빨라짐 | 다른 기능이 쓸 메모리가 줄어듦 |
| 버퍼를 작게 | 메모리를 아낌 | 전송이 느려지고 링크를 못 채움 |