시험끝!
나오는 문제들은 보라색으로 표시를 해둔다. (2016-04-26)
TCP/IP 윈도우 소켓 프로그래밍
24p - 어떠한 구조
호스트(End user) - 라우터 - 인터넷 - 라우터 - 호스트(End user)
호스트는 응용프로그램을 사용해서 TCP/IP 프로토콜 통신을 거친다.
27p - TCP와 UDP 특징 표 -- 객관식
TCP |
UDP |
연결형 |
비연결형 |
신뢰성 있음 |
신뢰성 없음 |
1:1 Unicast |
1:1 Unicast OR 1:x Broadcast, Multicast |
byte stream |
datagram |
28p - 데이터 전송 원리 간단하게
Application |
|
|
|
Data |
|
TCP |
|
|
TCP Header |
Data |
|
IP |
|
IP Header |
TCP Header |
Data |
|
Ethernet |
Ethernet Header |
IP Header |
TCP Header |
Data |
Ethernet Trailer |
송신 측에서는 응용 프로그램부터 시작해서 이더넷까지 캡슐화
수신 측에서는 이더넷부터 시작해서 응용 프로그램까지 역캡슐화
37p - 윈도우 소켓 특징 (Winsock) -- 객관식
1) DLL 초기화와 종료 작업을 위한 함수
2) 메시지 구동 방식 함수를 가지고 있다.
3) 멀티스레드 환경 함수를 가지고 있다.
4) TCP/IP 프로토콜 지원
5) IPv6 프로토콜 지원
6) IrDA 프로토콜 지원
7) 블루투스 프로토콜 지원
38p - 윈도우소켓 장단점 -- 객관식
장점 |
유닉스 소켓 수준에서 호환성이 높아 활용성이 좋다. |
많이 사용하는 네트워크 프로그래밍 인터페이스라서 호환성이 좋다. |
|
많은 프로토콜을 지원하므로 최소 수정으로 사용하는 프로토콜을 변경할 수 있다. |
|
low 또는 mid 레벨 프로그래밍으로 세부 제어가 가능하고 고성능 프로그램 개발이 가능하다. |
|
단점 |
응용 프로그램의 프로토콜을 직접 개발해야한다. 예를 들어 데이터 형식이나 전송 절차등을 생각해서 프로그래밍 해야한다. |
서로 다른 바이트 정렬(byte ordering), 32비트와 64비트가 통신할 경우 데이터 변환이 필요하다. |
64p - 소켓 주소 구조체 전반, 소스 다 읽기
네트워크에서 필요한 주소 정보를 담고 있는 struct 이다.
아래는 기본적인 SOCKADDR 구조를 가진 ws2def.h 파일이다.
typedef struct sockaddr {
// 주소 체계를 나타내는 16bit 정수. ex) AF_INET OR AF_INET6
u_short sa_family;
// 주소 체계에서 사용할 주소 정보를 바이트 배열로 저장. ex) IPADDR+PORT
char sa_data[14];
} SOCKADDR;
구조체 이름 |
전체 크기(bytes) |
SOCKADDR |
16 |
SOCKADDR_IN |
16 |
SOCKADDR_IN6 |
28 |
SOCKADDR_IRDA |
32 |
SOCKADDR_BTH |
30 |
소켓 주소를 소켓 함수 인자로 전달할 때는 항상 주소 값을 사용한다.
반드시 SOCKADDR 포인터형으로 변환해야 한다.
// 소켓 주소 구조체 초기화
SOCKADDR_IN addr;
SocketFunc ( ..., (SOCKADDR *)&addr, sizeof(addr), ...);
68p - 바이트 정렬 함수 -- 객관식
Big-endian, 최상위 바이트(MSB)부터 차례로 저장
Little-endian, 최하위 바이트(LSB)부터 차례로 저장
0x12345678 을 메모리를 저장할 때 방식 |
||||
Big-endian |
0x12 |
0x34 |
0x56 |
0x78 |
Little-endian |
0x78 |
0x56 |
0x34 |
0x12 |
70p - hton, ntoh (host-to-network, network-to-host)
hton 함수는 호스트 바이트 정렬로 저장된 값을 입력받아 네트워크 바이트 정렬로 변환한 값을 보낸다.
응용프로그램이 소켓 함수에 데이터를 넘겨주기 전에 hton 호출
ntoh 함수는 네트워크 바이트 정렬로 저장된 값을 입력받아 호스트 바이트 정렬로 변환한 값을 보낸다.
소켓 함수가 응용프로그램에 데이터를 넘겨주기 전에 ntoh 호출
단순하게 ntoh는 hton의 반대
73p - 주소변환
IPv4 주소 변환
// 문자열(192.168.100.1) -> 32비트 숫자(11000000 10101000 01100100 00000001)
unsigned long inet_addr(const char *cp);
// 32비트 숫자 -> 문자열
char *inet_ntoa(struct in_addr in);
IPv6 와 IPv4 주소 변환
int WSAStringToAddress(
LPTSTR AddrString, //문자열 IP주소
INT AddrFamily, //AF_INET 또는 AF_INET6
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPSOCKADDR lpAddr, // IP주소를 저장할 구조체
LPINT lpAddrLen //위 구조체의 길이
);
int WSAAddressToString(
LPSOCKADDR lpsaAddr, //32비트 숫자 IP주소
DWORD dwAddrLen, // 구조체 길이
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPSTR lpszAddrString, // 문자열 IP주소를 저장할 구조체
LPDWORD lpdwAddrStringLen // 버퍼 길이
);
inet_addr 과 addr.sin_addr 함수는 이미 32비트 정렬된 IP 이므로 htonl이나 ntohl 함수를 쓰면 아니된다.
92p - 서버와 클라이언트 동작원리
서버는 소켓을 생성한다. ▶ 서버는 클라이언트 연결을 기다린다. (특정 포트번호만 연결)
▶ 클라이언트가 서버에 접속한다. (TCP 패킷교환, 1:SYN, 2:SYN/ACK, 3:ACK)
▶ 서버는 통신을 위한 새로운 소켓을 생성한다. (기존 소켓은 새로운 클라이언트를 받음)
▶ 다른 클라이언트가 접속한다면 새로 생성한 것을 제외하고 기존에 있던 소켓을 사용한다.
94p - TCPServer 와 TCPClient 소스코드 괄호넣기, socket(), bind(), listen(), connect(), accept(), 중요한부분
주관식 빈칸문제이며 빈칸인 부분은 보라색 표시함.
SEVERPORT와 SERVERIP는 정의된 값입니다.
socket ()
SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if(listen_sock == INVALID_SOCKET) err_quit("socket()");
bind ()
SOCKADDR_IN serveraddr;
ZeroMemory(&serveraddr, sizeof(serveraddr)); // memset (&saddr, 0, sizeof()); 도 가능함.
serveraddr.sin_family = AF_INET; // IPv4 사용
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // 아무 클라이언트IP 접속가능
serveraddr.sin_port = htons(SERVERPORT);
retval = bind(listen_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr));
if(retval == SOCKET_ERROR) err_quit("bind()");
listen ()
retval = listen(listen_sock, SOMAXCONN);
if(retval == SOCKET_ERROR) err_quit("listen()");
accept ()
addrlen = sizeof(clientaddr);
client_sock = accept(listen_sock, (SOCKADDR *)&clientaddr, &addrlen);
if(client_sock == INVALID_SOCKET) {
err_display("accept()");
break; // While문이 앞에 열려 있음.
}
connect ()
SOCKADDR_IN serveraddr;
ZeroMemory(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(SERVERIP);
serveraddr.sin_port = htons(SERVERPORT);
retval = connect(sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr));
if(retval == SOCKET_ERROR) err_quit("connect()");
106p - TCP 서버 함수들이 무엇을 하는 기능인지 설명 -- 주관식
TCP 서버 함수
socket( ) |
소켓을 생성하여 사용할 프로토콜을 결정 |
bind( ) |
지역 IP주소와 포트 번호를 설정 |
listen( ) |
TCP를 LISTENING상태로 변경 |
accept( ) |
클라이언트와 통신할 수 있는 새로운 소켓 생성(원격IP주소+포트 결정) |
closesocket( ) |
send, recv 실행 후 소켓을 닫음 |
112p - TCP 클라이언트 함수들이 무엇을 하는 기능인지 설명 -- 주관식
TCP 클라이언트 함수
socket( ) |
소켓을 생성하여 사용할 프로토콜을 설정 |
connect( ) |
서버 접속 시 원격IP+포트 와 지역IP+포트 설정 |
closesocket( ) |
send, recv 실행 후 소켓을 닫음 |
134p - 데이터 전송 경계 구분 4가지 -- 주관식
번호 | 수신자 | 송신자 |
1 | 고정길이 데이터 보냄 |
고정길이 데이터 읽음 |
2 | 가변길이 데이터+EOR |
EOR이 나올 때까지 데이터 읽음 |
3 | 보낼 크기: 고정길이 데이터 가변길이 데이터 보냄 |
고정길이 데이터를 읽고 가변 길이 알아냄 그 길이만큼 데이터 읽음 |
4 | 가변길이 데이터 전송 후 접속 종료 |
recv함수의 return값이 0이 될 때까지 읽음 |
138p - 고정길이 데이터전송, 고정길이+가변길이 데이터 전송 개념 알기
이 부분은 책을 참고한다. 소스 코드의 전체를 복붙할 수는 없다..
174p - 스레드 기본 개념 -- 객관식
일반적인 프로세스 = 윈도우 프로세스 + 스레드
윈도우에서 프로세스 |
code, data 등을 저장하는 컨테이너, 정적임 |
스레드 |
CPU 시간을 받아 프로세스 메모리의 code 수행, 동적임 |
메인 스레드 | Winmain() 또는 main() 함수에서 시작. 이를 활용하여 멀티스레드로 만듦 |
스레드의 context switch (간단하게 표현)
조건: 메모리의 스택은 유지된다. / CPU 레지스터의 값이 수정된다.
스레드가 A, B가 있다.
스레드 A가 실행 중 일 때, 스레드A의 상태를 저장하고,
스레드B를 불러와 실행하고, 스레드B의 상태를 저장하고, 저장된 스레드 A를 불러와서 실행한다.
180p - 스레드 종료하는 방법 4가지 -- 객관식
스레드 함수가 리턴한다. | 권장사항 |
스레드 함수 안에서 ExitThread( ) 함수를 호출한다. |
|
다른 스레드가 TerminateThread( ) 함수를 호출해 스레드를 강제 종료시킨다. | 필요한 경우 |
주 스레드가 종료하면 모든 스레드가 종료된다. | 메인스레드 특성 |