[C] 네트워크 소켓

ss9909·2022년 10월 13일
0

C

목록 보기
1/1

소켓의 정의

TCP를 유저모드 어플리케이션 프로세스가 접근할 수 있도록 파일 형식으로 추상화 한 인터페이스가 소켓이다.

계층식별자
TransportPORT
NetworkIP
DataMAC Adress

네트워크 소켓 프로그래밍

Want to doDo it
소켓 생성socket 함수 호출
IP, PORT 번호 할당bind 함수 호출
연결 요청 가능한 상태로 변경listen 함수 호출
연결 요청에 대한 수락accept 함수 호출
연결을 요청connect 함수 호출

네트워크를 통한 데이터 전달은 전화기에 비유해서 설명하면 좀 더 쉽게 이해할 수 있는 측면이 있다. 실제로도 음성데이터를 주고 받는다는 점에서 더더욱 네트워크와 비슷한 면모가 존재한다.

서버 측 소켓은 전화를 받는 전화기에 비유해서 생각해볼 수 있다.

서버측 소켓 생성

  1. 전화를 받으려면 전화기가 있어야 한다.
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
// 성공 시 FD(File Descriptor) 반환
// 실패 시 -1 반환

socket()함수를 통해 파일로 추상화된 TCP를 코드단으로 처리할 수 있게 한다.

IP,PORT번호 할당

  1. 전화기가 있다고 전화를 할 수 있는 게 아니다. 전화번호를 받아야 한다.
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
// 성공 시 0 반환
// 실패 시 -1 반환

bind() 함수 호출을 통해 소켓에 포트를 할당했다. 전화번호가 생긴 셈이다.
코드단에서 네트워크 계층의 IP와 전송 계층의 PORT번호를 지정한다.

연결 가능한 상태로 변경

  1. 전화기의 플러그를 꽂아 전화 연결이 가능한 상태로 만들어 줄 것
#include <sys/socket.h>
int listen(int sockfd, int backlog);
// 성공 시 0 반환
// 실패 시 -1 반환

listen()함수를 통해 소켓을 연결 가능한 상태로 변환

연결 요청에 대한 수락

  1. 전화벨이 울리면 수화기를 들어 전화를 받는다.
#include <sys/socket.h>
int accept(int sockfc, struct sockaddr *addr socklen_t *addrlen);
// 성공 시 FD(File Discriptor) 반환
// 실패 시 -1 반환

소켓에 데이터 송수신 요청이 들어오면 accept함수를 통해 그 요청을 수락한다.
TCP/IP로 들어온 요청이 file로 추상화 되어 코드단에서 처리가 가능해진다.

기본 Server 구현

#include <stdio.h>
#include <stdilib.h>
#include <unistd.h>
#include <arpa/inet.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;
  socklen_t clnt_addr_size;

  char message[] = "hi!";

  if(arc!=2)
  {
    printf("Usage : %s <port>\n", argv[0]);
    exit(1);

    serv_sock=socket(PF_INET, SOCK_STREAM, 0);  // 1. 소켓을 생성하고 FD 반환
    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 = hotns(atoi(argv[1]));
  
    if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1) // 2. bind 함수를 통해 IP, PORT번호 할당
      error_handling("bind() error");
    
    if(listen(serv_sock, 5)==-1)        // 3. listen 함수를 통해 소켓이 연결 요청을 받을 수 있는 상태로 변환
      error_handling("listen() error");


    clnt_addr_size = sizeof(clnt_addr);
    // accept 함수가 호출되면 연결 요청이 있을 때까지 함수를 반환하지 않는다.
    clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); // 4. accept함수를 통해 연결요청을 수락
    if(clnt_sock==-1)
      error_handling("accept() error");

    write(cln_sock, message, sizeof(message));
    close(clnt_sock);
    close(serv_sock);
    return 0;
}

void error_handling(char * message)
{
  fputs(message,stderr);
  fputc('\n', stderr);
  exit(1)
}

클라이언트 소켓

클라이언트 측 소켓을 전화를 거는 측 전화기에 비유해서 생각해 볼 수 있다.
1. 전화를 걸려면 전화기가 있어야 한다. socket()함수를 통해 file로 TCP/IP 추상화
(서버측과 같으므로 생략)

서버측 소켓에 연결 요청

  1. 전화를 건다.
#include <sys/socket.h>
int connect(int sockfd, struc sockaddr *serv)addr, socklen_t addrlen);
// 성공 시 0 반환
// 실패 시 -1 반환

connect() 함수를 통해 서버 측 소켓에 연결한다.

profile
이름 짓는 게 어려운 사람

0개의 댓글