본문 바로가기
열심히 살기/Network

소켓 프로그래밍(Socket Programming)

by yeni03o_o 2020. 12. 11.

소켓(Socket)

- 네트워크 환경에 연결할 수 있도록 만들어진 연결부

  → 소켓을 사용하여 네트워크 통신 기능 구현

 

 

소켓 API (시스템 콜 호출) 흐름

※ 클라이언트 소켓(연결 요청): socket() → connect() → send/recv() → close()

  클라이언트 소켓 생성: socket()

// 소켓 생성 성공 시 파일디스크립터, 실패 시 -1 반환
int socket(int domain, int type, int protocol);
// domain: 생성할 소켓이 통신을 하기 위해 사용할 프로토콜 체계 설정
// type: 소켓의 데이터 전송 타입
// protocol: 특정 프로토콜 지정

 

 * 프로토콜 체계    

이름 프로토콜 체계(Protocol Family)
PF_INET IPv4 인터넷 프로토콜 체계
PF_INET6 IPv6 인터넷 프로토콜 체계
PF_LOCAL 로컬 통신을 위한 UNIX 프로토콜 체계
PF_PACKET Low Level 소켓을위한 프로토콜 체계
PF_IPX IPX 노벨 프로토콜 체계

 * 소켓 타입(프로토콜 PF_INET)

   - 연결지향형 소켓: SOCK_STREAM

                           순서대로 데이터 수신, 중간에 데이터 소멸 X, 데이터의 경계 존재 X

                           1:1구조로 소켓 vs 소켓 연결

   - 비연결지향형 소켓: SOCK_DGRAM

                              빠른 속도의 전송 지향 → 데이터 손실 및 변형 가능

                              데이터의 경계 존재, 한번에 전송할 수 있는 데이터 크기 제한

 * 프로토콜 지정

int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);		//TCP 소켓
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);		//UDP 소켓

# domain과 type인자로 소켓의 프로토콜이 결정되므로 protocol인자로 0을 전달해도 됨

 

  ② 연결 요청: connect()

      - Target(IP와 포트번호로 식별)에게 연결 요청 전송

      - Block 방식으로 동작하므로 연결 요청에 대한 결과(성공, 거절, 시간 초과 등)가 결정되기 전에는 종료되지 않음

// 연결 성공 시 0, 실패 시 -1 반환
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);
// sockfd: 클라이언트 소켓의 파일디스크립터
// *serv_addr: 연결 요청을 보낼 서버의 주소 정보를 지닌 변수의 주소 값
// addrlen: serv_addr 포인터가 가리키는 주소 정보 구조체 변수의 크기

 

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

    - Block 방식으로 동작하므로 실행 결과(성공, 실패, 종료)가 결정되기 전에는 리턴되지 않음 

       → recv() API는 수신 및 에러 발생 전에는 실행이 종료되지 않으므로 별도의 스레드에서 실행

  ④ 소켓 닫기: close()

    - close()에 의해 닫힌 소켓은 데이터 송수신 불가

 

※ 서버 소켓(연결 요청 허용): socket() → bind() → listen() → accept() → send/recv() → close()

  ① 서버 소켓 생성: socket()

// 소켓 생성 성공 시 파일디스크립터, 실패 시 -1 반환
int socket(int domain, int type, int protocol);
// domain: 생성할 소켓이 통신을 하기 위해 사용할 프로토콜 체계 설정
// type: 소켓의 데이터 전송 타입
// protocol: 특정 프로토콜 지정

 

  ② 서버 소켓 바인딩: bind()

    - 서버가 사용할 주소 정보(IP, 포트번호)를 소켓에 결합

      → bind() API는 운영체제에게 해당 소켓이 지정된 포트번호를 사용할 것을 요청

// 포트 번호 바인딩 성공 시 0, 실패 시 -1 반환
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
// sockfd: 주소를 할당하고자 하는 소켓의 파일디스크립터
// *myaddr: 할당하고자 하는 주소 정보를 지니고있는 sockaddr 구조체 변수의 포인터 인자 값
// addrlen: 인자로 전달된 주소 정보 구조체 길이

 

  ③ 클라이언트 연결 요청 수신 대기: listen()

    - 바인딩된 포트 번호로 클라이언트의 연결 요청(connect() API) 대기

    - 연결 요청이 수신되거나 에러가 발생하면 대기 상태 종료 후 리턴

    - 클라이언트 연결 요청 정보는 큐에 쌓임

      → 클라이언트와 완전히 연결되지 않은 not ESTABLISHED 상태

// 클라이언트 연결 요청 수신 시 0, 실패 시 -1 반환
int listen(int sockfd, int backlog);
// sockfd: 클라이언트로부터 연결 요청을 받아들이기 위한 소켓 파일디스크립터
//	   이 함수의 인자로 전달된 디스크립터의 소켓이 서버 소켓(리스닝 소켓)이 됨
// backlog: 연결요청 대기 큐의 크기 설정
//	    큐의 크기가 n이라면 클라이언트의 연결요청을 n개까지 대기시킬 수 있음

 

  ④ 연결 수립: accept()

    - 데이터 송수신을 위한 새로운 소켓을 만들고, 서버 소켓의 대기 큐에 쌓여있는 첫 번째 연결 요청 매핑

// 연결 수립 성공 시 파일디스크립터, 실패 시 -1 반환
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// sockfd: 서버 소켓의 파일디스크립터
// *addr: 연결 요청을 수락 할 클라이언트의 주소 정보를 담고있는 변수의 주소 값
//	  함수 호출이 완료되면 클라이언트의 주소정보가 채워짐
// *addrlen: addr이 가리키는 구조체의 크기를 저장하고 있는 변수의 주소 값
//	    함수 호출이 완료되면 클라이언트의 주소정보 길이가 바이트 단위로 계산되어 채워짐

 

  ⑤ 연결 수립 시 데이터 송수신: send/recv()

  ⑥ 소켓 닫기: close()

    - close() API 대상: socket() API로 생성한 소켓, accept() API로 생성한 소켓

 

 

공부하면서 학습 목적으로 작성한 포스팅이므로 내용이 완전하지 않습니다ㅠ 
계속해서 학습 후 지식이 좀 더 쌓이면 수시로 수정해나갈 예정입니다! 
틀린 내용은 둥글게 댓글 달아주시면 빠른 확인 후 수정하겠습니다. :)


참고

* recipes4dev.tistory.com/153

* mang-geun.tistory.com/entry/011-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EA%B3%BC-%EC%86%8C%EC%BC%93%EC%9D%98-%EC%9D%B4%ED%95%B4

* mintnlatte.tistory.com/

 

 

 

댓글