서버쪽 함수

1. socket() 함수를 이용해 생성
2. bind() 함수를 이용해 지역IP 와 지역 포트 번호 결정
3. listen() 함수를 이용해 TCP상태를 LISTENING 상태로 변경
4. accpet() 함수를 이용해 접속한 클라이언트와 통신할 수 있는 새로운 소켓을 생성. 이때 원격IP주소와 포트번호 결정됨
5. send(), recv() 등의 함수를 이용해 통신을 수행,
6. closesocket() 함수를 이용해 소켓을 종료한다.

새로운 클라이언트가 접속시 4~6의 과정을 반복한다.

1. bind()
int bind(
SOCKET s,
const struct sockaddr* name,
int namelen
);

SOCKET s,
- 클라이언트 접속을 수용할 목적으로 만든 소켓이며, 지역 IP주소와 포트번호가 아직 결정되지 않는다.

const struct sockaddr* name,
- 소켓 주소 구조체(TCP일 경우 SOCKADDR_IN 타입) 변수를 지역 IP주소와 지역 포트 번호로 초기화 후,
이 변수의 주소값을 여기에 대입한다.

int namelen
- 소켓 주소 구조체 변수의 길이(바이트) 를 대입한다.

예문)

SOCKADDR_IN serveraddr;
 ZeroMemory(&serveraddr, sizeof(serveraddr));
 serveraddr.sin_family = AF_INET;
 serveraddr.sin_port = htons(9000);
 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 retval = bind(listen_sock, (SOCKADDR *) &serveraddr, sizeof(serveraddr));
 if(retval == SOCKET_ERROR ) err_quit("bind()");

// 소켓 주소 구조체 변수를 선언후에 0으로 초기화한다. ZeroMemory() (API 함수) 또는 memset()을 이용한다.
// 인터넷 주소 체계를 사용한다는 의미로 AF_INET을 대입한다.
// 포트 번호를 9000번으로 설정하며, htons() 함수로 바이트 정렬을 변경한 값을 대입한다.
// 서버의 지역 IP 주소를 설정한다. 서버의 경우 특정 IP 주소보다는 INADDR_ANY 값을 사용하는 것이 바람직하다.
// 서버가 2개 이상일 경우 INADDR_ANY 값을 지역 주소로 설정하면 클라이언트가 어느 주소로 접속하든 처리 가능하다.
// bind() 함수를 호출하고, 두번째 인자는 항상 (SOCKADDR*) 타입으로 반환해야 한다.



2. listen() 함수
int listen(
SOCKET s,
int backlog
);

SOCKET s,
- 클라이언트 접속을 수용할 목적으로 만든 소켓으로, bind() 함수에 의해 지역 IP 주소와 지역 포트 번호가 설정된 상태이다.

int backlog
- 서버가 당장 처리하지 않더라도 접속 가능한 클라이언트의 수다. 클라이언트의 접속 정보는 연결 큐에 저장되며,
backlog 는 이 연결 큐의 길이를 나타낸다고 보면 된다. 하부 프로토콜에서 지원 가능한 최대값을 사용시 SOMAXCONN 대입.


3. accept() 함수
- 서버에 접속한 클라이언트와 통신할 수 있도록 새로운 소켓을 생성 후, 리턴하는 역활을 한다.
또한 접속한 클라이언트의 IP 주소와 포트 번호를 알려준다. 클라이언트 입장에서는 지역 IP 주소와 포트번호.
SOCKET accept(
SOCKET s,
struct sockaddr* addr,
int* addrlen
);

SOCKET s,
- 클라이언트 접속을 수용할 목적의 소켓

struct sockaddr* addr,
- 소켓 주소 구조체 변수를 정의한 후, 이 변수의 주소값을 여기에 대입한다.
- accpet() 함수는 addr이 가리키는 메모리 영역을 클라이언트의 IP 주소와 포트 번호로 채워 넣는다.

int* addrlen
- 정수형 변수를 addr이 가리키는 메모리 영역의 크기로 초기화한 후, 이 변수의 주소값을 여기에 대입한다.
accept() 함수가 리턴하면 정수형 변수는 addrlen은 함수가 초기화한 메모리 크기값(바이트) 을 가진다.

// 클라이언트의 IP 주소와 포트 번호를 알 필요가 없다면 addr과 addrlen에 NULL을 사용하면 된다.


사용예)

//데이터 통신에 사용할 변수
 SOCKET client_sock;[각주:1]
 SOCKADDR_IN clientaddr;[각주:2]
 int addrlen;[각주:3]
 char buf[BUFSIZE+1];
 
 while(1)[각주:4]
 {
  //accept
  addrlen = sizeof(clientaddr);[각주:5]
  client_sock = accept(listen_sock, (SOCKADDR*) &clientaddr , &addrlen);[각주:6]
  if(client_sock == INVALID_SOCKET )
  {
   err_display("accpet()");
   continue;
  }
  printf("\n[TCP 서버] 클라이언트 접속 : IP 주소 : %s, 포트번호 : %d\n",
    inet_ntoa(clientaddr.sin_addr),
    ntohs(clientaddr.sin_port ));
    


 while(1)
 {
//클라와 데이터 통신[footnote][/footnote]
 }
 
closesocket(client_sock);
printf("\n[TCP Server] 클라이언트 종료 : IP 주소 : %s , 포트번호 : %d\n",
   inet_ntoa(clientaddr.sin_addr),
   ntohs(clientaddr.sin_port ));
}




  1. accept() 함수의 리턴값을 저장할 SOCKET 타입 변수다. [본문으로]
  2. accpet() 함수의 두 번째 인자로 사용되며 accept() 함수 리턴 후 클라이언트의 IP 주소와 포트 번호가 여기에 저장된다. [본문으로]
  3. accept() 함수의 세번째 인자로 사용된다. [본문으로]
  4. 일반적으로 서버는 계속클라이언트 요청을 처리해야 하므로 무한 루프를 돈다. [본문으로]
  5. accept() 함수를 호출하기 전에, 세 번째 인자로 사용할 정수형 변수 addrlen을 소켓 주소 구조체 변수(clientaddr)의 크기로 초기화한다. [본문으로]
  6. accept() 함수를 호출하고 오류 처리를 한다. 이전에 사용한 소켓 함수와 달리 오류가 발생시 err_display() 함수를 이용해 화면에 표시한 후, 다시 돌아간다. 심각한 오류가 아니면 이와 같이 서버를 계속 구동하는 것이 바람직하다. [본문으로]

'Windows > Network Programming' 카테고리의 다른 글

send(), recv() 사용 분석  (0) 2011.07.16
데이터 전송 함수 및 소켓 데이터 구조체  (0) 2011.07.16
TCP Client 분석  (0) 2011.07.15
TCP Server / Client  (0) 2011.07.15

+ Recent posts