네트워크 계층 구조의 기준이라고 할 수 있는 ISO의 OSI 7 계층과 달리 TCP/IP는 5개 계층이다.

- 응용 계층
- 사용자에게 서비스를 제공하기 위한 계층
- Telnet, FTP, HTTP, SMTP, DNS
- 전송 계층
- 네트워크 계층
- 네트워크 접속 계층, 하드웨어 계층
- 물리적인 네트워크와의 연결을 담당. 이더넷 카드, 랜 카드
TCP / IP 프로토콜
TCP
- 전화를 걸 때처럼 데이터를 주고받기 전에 송신측과 수신측이 연결되어 있어야 함.
- 송신한 데이터가 수신측에 도착했는지 확인하는 과정을 거침
- 데이터를 주고 받는 속도를 조절할 수 있음
UDP
- 사전에 목적지와 연결을 설정하지 않고, 상대방이 데이터를 수신 했는지 확인하지 않음
- 단순히 목적지 주소를 지정해 네트워크로 전송
- 중도에 데이터가 분실되어도 신경 쓰지 않음
- 신뢰성보단 속도

소켓 인터페이스
- 응용 계층에서 전송 계층의 기능을 사용할 수 있도록 제공하는 응용 프로그램 인터페이스(API)
- 응용 프로그램과 TCP 계층을 연결하는 역할

IP 주소와 호스트명
- IP 주소
- 인터넷을 이용할 때 사용하는 주소로, 점(.)으로 구분된 32비트 숫자로 표시
- IP 주소를 네트워크 주소라고도 함
- 호스트명
- IP주소 외에 이름을 지정
- 인터넷에서 사용하는 호스트명은 호스트명+도메인명 형태로 구성
- DNS : 호스트명과 도메인명을 관리하는 시스템
호스트명과 IP주소 읽어오기 : gethostent(), sethostent(), endhostent()
- h_name : 호스트명을 저장
- h_aliases : 호스트를 가리키는 다른 이름들을 저장
- h_addrtype : 호스트 주소의 형식을 지정
- h_length : 주소의 길이를 저장
- h_addr_list : 해당 호스트의 주소 목록을 저장,이 항목의 값을 해석하려면 2절에서 배우는 함수들이 필요
int main(){
struct hostent *hent;
sethostent(0);
while((hent = gethostent()) != NULL)
printf("Name=%s\n", hent->h_name);
endhostent();
}
호스트명으로 정보 검색 : gethostbyname()
IP 주소로 정보검색 : gethostbyaddr()
포트 번호
- IP 주소 구분의 필요성
- IP 주소는 데이터가 전송될 목적지 호스트를 알려주는 역할을 수행.
- 포트 번호
- 2바이트 정수로 되어 있으므로 0~65535까지 사용가능
- 대표적인 포트 번호는 SSH 프로토콜이 22, FTP가 21, HTTP가 80
- 일반 프로그램 1024~65535
- 이미 정해진 포트 번호는 /etc/services 파일에 등록
포트정보 읽어오기 : getservent(), setservent(), endservent()
포트 정보 읽어오기
int main(){
struct servent *port;
int n;
setservent(0);
for(n = 0; n < 5; n++){
port = getservent();
printf("Name = %s, Port = %d\n", port->s_name, port->s_port);
}
endservent();
}
서비스명으로 정보 검색 : getservbyname(name, proto)
- proto에는 “tcp”나 “udp” 혹은 NULL
포트 번호로 정보 검색 : getservbyport()
소켓의 종류
- 유닉스 도메인 소켓
- 같은 호스트에서 프로세스 사이에 통신할 때 사용
- 패밀리명 : AF_UNIX
- 인터넷 소켓
- 인터넷을 통해 다른 호스트와 통신할 때 사용
- 패밀리명 : AF_INET
소켓의 통신 방식
- 프로토콜
- 소켓을 이용할 때도 하부 프로토콜로 TCP를 사용할 것인지 UDP를 사용할 것인지 지정해야 하는데 이 때 정의된 상수 사용
- SOCK_STREAM : TCP 사용
- SOCK_DGRAM : UDP 사용
- 소켓의 네 가지 통신 유형
- AF_UNIX - SOCK_STREAM
- AF_UNIX - SOCK_DGRAM
- AF_INET - SOCK_STREAM
- AF_UNIX - SOCK_DGRAM
바이트 순서 함수
- 빅 엔디언
- 각각 바이트를 순서대로 저장
- 메모리의 낮은 주소에 정수의 첫 바이트를 위치
- 리틀 엔디언
- 각각 바이트를 거꾸로 저장
- 메모리의 높은 주소에 정수의 첫 바이트를 위치
- 네트워크 바이트 순서(NBO), 호스트 바이트 순서(HBO)
- TCP/IP 에서는 무조건 빅 엔디언 방식 채택
- 통신을 통해 데이터를 내보낼 때 HBO → NBO, 받으면 NBO→HBO 변환 후 처리
NBO를 HBO로 변환
int main(){
struct servent *port;
int n;
setservent(0);
for(n = 0 ; n < 5; n++){
port = getservent();
printf("Name = %s, Port = %d\n", port->s_name, ntohs(port->s_port));
}
endservent();
}
HBO를 NBO로 변환
int main(){
struct servent *port;
port = getservbyname("ssh", "tcp");
printf(("Name = %s, Port = %d\n", port->s_name, ntohs(port->s_port));
port = getservbyname(htons(21), "tcp");
printf(("Name = %s, Port = %d\n", port->s_name, ntohs(port->s_port));
}
포트 번호로 검색하려면 포트 번호를 NBO로 지정해야 함
getservbyport() 함수의 첫 번째 인자는 htons() 함수를 사용해 포트 번호를 HBO에서 NBO로 변환해 지정
문자열 IP 주소를 숫자로 변환 : inet_addr()
ip 주소를 문자열로 받아 이를 이진값으로 바꿔서 리턴
구조체 IP 주소를 문자열로 변환 : inet_ntoa()
소켓 인터페이스 함수의 종류
- socket( ) : 소켓 파일 기술자 생성
- bind( ) : 소켓 파일 기술자를 지정된 IP 주소/포트 번호와 결합
- listen( ) : 클라이언트의 연결 요청 대기
- connect( ) : 클라이언트가 서버에 접속 요청
- accept( ) : 클라이언트의 연결 요청 수락
- send( ) : 데이터 송신(SOCK_STREAM)
- recv( ) : 데이터 수신(SOCK_STREAM)
- sendto( ) : 데이터 송신(SOCK_DGRAM)
- recvfrom( ) : 데이터 수신(SOCK_DGRAM)
- close( ) : 소켓 파일 기술자 종료

유닉스 도메인 소켓(서버)
#define SOCKET_NAME "hbsocket"
int main(){
char buf[256];
struct sockaddr_un ser, cli;
int sd, nsd, len, clen;
sd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&ser, 0, sizeof(struct sockaddr_un));
ser.sun_family = AF_UNIX;
strcpy(ser.sun_path, SOCKET_NAME);
len = sizeof(ser.sun_family) + strlen(ser.sun_path);
bind(sd, &ser, len);
listen(sd, 5);
nsd = accept(sd, &cli, &clen);
recv(nsd, buf, sizeof(buf));
printf("Received message : %s\n", buf);
close(nsd);
close(sd);
}
유닉스 도메인 소켓(클라이언트)
#define SOCKET_NAME "hbsocket"
int main(){
int sd, len;
char buf[256];
struck sockaddr_un ser;
sd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&ser, '\0', sizeof(ser));
ser.sun_family = AF_UNIX;
strcpy(ser.sun_path, SOCKET_NAME);
len = sizeof(ser.sun_family) + strlen(ser.sun_path);
connect(sd, &ser, len);
strcpy(buf, "Unix Domain Socket Test");
send(sd, buf, sizeof(buf));
close(sd);
}