c socket 예제

여러 예제를 보고 따라하면서 많은 이해가 됐다.

sockaddr 구조체와 sockaddr_in 구조체는 크기가 같다는 것이 인상깊었다.

아래는 작성한 예제

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

int main () {
    int ret;

    pid_t pid = fork();
    /* client */
    if (pid == 0) {
        sleep(1);
        /* create client socket */
        int client_sockfd;
        client_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (client_sockfd == -1) { perror("[C] socket"); return -1; }
        printf("[C] socket\n");

        /* set client_sockaddr */
        struct sockaddr_in client_sockaddr;
        memset(&client_sockaddr, 0, sizeof(struct sockaddr_in));
        client_sockaddr.sin_family      = AF_INET;
        client_sockaddr.sin_port        = htons(4000);
        inet_pton(AF_INET, "127.0.0.1", &client_sockaddr.sin_addr.s_addr);

        /* connect */
        printf("[C] connect\n");
        ret = connect(client_sockfd, (struct sockaddr *)&client_sockaddr, sizeof(struct sockaddr_in));
        if (ret == -1) { perror("[C] connect"); return -1; }

        /* send */
        printf("[C] send\n");
        int writelen;
        writelen = send(client_sockfd, "hello, world!", strlen("hello, world!"), 0);

        /* recv */
        char buf[512];
        int readlen;
        readlen = recv(client_sockfd, buf, 512, 0);
        if (readlen < 1) { perror("[C] recv"); return -1; }
        printf("[C] recv\n");
        printf("[C] buf \"%s\"\n", buf);

        close(client_sockfd);
    }
    /* server */
    else {
        /* create socket socket */
        int server_sockfd;
        server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (server_sockfd == -1) { perror("[S] socket"); return -1; }
        printf("[S] socket\n");

        /* set server_sockaddr */
        struct sockaddr_in server_sockaddr;
        memset(&server_sockaddr, 0, sizeof(struct sockaddr_in));
        server_sockaddr.sin_family      = AF_INET;
        server_sockaddr.sin_port        = htons(4000);
        server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

        /* bind */
        ret = bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr_in));
        if (ret == -1) { perror("[S] bind"); return -1; }
        printf("[S] bind\n");

        /* listen */
        ret = listen(server_sockfd, 5);
        if (ret == -1) { perror("[S] listen"); return -1; }
        printf("[S] listen\n");

        /* loop */
        int client_sockfd;
        struct sockaddr_in client_sockaddr;
        int socklen, readlen, writelen;
        char buf[512];
        /* for (;;) { */
            /* accept */
            memset(&client_sockaddr, 0, sizeof(struct sockaddr_in));
            socklen = sizeof(struct sockaddr_in);
            client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_sockaddr, &socklen);
            if (client_sockfd == -1) { perror("[S] accept"); return -1; }
            printf("[S] accept\n");

            /* recv */
            readlen = recv(client_sockfd, buf, 512, 0);
            if (readlen == -1) { perror("[S] recv"); return -1; }
            printf("[S] recv\n");
            printf("[S] buf \"%s\"\n", buf);

            /* send */
            printf("[S] send\n");
            writelen = send(client_sockfd, buf, readlen, 0);

            /* close socket */
            close(client_sockfd);
        /* } */

        /* close server */
        close(server_sockfd);

        wait(&ret);
    }

    return 0;
}

실행 하면 이렇게 나온다.

$ ./socket
[S] socket
[S] bind
[S] listen
[C] socket
[C] connect
[C] send
[S] accept
[S] recv
[S] buf "hello, world!"
[S] send
[C] recv
[C] buf "hello, world!"
$

[*] 더 공부해야할 것.

bindlisten은 정확히 무슨 역할을 할까?

readwrite로 통신하는 것과 sendrecv로 통신하는 것은 무슨 장단점이 있을까?

aio로 동시접속을 제어하는 서버 구현하기

온르은 일찍 자야지ㅎ