accept(2) / accept4(2)

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);

client의 접속 요청을 받아들여 client와 연결합니다. accept(2)함수의 실행결과로 client와 연결을 유지하는 새로운 socket을 생성합니다. accept(2)는 socket(2) 호출시, type이 SOCK_STREAM, SOCK_SEQPACKET과 같은 connection-based socket이어야 합니다. accept4(2) 함수의 parameter flags의 값을 0으로 설정하면 accept( )함수와 기능이 같습니다.

 

 

파라미터

sockfd
    - socket(2)함수를 통하여 생성한 socket descriptor이면서 
      bind(2) 및 listen(2)이 완료된 상태인 socket descriptor입니다.
addr
    - 접속한 client의 주소 정보를 저장합니다. (설정하는 값이 아니라 얻는 값입니다.)
      addr에 NULL을 넘기면, client 주소 정보를 받지 않겠다는 의미입니다.
      이를 이용하여 특정 주소 이외의 접속을 허용하지 않으려면, accept가 return한 socket을 close하면 됩니다.
addrlen
    - addr의 크기를 설정합니다. (INPUT)
    - 접속이 완료되면 실제로 addr에 설정된 접속한 client의 주소 정보의 크기를 저장합니다. (OUTPUT)
    - addr에 NULL을 넘기면 addrlen의 값은 무시됩니다.
flags
    - accept4( ) 함수가 return 하는 새로운 socket descriptor에 socket 속성을 설정합니다.
      속성값은 bit or 연산자( | )를 통하여 설정가능합니다.

 SOCK_NONBLOCK : non-blocking으로 socket을 설정합니다.
 SOCK_CLOEXEC : fork(2) + execl(3)이 발생하면 socket을 close합니다. 
     - 부모 process가 open한 파일(socket 포함)은 fork(2) 시에 그대로 child에 상속되어 open 상태를 유지합니다.
     - execl(3)에 의하여 프로세스의 로직이 다른 프로그램으로 변경되어도 open을 그대로 유지합니다.
     - 이 옵션은 execl(3)을 호출하기 전에 자동으로 socket을 close하는 option입니다.

 

RETURN

-1이 아님
    - client와 연결된 새로운 socket이 생성됩니다.
    - server socket은 socket(2)을 통하여 생성된 socket descriptor와 client와 통신할 수 없으며,
      accept(2)/accept4(2)가 return한 socket을 통하여 client와 데이터를 송수신할 수 있습니다.

-1
    - 오류가 발생하였으며, 오류 내용은 errno에 설정됩니다.
  
    EAGAIN or EWOULDBLOCK : nonblocking 상태로 이번 호출에 client의 접속 요청이 없었습니다.
    EBADF        : sockfd은 open된 descriptor가 아닙니다. (listen이 안됨)
    ECONNABORTED : connection이 종료되었습니다.
    EFAULT       : addr에 사용자가 쓸수 있는 부분이 아닙니다.
    EINTR        : signal이 발생하였습니다.
    EINVAL       : Socket listening 상태ㅏ 아니거나 addrlen이 유효하지 않습니다.
                   accept4()의 flags가 유효하지 않은 값입니다.
    EMFILE       : process당 open할 수 있는 file descriptor 수가 최대치에 도달하여 open할 수 없습니다.
                   또는 시스템에서 open할 수 있는 file descriptor 수가 최대치에 도달하였습니다.
    ENOBUFS, ENOMEM : 할당할 수 있는 memory가 부족합니다.
    ENOTSOCK      : sockfd가 socket이 아닙니다.
    EOPNOTSUPP    : socket의 type은 SOCK_STREAM이 아닙니다.
    EPROTO        : Protocol error.
    EPERM         : 방화벽 문제로 connection을 잃어버렸습니다.

 


활용 예제

 

#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#define SERVER_PORT    6905

int    server_fd;
int    connected_fd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t addr_len;

if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    fprintf(stderr, "socket create error: %s\n", strerror(errno));
    return -1;
}

memset(&server, 0x00, sizeof(struct sockaddr_in));
server.sin_family      = AF_INET;
server.sin_port        = htons(SERVER_PORT);
server.sin_addr.s_addr = INADDR_ANY;

if(bind(server_fd, (const struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) {
    fprintf(stderr, "socket create error: %s\n", strerror(errno));
    return -1;
}

if(listen(server_fd, 20) == -1) {
    fprintf(stderr, "socket create error: %s\n", strerror(errno));
    return -1;
}

if((connected_fd = accept(server_fd, &client, &addr_len)) == -1) {
    fprintf(stderr, "socket create error: %s\n", strerror(errno));
    return -1;   
}

...

 


see also : Socket 통신과 Socket 응용

 

 

 

 

블로그 이미지

자연&사람

행복한 개발자 programmer since 1995.

댓글을 달아 주세요