앞서 이야기했듯이 여기서는 의사 코드 형태로, 각 코드 라인이 무슨 일을 하는지 살펴봅니다.
➊ socket(TCP)는 TCP 소켓 핸들 s를 생성합니다. 아직 s는 아무것도 할 수 없습니다.
➋ s.bind(any_port)는 자기 컴퓨터(localhost) 안에 있는 포트 6만 5535개 중에서 사용 가능한 포트(빈 포트)를 차지합니다. 빈 포트가 없을 경우 이미 다른 곳에서 점유한 포트라고 하더라도 그것을 공유합니다. 그런다고 해서 작동에 문제가 생기는 것은 아닙니다. TCP 통신을 할 수 있으려면 상대방 끝점을 알아야 할 뿐만 아니라 자기 자신의 끝점도 알아야 합니다. 이것이 함수를 호출하는 이유입니다.
➌ connect(xxx)는 상대방 끝점을 향해 TCP 연결을 시도합니다. 그리고 이 함수는 블로킹이 일어납니다. TCP 연결이 완료될 때까지 블로킹을 유지하다가 상대방이 연결을 수락하면 함수는 리턴을 합니다. 상대방이 연결을 거절하거나 상대방이 존재하지 않는 경우(상대방 컴퓨터가 꺼져 있는 경우) 마찬가지로 함수는 리턴을 합니다. 우리는 함수가 리턴한 후 연결이 성공했는지 실패했는지 알 수 있습니다.
➍ send(xxx)는 상대방 끝점을 향해 데이터를 전송합니다. 이 함수는 자기 컴퓨터의 운영체제에서 상대방 컴퓨터로 데이터를 전송하는 처리가 완료되면 리턴합니다. 여기서 주의할 점이 있습니다. 이 함수가 리턴했다고 해서 상대방이 데이터를 성공적으로 수신했다는 말은 아닙니다. 자세한 것은 뒤에서 설명하겠습니다.
➎ close()는 TCP 소켓을 닫습니다. TCP 소켓을 닫으면서 TCP 연결도 해제됩니다.
안타깝게도 이 의사 코드는 생각과 다르게 작동합니다. 호출한 send()는 블로킹 없이 즉시 리턴할 것입니다. 그리고 뒤에서 설명할 TCP를 수신하는 코드에서는 데이터를 가끔 수신하지 못할 것입니다. 왜 이러한 일이 생길까요? 이를 이해하려면 운영체제가 소켓 송신과 수신을 어떻게 처리하는지, 그리고 소켓 버퍼(socket buffer)에 대한 이해가 필요합니다.