1. 소켓의 사전적 정의

전기 공급 인프라 환경에 연결할 수 있게 만들어진 연결부
2. 네트워크 프로그래밍에서의 소켓

프로그램이 네트워크에서 데이터를 송수신할 수 있도록 네트워크 환경에 연결할 수 있게 만들어진 연결부
3. 소켓 (Socket)
네트워크를 경유하는 프로세스 간 통신의 종착점. OSI 7계층 중 응용 계층에 속하는 프로세스들은 데이터 송수신을 위해 반드시 소켓을 거쳐 전송 계층으로 데이터를 전달해야한다.
즉, 소켓은 전송 계층과 응용 프로그램 사이의 인터페이스 역할을 하며 떨어져 있는 두 호스트를 연결해준다.

4. Socket API 흐름

client socket : 생성(socket) → 연결(connect) → 송수신(send/recv) → 닫기(close)
server socket : 생성(socket) → 결합(bind) → 주시(대기, listen) → 받기(accept) → 송수신(send/recv) → 닫기(close)
5. socket 프로그래밍 관련
함수명 원형
| socket | int socket(int family, int type, int protocol) |
| bind | int bind(int sockfd, const struct sockaddr *my addr, socklen_t addrlen) |
| listen | int listen(int sockfd, int backlog) |
| accept | int accept(int sockfd, struct sockaddr *clientaddr, socklen_t *addrlen) |
| connect | int connect(int sockfd, const struct sockaddr *serveraddr, socklen_t addrlen) |
| read | ssize_t read(int fd, void *buff, size_t nbytes) |
| write | ssize_t write(int fd, const void *buff, size_t nbytes) |

socket.h 파일의 역할

| /usr/include/sys/socket.h | 소켓 API 제공 (사용자가 직접 #include하는 파일) |
| /usr/include/linux/socket.h | 리눅스 커널 관련 소켓 상수 및 구조체 |
| /usr/include/asm/socket.h | 아키텍처별(예: x86, ARM) 소켓 관련 설정 |
| /usr/include/asm-generic/socket.h | 여러 아키텍처에서 공통적으로 사용되는 소켓 설정 |
| /usr/include/bits/socket.h | 내부적으로 사용되는 비트 필드 관련 설정 |
일반적인 네트워크 프로그래밍에서는 sys/socket.h를 포함하면 충분함.
커널이나 저수준 네트워크 프로그래밍을 할 때는 linux/socket.h 등을 직접 포함할 수도 있음.
#inlcude <socket.h>만 하면 되는 이유?
리눅스의 내부 구현과 관련된 파일들이며, 사용자가 직접 포함할 필요가 없음. (자동 참조)
socket 실습
int main() {
int x = 1;
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(10000);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
listen(listenfd, 5);
int connfd = accept(listenfd, (struct sockaddr *) NULL, NULL);
write(connfd, "Hello", 6);
close(connfd);
printf("Server: All done");
return 0;
}
1) 소켓 생성
int listenfd = socket(AF_INET, SOCK_STREAM, 0)
- AF_INET : ipv4 version 사용하겠다는 의미
- SOCK_STREAM : TCP, SOCK_DGRAM: UDP
- 0은 소켓에서 사용할 프로토콜
- IPPROTO_TCP : TCP
- IPPROTO_UDP : UDP
- 0 : type(SOCK_STREAM or SOCK_DGRAM)에서 정해진 경우
2) bind 함수
struct sockaddr_in servaddr
servaddr.sin_family = AF_INET
servaddr.sin_port = htons(10000)
servaddr.sin_addr.s_addr = htonl(INADDR_ANY)
bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr))
- bind(소켓 fd, 주소 정보 (형변환), 구조체 크기)
- 핵심
- sockaddr_in 구조체 bind 함수
- #include <sys/types.h>
- #include <sys/socket.h>
2) bind 함수 원형
int bind(SOCKET sockfd, const sockaddr *my_addr, int namelen);
- sockfd : 앞서 socket 함수로 생성된 endpoint 소켓의 식별 번호
- my_addr : IP 주소와 port 번호를 저장하기 위한 변수가 있는 구조체
- namelen : 두 번째 인자의 데이터 크기
- 반환값 : 성공하면 0, 실패하면 -1
* htons() vs htonl() 비교
함수 변환 대상 크기 사용 예시
| htons() | short (16비트, 2바이트) | 2B | 포트 번호 (sin_port) |
| htonl() | long (32비트, 4바이트) | 4B | IP 주소 (sin_addr.s_addr) |
* ntohs()와 ntohl()
- ntohs() : 네트워크 바이트 순서를 호스트 바이트 순서로 변환 (htons()의 반대)
- ntohl() : 네트워크 바이트 순서를 호스트 바이트 순서로 변환 (htonl()의 반대)
3) listen 함수
int listen(int sockfd, int backlog);
- socketfd : 수신 대기할 소켓
- backlog : 대기 큐 크기 (최대 대기 중인 연결 요청 개수)
- 성공 시 0, 실패 시 -1 리턴
- 클라이언트 연결 요청에 대한 정보는 시스템 내부적으로 관리되는 queue에서 쌓이게 되는데, 이 시점에서 클라이언트와의 연결은 아직 완전히 연결되지 않은(not ESTABLISHED state) 대기 상태
4) accept 함수
accept(listenfd, (struct sockaddr *) NULL, NULL)
client socket과 연결이 만들어지는 socket은 서버 소켓이 아니라 accept API 내부에서 새로 만들어지는 socket
accept() API에서 데이터 송수신을 위한 새로운 소켓을 만들고 서버 소켓의 대기 큐에 쌓여있는 첫 번째 연결 요청을 매핑시킴
5) write 함수
write로 client에게 메시지 전달 후 close 함수로 연결을 끊음
구조체 2종류
- sockaddr
- sockaddr_in
sockaddr 구조체
struct sockaddr {
sa_family_t sa_family; // 소켓 주소체계 (대부분 AF_INET)
char sa_data[14]; // 14 바이트로 실제 주소 저장을 위함
}
sa_family_t가 AF_INET인 경우 사용하는 구조체
struct sockaddr_in {
sa_family_t sin_family; // 2바이트: 주소 체계(AF_INET)
unsigned short int sin_port; // 2바이트: 포트 번호
struct in_addr sin_addr; // 4바이트: IPv4 주소 (in_addr 구조체)
unsigned char sin_zero[8]; // 8바이트: 패딩(사용되지 않음), 0으로 채움
};
'computer science' 카테고리의 다른 글
| 부동소수점 연산 (0) | 2025.02.19 |
|---|