bind 함수 호출을 통해 소켓에 주소를 할당했다면 listen 함수를 통해 ‘연결 요청 대기 상태’로 들어가야 함
#include <sys/type.h>
int listen(int s, int backlog);
// s : '연결 요청 대기 상태'에서 클라이언트의 연결 요청을 받아들이는 역할을 하게 될 소켓의
// 파일 디스크립터를 인자로 전달하게 됨 -> 이 소켓을 서버 소켓이라고 함
// backlog : 연결 요청 대기 큐의 크기를 나타냄
// 인자로 5가 들어오면 큐의 크기가 5가 되어 클라이언트의 연결 요청을 5개까지 대기시킬 수 있게 됨
서버가 연결 요청 대기 상태에 있다는 것은 클라이언트가 연결 요청을 했을 때 연결이 수락될 때까지 연결 요청 자체를 대기시킬 수 있는 상태에 있다는 것을 의미
클라이언트 연결 요청도 인터넷을 통해 흘러 들어오는 일종의 데이터 전송이기 때문에 이것을 받아들이기 위한 소켓이 필요함 → 서버 소켓
⇒ 즉, listen 함수가 호출되면 문지기 역할을 하는 서버 소켓을 만들어 주고, 두 번재로 정달되는 정수를 참조해서 대기실(연결 요청 대기 큐)을 만듬
대기 큐와 서버 소켓이 준비되어서 클라이언트 연결 요청을 받아들일 수 있는 상태를 ‘연결 요청 대기 상태’라고 함
대기 큐에 들어 있는 연결 요청을 순서대로 수락해야 함
수락한다는 것은 요청한 클라이언트와 데이터를 주고 받을 수 있는 상태가 되는 것을 의미
→ 당연히 소켓이 필요함
#include <sys/types.h>
#include <sys/socket.h>
int accept(int s, struct sockaddr* addr, int* addrlen);
// 성공 시 소켓의 새로 생성된 파일 디스크립터를 실패 시 -1 리턴
// s : 서버 소켓의 파일 디스크립터를 인자로 전달
// addr : 연결 요청을 수락할 클라이언트 주소 정보를 저장할 변수의 포인터임
// 함수 호출이 성공하게 되면 addr이 가리키는 변수에는 클라이언트의 주소 정보로 채워지게 됨
// addrlen : 함수 호출 시 인자로 전달된 addr 포인터가 가리키는 구조체의 크기를 저장하고 있는
// 변수의 포인터를 넘겨줌
// 함수 호출이 성공적으로 끝나게 되면 addrlen 포인터가 가리키는 변수 안에는 리턴 받은
// 클라이언트의 주소 정보 길이가 바이트 단위로 채워지게 됨
accept 함수는 호출 성공 시 내부적으로 클라이언트와의 데이터 입/출력을 하기 위해 사용될 소켓을 생성하고, 그 소켓의 파일 디스크립터를 리턴해 줌 (소켓을 알아서 생성해줌!!)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
void error_handling(char* message);
int main(int argc, char** argv)
{
int serv_sock;
int clnt_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
int clnt_addr_size;
char message[]="Hello World!\n";
if(argc!=2)
{
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
serv_sock=socket(PF_INET, SOCK_STREAM, 0); // 서버 소켓 생성
if(serv_sock == -1)
error_handling("socket() error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*) &serv_addr,
sizeof(serv_addr)) == -1) // 소켓에 주소 할당
error_handling("bind() error");
if(listen(serv_sock, 5) == -1) // 연결 요청 대기 상태로 진입
error_handling("listen() error");
clnt_addr_size = sizeof(clnt_addr);
// 연결 요청 수락
clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);
if(clnt_sock == -1)
error_handling("accept() error");
// 데이터 전송
write(clnt_sock, message, sizeof(message));
close(clnt_sock); // 연결 종료
return 0;
}
void error_handling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}