DoIP를 붙일 때는 IP와 포트만 겹치지 않으면 될 것처럼 보인다.
그런데 실제로는 Source Address가 겹쳐도 로그가 금방 이상해진다.
- Routing Activation은 된다
- 첫 요청도 가끔 된다
- 그런데 응답이 엉뚱한 요청에 붙는다
- 어떤 때는 그냥 timeout처럼 보인다
이럴 때 ECU 버그나 TCP 문제부터 의심하기 쉽다.
하지만 원인은 더 단순한 경우가 있다.
오늘 메모는 DoIP에서 두 테스터나 두 프로세스가 같은 Source Address를 쓸 때 보이는 전형적인 증상이다.
결론부터
DoIP에서는 Source Address가 단순 표식이 아니다.
ECU나 게이트웨이는 이 값을 기준으로
어느 테스터 문맥에서 온 요청인지 구분한다.
tester A: SA 0E80
tester B: SA 0E80
-> ECU 입장에서는 둘을 같은 발신자로 볼 수 있음
그래서 같은 SA를 공유하면 아래 문제가 쉽게 생긴다.
- 응답이 다른 프로세스로 돌아간다
- 이전 세션 문맥이 덮인다
- Routing Activation 이후 상태가 섞인다
- timeout처럼 보이지만 실제로는 응답 매칭 실패다
즉 IP가 달라도
같은 ECU 대상으로 같은 SA를 동시에 쓰지 않는 편이 안전하다.
왜 초반에는 멀쩡해 보이나
이 문제는 항상 바로 터지지 않는다.
- 한 번에 한 테스터만 요청하면 지나간다
- 테스트가 짧으면 응답이 우연히 맞아 떨어진다
- 장비 재시작 직후에는 세션 문맥이 비어 있다
그러다가 아래 상황이 겹치면 이상해진다.
- 두 툴이 같은 ECU에 번갈아 요청한다
- 백그라운드 keepalive와 수동 진단이 같이 돈다
- 재연결 직후 이전 요청 응답이 늦게 도착한다
즉 체감상으로는
“가끔 응답이 사라진다”가 된다.
흔한 패턴 1: PC 툴과 자동화 프로세스가 같은 SA를 쓴다
가장 흔한 그림은 이렇다.
tool A
-> Routing Activation with SA 0E80
-> ReadDataByIdentifier
tool B
-> Routing Activation with SA 0E80
-> Tester Present
ECU / gateway
-> 응답 문맥 충돌 또는 이전 상태 덮어쓰기
이 경우 패킷 자체는 정상처럼 보여도
앱에서는 아래처럼 보일 수 있다.
- Tool A의 요청 응답을 Tool B가 받음
- Tool B의 keepalive 뒤에 Tool A의 세션이 끊긴 것처럼 보임
- 한쪽은
timeout, 다른 쪽은 “이상한 양의 응답”으로 기록됨
흔한 패턴 2: 한 프로그램 안에서 소켓 두 개가 같은 SA를 쓴다
외부 툴 충돌만 있는 것은 아니다.
프로그램 내부에서도 이런 구조가 나온다.
foreground diagnostic client -> SA 0E80
background monitor thread -> SA 0E80
개발자는 “같은 장비니까 같은 SA를 써도 되겠지”라고 생각하기 쉽다.
하지만 연결이 둘이면 상태도 둘이다.
특히 아래 조합에서 잘 꼬인다.
- foreground는 긴 UDS 요청 대기 중
- background는 주기 Tester Present 송신
- 둘 다 같은 SA 사용
그러면 ECU는 둘을 같은 발신자로 보고
어느 요청 문맥을 이어야 할지 애매해질 수 있다.
흔한 패턴 3: 재연결 뒤 늦게 온 응답이 새 세션에 섞인다
이 문제는 재연결 구간에서 더 헷갈린다.
old socket with SA 0E80
-> request sent
-> connection resets
new socket with SA 0E80
-> Routing Activation again
-> new request sent
late response from old flow
-> app logs become ambiguous
테스터 로그에는 그냥 순서가 꼬인 것처럼 보인다.
하지만 실제로는 같은 SA를 재사용한 새 연결이 문제를 더 키운다.
그래서 재연결 직후에는
- 소켓 세대
- Routing Activation 세대
- SA 재사용 시점
을 같이 기록하는 편이 좋다.
왜 timeout으로 오해하기 쉬운가
응답이 완전히 사라지는 게 아니라
“내가 기다리던 곳으로 안 돌아오는” 경우가 많기 때문이다.
예를 들면 이런 식이다.
request A sent
-> response is emitted by ECU
-> app A does not match it
-> app A reports timeout
패킷 캡처만 보면 응답은 있었다.
그런데 애플리케이션은 timeout이라고 쓴다.
이때 네트워크 timeout 정책만 조정하면
문제를 더 오래 끌게 된다.
구현 쪽에서 무난한 패턴
가장 단순한 원칙은 하나다.
동시에 살아 있는 진단 클라이언트마다 SA를 분리한다.
예를 들면:
interactive tester -> SA 0E80
background monitor -> SA 0E81
factory automation -> SA 0E82
그리고 같은 프로세스 안에서도
SA별로 상태를 묶는 편이 좋다.
- socket generation
- routing activation state
- pending UDS request
- current diagnostic session
즉 SA를 단순 상수가 아니라
세션 식별자의 일부로 다루는 편이 안전하다.
로그를 이렇게 남기면 빨라진다
이 문제는 ECU 로그 없이도 테스터 쪽에서 꽤 빨리 잡을 수 있다.
나는 보통 아래 항목을 같이 남긴다.
- 소켓별 local IP, remote IP, remote port
- 각 연결의 Source Address
- Routing Activation 성공 시각과 activation 타입
- 현재 pending UDS 요청 SID
- 응답을 받은 프로세스나 스레드 식별자
이 다섯 줄이 있으면
“응답이 안 왔다”보다
“응답이 다른 SA 문맥으로 갔다”를 먼저 볼 수 있다.
빠른 체크리스트
- 같은 ECU 대상으로 동시에 살아 있는 연결들이 같은 SA를 쓰지 않는지 확인
- 백그라운드 keepalive나 모니터링 프로세스가 같은 SA를 재사용하지 않는지 확인
- 재연결 뒤 새 소켓이 이전 소켓과 같은 SA를 바로 재사용하는지 확인
- 응답 매칭 키에 SA와 소켓 세대가 함께 들어가는지 확인
- timeout 로그를 보기 전에 실제 패킷 캡처에서 응답이 다른 연결로 간 흔적이 없는지 확인
한 줄 요약
DoIP에서 Routing Activation은 되는데 응답이 가끔 섞이거나 timeout처럼 사라져 보이면, ECU보다 먼저 같은 대상 ECU에 대해 Source Address를 누가 같이 쓰고 있는지 확인하는 편이 빠르다.
추천 키워드
DoIP, UDS, Source Address, Routing Activation, Diagnostic Message, timeout
DevBJ | 오늘을살자, Log Today