Skip to content

실습 목표#

  • TCP 예제 코드를 실행하고 연결이 맺어지는 과정을 WireShark로 분석한다.
  • SEQ와 ACK 번호로 신뢰성이 어떻게 확보되는지 확인한다.
  • 코드를 직접 고쳐 보내는 데이터를 바꾸고 서버 응답을 추가한다.


실습. TCP 예제 코드 실행#


실습 진행#

라즈베리파이와 노트북에서 각각 아래와 같이 build한다. 라즈베리파이에서 tcp_server를 먼저 실행하고, 노트북에서 tcp_client를 실행한다.

라즈베리파이·터미널
make
./tcp_server
노트북·WSL
make
./tcp_client


WireShark에서 필터를 'tcp.port==9999'로 설정한다. TCP 예제 코드 실행


SYN 분석#

다음 표를 참고하여 SYN 비트를 분석한다.

9c 6d 27 0f 5b 52 f3 91 00 00 00 00 a0 02 fa f0
63 e4 00 00 02 04 05 b4 04 02 08 0a a4 e6 9c 8c
00 00 00 00 01 03 03 0a

오프셋 바이트 필드 의미
0~33 1타임과 같은 구조 Ethernet + IP Header -
34 ~ 35 96 6d Src Port OS가 임시 할당한 Port #, 40045
36 ~ 37 27 0f Dst Port 9999
38 ~ 41 5b 52 f3 91 Seq # 첫 Seq #는 임의의 값, 상대 번호 0
42 ~ 45 00 00 00 00 Ack # 첫 Ack #는 0
46 a0 Data Offset / Reserved TCP Header 길이, 10 X 4 Bytes = 40 Bytes
47 02 TCP Flags SYN
48 ~ 49 fa f0 Window Size 수신 버퍼 크기, 64240
50 ~ 51 63 e4 Checksum 오류 검출용
52 ~ 53 00 00 Urgent Pointer 긴급 데이터 위치, 미사용
54 ~ 73 02 04 05 b4 ⋯ 03 03 0a TCP Options MSS 1460 · SACK · Timestamp · WS 1024


SYN, ACK 분석#

다음 표를 참고하여 SYN 비트와 ACK 비트를 분석한다.

27 0f 9c 6d 98 f3 0d d5 5b 52 f3 92 a0 12 fe 88
aa 9d 00 00 02 04 05 b4 04 02 08 0a 49 f2 c4 e2
a4 e6 9c 8c 01 03 03 0a

오프셋 바이트 필드 의미
0~33 1타임과 같은 구조 Ethernet + IP Header -
34 ~ 35 27 0f Src Port 9999
36 ~ 37 9c 6d Dst Port OS가 임시 할당한 Port #, 40045
38 ~ 41 98 f3 0d d5 Seq # 첫 Seq #는 임의의 값, 상대 번호 0
42 ~ 45 5b 52 f3 92 Ack # SYN의 Seq # + 1, 상대 번호 1
46 a0 Data Offset / Reserved TCP Header 길이, 10 X 4 Bytes = 40 Bytes
47 12 TCP Flags SYN + ACK
48 ~ 49 fe 88 Window Size 수신 버퍼 크기, 65160
50 ~ 51 aa 9d Checksum 오류 검출용
52 ~ 53 00 00 Urgent Pointer 긴급 데이터 위치, 미사용
54 ~ 73 02 04 05 b4 ⋯ 03 03 0a TCP Options MSS 1460 · SACK · Timestamp · WS 1024


ACK 분석#

다음 표를 참고하여 ACK 비트를 분석한다.

9c 6d 27 0f 5b 52 f3 92 98 f3 0d d6 80 10 00 3f
d7 b5 00 00 01 01 08 0a a4 e6 9c 8d 49 f2 c4 e2

오프셋 바이트 필드 의미
0~33 1타임과 같은 구조 Ethernet + IP Header -
34 ~ 35 9c 6d Src Port OS가 임시 할당한 Port #, 40045
36 ~ 37 27 0f Dst Port 9999
38 ~ 41 5b 52 f3 92 Seq # SYN의 Seq # + 1, 상대 번호 1
42 ~ 45 5b 52 f3 92 Ack # SYN, ACK의 Seq # + 1, 상대 번호 1
46 80 Data Offset / Reserved TCP Header 길이, 8 X 4 Bytes = 32 Bytes
47 10 TCP Flags ACK
48 ~ 49 00 3f Window Size 수신 버퍼 크기, 63 X 1024 = 64512
50 ~ 51 d7 b5 Checksum 오류 검출용
52 ~ 53 00 00 Urgent Pointer 긴급 데이터 위치, 미사용
54 ~ 65 01 01 08 0a ⋯ c4 e2 TCP Options NOP · Timestamp 12 Bytes


데이터 전송 분석#

9c 6d 27 0f 5b 52 f3 92 98 f3 0d d6 80 18 00 3f
d3 15 00 00 01 01 08 0a a4 e6 9c 8e 49 f2 c4 e2
48 65 6c 6c 6f 20 54 43 50 20 66 72 6f 6d 20 6c
61 70 74 6f 70
오프셋 바이트 필드 의미
0~33 1타임과 같은 구조 Ethernet + IP Header -
34 ~ 35 9c 6d Src Port OS가 임시 할당한 Port #, 40045
36 ~ 37 27 0f Dst Port 9999
38 ~ 41 5b 52 f3 92 Seq # 상대 번호 1, 데이터의 시작 위치
42 ~ 45 98 f3 0d d6 Ack # 상대 번호 1
46 80 Data Offset / Reserved TCP Header 길이, 8 X 4 Bytes = 32 Bytes
47 18 TCP Flags PSH + ACK
48 ~ 49 00 3f Window Size 수신 버퍼 크기, 63 X 1024 = 64512
50 ~ 51 d3 15 Checksum 오류 검출용
52 ~ 53 00 00 Urgent Pointer 긴급 데이터 위치, 미사용
54 ~ 65 01 01 08 0a ⋯ c4 e2 TCP Options NOP · Timestamp 12 Bytes
66 ~ 86 48 65 6c 6c 6f ⋯ 6f 70 Data Hello TCP from laptop, 21 Bytes


과제 1. 보내는 데이터 변경#


노트북 tcp_client_blank.cpp에서 보내는 데이터를 변경한다. 실습 1과 같이 build후, 라즈베리파이에서 tcp_server를 먼저 실행하고 노트북에서 tcp_client_blank를 실행한다.

tcp_client_blank.cpp
const char* msg = "________________";
노트북·WSL
make
./tcp_client_blank

송신 측에서 보낸 바이트 수가 많을 수록 수신 측의 ACK 값이 증가한다. "_" 안의 문자열을 바꿔가며 전송해 보자.

관찰 포인트

이 때 라즈베리파이 화면에 바뀐 내용이 찍히는지, 캡처의 Len 값이 얼마로 바뀌는지 확인한다.

예시 문장
const char* msg = "Hello from ACE Lab";


과제 2. 서버가 응답 보내기#


이번에는 라즈베리파이 tcp_server_blank.cpp에서 recv 아래에 응답을 보내는 줄을 추가하여 수신 측에서 응답을 보낸다. TCP는 이미 연결된 소켓으로 보내기 때문에 주소를 다시 적지 않아도 된다.
send('_')에 들어갈 문장을 바꿔가며 보내보자.

tcp_server_blank.cpp
const char* reply = ________;
send(____, reply, strlen(reply), 0);
라즈베리파이·터미널
make
./tcp_server_blank

관찰 포인트

1타임 UDP의 sendto와 무엇이 다른지 생각해 보고 빈칸을 채워보자.

예시 문장
const char* reply = "ACK from Pi";
send(conn, reply, strlen(reply), 0);

관찰 포인트

노트북 측에서 ACK from Pi(또는 직접 작성한 문장)이 왔는지, 캡처에 양방향 데이터가 보이는지 확인한다.