소켓(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로 생성한 소켓
공부하면서 학습 목적으로 작성한 포스팅이므로 내용이 완전하지 않습니다ㅠ
계속해서 학습 후 지식이 좀 더 쌓이면 수시로 수정해나갈 예정입니다!
틀린 내용은 둥글게 댓글 달아주시면 빠른 확인 후 수정하겠습니다. :)
참고
'열심히 살기 > Network' 카테고리의 다른 글
소켓 프로그래밍 - TCP 기반(서버, 클라이언트) (6) | 2020.12.12 |
---|---|
소켓 프로그래밍 - 바이트 순서(호스트, 네트워크) (0) | 2020.12.12 |
소켓 프로그래밍 - 연결지향형 소켓(TCP 소켓) (0) | 2020.12.12 |
소켓 프로그래밍 - 파일 디스크립터 (0) | 2020.12.12 |
소켓 프로그래밍 - 코드실행(서버, 클라이언트) (0) | 2020.12.11 |
댓글