본문 바로가기
코스웨어/10년 시스템제어

12번 박철민 보고서.

by 알 수 없는 사용자 2010. 4. 8.
728x90
반응형

수업시간 진도대신(다들 소스공개로 해봤고 주석도 달았으므로) 처음배웠던 가장중요한
서버 통신의 6가지단계(5단계라고도함)에 대하여 알아봤습니다.

* 몇가지 몰랐던것들..
* WORD : 16비트 unsigned int를 의미(WORD wId == unsigned int wId)
* LPVOID : Long Pointer void (void *)를 줄여놓음.

* getpeername
--------------------------------------------------------------
 getpeername(client_sock,(SOCKADDR *)&clientaddr,&addrlen);
---------------------------------------------------------------
getpeername 함수는 소켓이 연결되어 있는 원격지 상대방(peer)의 이름(인터페이스어드레스와 포트번호)을
얻는 함수입니다.

int getpeername(
 SOCKET s,
 struct sockaddr FAR* name,
 int FAR* namelen
);

- s
[입력] 사용할 접속된 소켓의 기술자(descriptor)
- name
[출력] 원격지 상대방(peer)의 이름을 받을 SOCKADDR 구조체의 포인터
- namelen
[입/출력] 입력시에는 name에 대한 버퍼 포인터의 최대 크기를 나타내고,출력할 때는 실제로 사용된
버퍼 공간량을 나타내는 정수에 대한 포인터



여기서부터 6단계입니다.

1. 윈도우소켓 초기화.

WSAStartup함수


* 윈속 초기화부분
 ----------------------------------------------------

if(WSAStartup(MAKEWORD(2,2),&wsa) != 0)  // 수업소스부분.
 -----------------------------------------------------
윈속 초기화를 2.2버전으로 초기화시키는부분.

* 원형
int WSAStartup(
  WORD wVersionRequested,
  LPWSADATA lpWSAData
);

성공시 0, 실패 시 SOCKET_ERROR 리턴
  

- wVersionRequested  
프로그램에서 요구하는 윈속의 최상위 버전을 알려주기 위해 사용된다.
상위 8비트 부버전,하위8비트 주버전으로 버전이 3.4이면 3이 주 버전이고 4가 부버전
WORD가 2바이트므로 0x0403을 인자로 넘겨주면된다.
우리가 쓰는 버전은 2.2를 기반으로 하므로 인자를 0x0202를 넘겨주게된다. 그런데 바이트
단위로 쪼개서 원하는 값을 설정하기 번거롭게 느껴지게 되므로 MAKEWORD함수(매크로함수)를
제공받아 쓰면된다.                   
- lpWSAData 
WSADATA타입 변수의 포인터를 인자로 전달한다. WSADATA변수에는 로딩한 DLL값이 채워진다.

1.1 MAKEWORD함수
* 원형
WORD MAKEWORD(
  BYTE bLow,
  BYTE bHigh
);
- MAKEWORD 함수는 매크로 함수로서 원하는 WORD값을 만들어준다.
bLow에는 하위 8비트에 채워질 인자로 전달하고,bHigh에는 상위 8비트에 채워질 인자로 전달.
우리가 요구하는 값은 0x0202이므로 MAKEWORD(2,2)



2.서버 소켓초기화
SOCKET구조체

-----------------------------------------------------
SOCKET listen_sock = socket(AF_INET, sock_STREAM, 0);  // 수업소스부분.
-----------------------------------------------------
listen_sock라는 소켓을 서버에 하나 만들고 AF_INET주소체계, sock_STREAM타입으로 초기화.


여기서 sock_STREAM타입이란?
- 메시지 경계를 유지하지 않는다. 수신 종점은 송신 종점이 write를 몇 번 호출하여 데이터를 전송하였는지 알 수 없고, 수신한 바이트의 스트림에서 언제 write 함수가 시작하고 끝났는지 알 수 없다. 예를 들어 보내는 쪽에서 처음에 25바이트를 보내고 다음으로 30바이트를 보냈다면, 수신측에서는 25바이트를 받고 다음으로 30바이트를 받을 수도 있고, 한번에 55바이트를 받을 수도 있다.
- 데이터는 초기에 쓰여진 순서 그대로 수신된다는 것을 확신할 수 있다. 즉, 보낸쪽에서 순서에 따라 보낸 데이터는 수신측에 순서대로 도착한다.
- 원격 종점은 쓰여진 모든 데이트를 에러 없이 수신한다는 것을 확신할 수 있다. 만약, 실패하는 경우, 에러를 복구할 수 있는 가능한 방법을 모두 시도해본 다음에 에러를 표시한다. 복구 시도는 자동으로 이루어지며, 응용 프로그램이 직접 복구를 시도하지 않는다. 물론, 서버 또는 클라이언트 측의 연결이 끊어진 경우는 응용 프로그램이 재접속 등의 동작을 수행하여야 한다.
- 데이터는 한 쌍의 연결된 소켓간에 전송된다. 즉, 데이터 전송 전에 서버와 클라이언트 측간의 연결이 이루어진 다음에 가능하다.

* 구조체의 원형

int socket(int domain,int type,int protocol);

성공시 소켓 핸들, 실패시 INVALID_SOCKET을 리턴

- domain
생성할 소켓이 통신을 하기위해 사용할 주소 체계를 설정한다.
우리는 주소체계를 사용할려고 AF_INET를 사용하였지만 상황에 따라서 프로토콜체계(PF_INET)를 사용하기도한다.
- type
소켓이 데이터를 전송하는데 있어서, 사용하게 되는 전송 타입을 설정해 준다.
- protocol
두 호스트간에 통신을 하는데 있어서 특정 프로토콜을 지정 하기 위해 사용된다.

3. 서버주소 초기화
SOCKADDR_IN구조체
----------------------------------
SOCKADDR_IN serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons (9000);   // 수업소스부분.
----------------------------------

SOCKADDR_IN 구조체를 serveraddr이름으로 만들어주고 구조체에 주소체계(AF_INET)와
포트(htons (9000))값을 넣우준다.

IPv4의 주소 체계를 나타내는 구조체의 원형
struct sockaddr_in{
  sa_family sin_family;
  uint16_t sin_port;
  struct in_addr sin_addr;
  char sin_zero[8];
};

- sa_family sin_family
주소 체계(address family)
- uint16_t sin_port;
16비트 TCP/UDP Port
- struct in_addr sin_addr;
32비트 IPv4 주소
- char sin_zero[8];
사용되지 않음.


4. bind -주소정보할당하기.(listen_sock 주소 할당)

------------------------------------------------------
retval = bind(listen_sock, (SOCKADDR *) &serveraddr, sizeof(serveraddr));
------------------------------------------------------
listen_sock소켓에 할당하고자 하는 주소정보를 지니고있는 구조체변수의 포인터(serveraddr)를
인자를 주소정보의 길이(serveraddr)만큼 전달.

함수의 원형.

int bind(int sockfd, strcut sockaddr *myaddr, int addrlen);
성공시 1, 실패시 -1리턴.


- sockfd
주소를 할당하고자 하는 소켓의 파일 디스크립터를 인자로 전달한다.
- myaddr
할당하고자 하는 주소 정보를 지니고 있는 sockaddr_in 구조체 변수의 포인터를 인자로 전달한다.
- addrlen
인자로 전달된 주소 정보 구조체의 길이를 전달한다.

5. 연결 요청 대기 상태

--------------------------------------
retval=listen(listen_sock,SOMAXCONN);
--------------------------------------
연결 요청 대기 상태로 들어갈때 서버소켓(listen_sock)과 SOMAXCONN를 인자로 넘긴다.
* SOMAXCONN

win2k server 이상에서는 200까지 인자로 넘길수있다. 그러나 win2k professional 이하에서는
최대 5개까지이다. Accept을 처리하는 데 많은 시간이 걸린다면 backlog가 다 차버린다.
이렇게 되면 더 이상 접속을 할 수 없다(Accept을 처리하면 다시 접속가능)
만약 backlog에 지정한 수 만큼 다 차지 않는 상태에서 한 유저의 accept를 처리하고
있다면 다른 유저가 접속을 하면 서버는 accept도 처리 하지 않은 상황인데 무조건
연결됐다고 나온다. 클라이언트쪽에서는 접속이 성공했다고..
그래서 SOMAXCONN이 OS에서 지원되는 최대값을 가지고 있으므로 SOMAXCONN 인자로 넘긴다.

*원형
int listen(int s,int backlog)
성공시 1, 실패시 -1리턴.

- s
'연결 요청 대기 상태'에서 클라이언트의 연결 요청을 받아들이는 역할을 하게 될 소켓의 파일 디스크립터를
인자로 전달하게 된다. 이 소켓을 서버 소켓이라고 한다.
- backlog
'연결 요청 대기 큐(Queue)'의 크기를 나타낸다. 인자로 5가 들어오면, 큐의 크키가 5가 되어 클라이언트의
요청을 5개까지 대기시킬 수 있게 된다.

6. 연결요청수락

---------------------------------------------------------------------
client_sock = accept(listen_sock,(SOCKADDR *)&clientaddr,&addrlen);
---------------------------------------------------------------------


함수의 원형

int accept(int s,struct sockaddr *addr,int *addrlen);
성공시 소켓 핸들, 실패 시 INVALID_SOCKET

- s
서버 소켓의 파일 디스크립터를 인자로 전달한다.
- addr
연결 요청을 수락할 클라이언트의 주소 정보를 저장할 변수의 포인터이다. 함수 호출이 성공하게 되면
addr이 가리키는 변수에는 클라이언트의 주소 정보로 채워진다.
- addrlen
함수 호출 시 인자로 전달된 addr 포인터가 가리키는 구조체의 크기를 저장하고 있는 변수의 포인터를 넘겨준다.
그러나 함수 호출이 성공적으로 끝나게 되면, addrlen 포인터가 가리키는 변수 안에는 리턴 받은 클라이언트의
주소 정보 길이가 바이트 단위로 채워지게 된다.
 
서버가 사용자를 두명받을수있는 소켓통신을 만듬.(과제)
728x90