• Socket은 커널에 구현된 프로토콜 요소의 추상화된 인터페이스
  • 장치 파일의 일종
  • 연결을 끊을 때는 Client가 끊도록 하는 것이 바람직

전체 흐름

Server(서버 소켓 + 통신 소켓)

socket() : 소켓 생성

bind() : ip 주소 및 포트를 socket에 묶음(binding)

listen() : client로부터의 연결을 대기

accept() : client로부터의 연결 요청에 응답

recv() / send() : 데이터 송수신

Client(통신 소켓)

socket() : 소켓 생성

connect() : server로 연결 요청

recv() / send() : 데이터 송수신

API

Socket

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
  • domain
    • AF_UNIX
    • AF_LOCAL
    • AF_INET : ipv4
    • AF_INET6 : ipv6
  • type
    • SOCK_STREAM : tcp
    • SOCK_DGRAM : udp
  • protocol
  • return
    • -1 : error
    • 0 : success

Bind

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd : 소켓 식별자 또는 디스크립터(서버)
  • addr : ip 정보가 담겨있는 구조체
  • addrlen : 구조체 크기
  • return
    • 0 : success
    • -1 : error

Listen

#include <sys/socket.h>

int listen(int sock, int backlog);
  • sock : 대기 상태에 두고자 하는 소켓 식별자 또는 디스크립터(서버)
  • backlog : 연결요청 대기 큐(queue)의 크기
  • return
    • 0 : success
    • -1 : error

Accept

#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, sockelnt_t *addrlen);
  • sockfd : 서버
  • addr : 클라이언트 ip 정보가 담긴 구조체
  • addrlen : 구조체 크기
  • return
    • -1 : error
    • 나머지 : 서버에서 통신할 소켓 디스크립터

Connect

#include <sys/types.h>
#include <sys/socket.h>

int connect(int socket, const struct sockaddr *address, socklent_t address_len);
  • socket : 클라이언트
  • address : 서버의 주소 정보가 담긴 구조체
  • address_len : 구조체 크기
  • return
    • -1 : error
    • 0 : success

Send

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd : 통신할 소켓 디스크립터
  • buf : 보낼 메세지가 담긴 버퍼
  • len : buffer의 크기
  • flags : 전송 옵션
  • return
    • -1 : error
    • 나머지 : 보낸 바이트 크기

Recv

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv(int sockfd, void* buf, size_t len, int flags);
  • sockfd : 통신할 소켓 디스크립터
  • buf : 받은 메세지를 담을 버퍼
  • len : 받아올 크기
  • flags : 수신 옵션
  • return
    • -1 : error
    • 나머지 : 받은 바이트 크기

Example

Server

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <pthread.h>
#include <signal.h>

#define BUFF_SIZE 1024
#define FILE_PATH "./test"
#define Error() perror("Error: ");\
                return -1;

void* send_msg(void* c_fd) {
        char s_buff[BUFF_SIZE];

        while (1)
        {
                printf("You: ");
                fgets(s_buff, BUFF_SIZE, stdin);
                if (!write(*(int*)c_fd, s_buff, BUFF_SIZE))
                {
                        perror("Error: send message");
                }
        }
}

int main(void) {
        int s_fd, c_fd, c_addr_size;
        struct sockaddr_un s_addr, c_addr;
        char c_buff[BUFF_SIZE];
        sigset_t sigset;
        pthread_t send_thread;

        if (!access(FILE_PATH, F_OK))
                unlink(FILE_PATH);

        s_fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (s_fd == -1)
        {
                Error();
        }

        memset(&s_addr, 0, sizeof(s_addr));
        s_addr.sun_family = AF_UNIX;
        strcpy(s_addr.sun_path, FILE_PATH);
        if (bind(s_fd, (struct sockaddr*)&s_addr, sizeof(s_addr)) == -1)
        {
                close(s_fd);
                Error();
        }

        if (listen(s_fd, 5) == -1)
        {
                close(s_fd);
                Error();
        }
        printf("Listening...\n");

        c_addr_size = sizeof(c_addr);
        c_fd = accept(s_fd, (struct sockaddr*)&c_addr, &c_addr_size);
        if (c_fd == -1)
        {
                close(s_fd);
                Error();
        }
        printf("Accept!\n");

        sigemptyset(&sigset);
        sigaddset(&sigset, SIGINT);
        sigprocmask(SIG_BLOCK, &sigset, (sigset_t*)NULL);
        pthread_create(&send_thread, NULL, send_msg, (void*)&c_fd);
        while (read(c_fd, c_buff, BUFF_SIZE))
        {
                printf("\nClient said : %s", c_buff);

                if (!strcmp(c_buff, "bye\n"))
                        break;
        }
        if (shutdown(c_fd, SHUT_RDWR) == -1)
        {
                Error();
        }
        close(c_fd);
        close(s_fd);
}

Client

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

#define BUFF_SIZE 1024
#define FILE_PATH "./test"
#define Error() perror("Error: ");\
                return -1;

void* read_msg(void* c_fd) {
        char s_buff[BUFF_SIZE];

        while (1)
        {
                read(*(int*)c_fd, s_buff, BUFF_SIZE);
                printf("\nServer said: %s", s_buff);
        }
}

int main(void) {
        int c_fd;
        struct sockaddr_un s_addr;
        char c_buff[BUFF_SIZE];
        pthread_t read_thread;

        c_fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (c_fd == -1)
        {
                Error();
        }

        memset(&s_addr, 0, sizeof(s_addr));
        s_addr.sun_family = AF_UNIX;
        strcpy(s_addr.sun_path, FILE_PATH);
        if (connect(c_fd, (struct sockaddr*)&s_addr, sizeof(s_addr)) == -1)
        {
                close(c_fd);
                Error();
        }
        puts("Connected!");

        pthread_create(&read_thread, NULL, read_msg, (void*)&c_fd);
        while (1)
        {
                printf("You: ");
                fgets(c_buff, BUFF_SIZE, stdin);
                if (!write(c_fd, c_buff, BUFF_SIZE))
                {
                        perror("Error: send message");
                }

                if (!strcmp(c_buff, "bye\n")) break;
        }
        if (shutdown(c_fd, SHUT_RDWR) == -1)
        {
                Error();
        }
        close(c_fd);
}

'💻 Computer Science > System' 카테고리의 다른 글

[System] Semaphore  (1) 2024.01.26
[System] Shared Memory  (1) 2024.01.26
[System] Named Pipe  (1) 2024.01.26
[System] 메모리 맵핑  (1) 2024.01.26
[System] 시그널  (1) 2024.01.25