C에서 소켓 열기

Jinku Hu 2023년10월12일
C에서 소켓 열기

이 기사에서는 C에서 소켓을 여는 방법에 대한 몇 가지 방법을 설명합니다.

listenaccept함수를 사용하여 C에서 소켓 열기

listenaccept는 프로세스 간 통신을 처리하는 핵심 기능을 구현하는 소켓 API라고도하는 UNIX 네트워킹 기능의 일부입니다. 소켓은 통신 경로에 대한 끝점의 추상적 인 표현입니다. 예를 들어 Unix 도메인과 인터넷 도메인과 같은 다양한 유형의 소켓이 있지만 모두 두 프로세스 간의 통신을 설정하는 유사한 절차를 따릅니다.

네트워킹은 실행중인 두 프로그램 간의 통신 일뿐입니다. 처음에는socket함수가 호출되어 엔드 포인트와 해당 핸들을 생성합니다. 소켓은 UNIX 시스템의 일반 파일 또는 파이프와 유사한 파일 설명 자로 처리됩니다. socket호출 후 개발중인 프로그램의 종류에 따라 두 가지 시나리오가 있습니다. 일반적으로 우리는 네트워크 통신에서 클라이언트-서버 모델을 가지고 있는데, 하나의 프로그램 (서버)은 다른 프로그램 (클라이언트)이 연결할 때까지 기다려야합니다.

이 예에서는 특정 엔드 포인트를 수신하고 클라이언트 연결을 수락해야하는 서버 측 프로그램을 구현합니다. 이 시나리오에서bind함수는socket다음에 호출되어 프로그램이 들어오는 연결을 수락 할 특정 주소에 바인드합니다. bind후에listenaccept함수가 호출되어 소위 수동 소켓을 형성합니다. accept는 다른 프로세스가connect함수 호출을 사용하여 연결을 설정하지 않을 때까지 프로세스를 차단합니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define handle_error(msg) \
  do {                    \
    perror(msg);          \
    exit(EXIT_FAILURE);   \
  } while (0)

#define SOCKET_PATH "/tmp/my.sock"

enum { LISTEN_QUEUE = 100 };

int main(int argc, char *argv[]) {
  int listenfd, connfd;
  socklen_t len;
  struct sockaddr_un servaddr, cliaddr;

  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (listenfd == -1) handle_error("socket");

  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sun_family = AF_UNIX;
  strncpy(servaddr.sun_path, SOCKET_PATH, sizeof(servaddr.sun_path) - 1);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    handle_error("bind");

  if (listen(listenfd, LISTEN_QUEUE) == -1) handle_error("listen");

  len = sizeof(cliaddr);
  connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
  if (connfd == -1) handle_error("accept");

  unlink(SOCKET_PATH);
  exit(EXIT_SUCCESS);
}

일반적으로accept호출 다음에는 수신 연결 처리를 구현하는 코드가옵니다. 이 서버와의 연결을 설정하려는 외부 프로그램은 주소와 포트를 알아야합니다. 둘 다 프로세스에 알려져 있다고 가정하면socket호출 후에connect함수를 호출하고 서버 프로세스에 연결되기를 바랍니다. 연결이 설정되면 두 프로세스 모두 양방향 채널이있는 것으로 소켓 설명자에서 쓰고 읽을 수 있습니다. 실제 시나리오에서는 여러 클라이언트 프로세스가 서버에 동시에 연결되어야합니다. 연결 처리 코드는 동시에 구현되어야합니다. 그렇지 않으면 서버가 한 번에 둘 이상의 클라이언트에 서비스를 제공 할 수 없습니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define handle_error(msg) \
  do {                    \
    perror(msg);          \
    exit(EXIT_FAILURE);   \
  } while (0)

#define SOCKET_PATH "/tmp/my.sock"

enum { MAXLINE = 4096, LISTEN_QUEUE = 100 };

int main(int argc, char *argv[]) {
  int listenfd, connfd;
  socklen_t len;
  struct sockaddr_un servaddr, cliaddr;
  char buf[MAXLINE];

  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (listenfd == -1) handle_error("socket");

  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sun_family = AF_UNIX;
  strncpy(servaddr.sun_path, SOCKET_PATH, sizeof(servaddr.sun_path) - 1);

  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    handle_error("bind");

  if (listen(listenfd, LISTEN_QUEUE) == -1) handle_error("listen");

  len = sizeof(cliaddr);
  connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
  if (connfd == -1) handle_error("accept");

  size_t ret = read(connfd, buf, MAXLINE);
  if (ret == -1) handle_error("read");

  printf("read %d bytes\nmessage: %s\n", connfd, buf);

  unlink(SOCKET_PATH);
  exit(EXIT_SUCCESS);
}
작가: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

관련 문장 - C Networking