임베디드/리눅스(Linux)

리눅스 소켓 프로그래밍 Linux socket programming

마달랭 2024. 10. 11. 10:35

개요

서버와 클라이언트는 동작이 다르다.

서버 : 클라이언트가 접속할 수 있도록 준비(Port, IP), 그리고 클라이언트의 연결을 기다린다.

클라이언트 : 서버의 IP와 Port를 이용해 접속하며, 연결이 되었을 경우 동작을 한다.

 

  서버 클라이언트
IP 서버 소켓이 동작하는
컴퓨터의 IP 주소
통신을 원하는
원격지 PC의 IP 주소
Port 소켓이 “위치 할” 포트 번호 소켓이 “위치한” 포트 번호

 

 

TCP 기반 서버 소켓 동작 순서는 다음과 같다.

  • socket() 소켓 생성
  • bind() 소켓에 주소 할당
  • listen() 클라이언트 연결 요청 대기
  • accept() 클라이언트 연결 승인
  • read() / write() 통신
  • close() 소켓 닫기

 

TCP 기반 클라이언트 소켓 동작 순서는 다음과 같다.

  • socket() 소켓 생성
  • connect() 연결 요청
  • read() / write() 데이터 송수신
  • close() 연결 종료

 

소켓은 인터페이스, 다른 말로는 프레임워크이기 때문에, 반드시 위 과정을 외워야 한다.

 

 

헤더파일

1. sys/socket.h

#include <sys/socket.h>

 

소켓 프로그래밍을 위한 헤더 파일이다.

 

2. netinet/in.h

#include <netinet/in.h>

 

인터넷 프로토콜 관련 구조체를 사용하기 위한 헤더 파일이다.

 

3. arpa/inet.h

arpa/inet.h>

 

인터넷 주소 변환 함수를 사용하기 위한 헤더 파일이다.

 

4. signal.h

#include <signal.h>

 

시그널 처리를 위한 헤더 파일이다.

 

5. sys/types.h

#include <sys/types.h>

 

socklen_t등 데이터 타입을 사용하기 위한 헤더 파일이다.

 

 

메서드

1. socket

int socket(int domain, int type, int protocol)

 

소켓을 생성하는 함수이다. 성공 시 socket의 파일 디스크립터를 정수형으로 리턴한다.

  1. domain : 프로토콜 도메인을 할당할 매개변수, IPv4를 사용하려면 AF_INET을 매개변수로 전달해 준다.
  2. type : 소켓 타입, TCP 소켓을 사용하기 위해선 SOCK_STREAM을 매개변수로 전달해 준다.
  3. protocol : 시스템이 정하기 때문에 주로 0을 입력한다.
  4. 해당 메서드를 사용하기 위해선 sys/socket.h 헤더파일이 필요하다.

 

2. setsockopt

int setsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen)

 

소켓의 옵션을 지정해 주는 메서드이다, 소켓 종료 후 다시 실행할 때 포트 충돌 방지 목적으로 사용

  1. scoket : 1번에서 생성한 소켓의 리턴 값을 넣어주면 된다.
  2. level : 소켓의 레벨, 주로 SOL_SOCKET을 매개변수로 전달해 준다.
  3. optname : 옵션 이름, 예시로 SO_REUSEADDR을 매개변수로 전달해 주면 주소 재사용 옵션을 적용한다.
  4. optval : 옵션의 값
  5. optlen : 옵션 길이
  6. 해당 메서드를 사용하기 위해선 sys/types.h, sys/socket.h가 필요하다.

 

3. sockaddr_in (구조체)

IPv4 주소 체계를 사용하는 경우, sockaddr_in 구조체를 사용한다.

  1. 초기화 → NULL 로 설정
  2. sin_family = AF_INET (IPv4 사용 매크로)
  3. sin_addr = IP 주소 배정
  4. sin_port = Port 배정, IP, Port를 지정할때는 빅엔디안 형태로 입력해 주어야 한다.
  5. socklen_t : 시스템 호환용으로 socket의 구조체 크기의 타입이다.

 

4. bind

int bind(int socket, const struct sockaddr*, socklen_t)

 

소켓에 Port와 IP주소를 할당한다. return값으로 성공 여부가 정수형으로 주어진다.

  1. socket : socket의 파일 디스크럽터
  2. addr : sockaddr 구조체를 매개변수로 전달한다. (socket의 주소 정보와 port정보를 담고 있음)
  3. socklen_t : 소켓 구조체의 크기를 매개변수로 전달한다.
  4. sys/socket.h 헤더가 필요하다.

 

5. listen

int listen(int socket, int backlog)

 

대기 큐를 만들고, socket의 연결을 기다리는 메서드 서버에서 사용된다. 성공 여부를 정수타입으로 리턴한다.

  1. socket : 연결을 기다릴 서버 소켓의 파일 디스크럽터
  2. backlog : 대기 큐의 크기를 나타내는 정수이다. 서버에 접속하기 위해 대기하는 클라이언트의 최대 수를 의미
  3. sys/socket.h 헤더가 필요하다.

 

6. accept

int accept(int sock, struct sockaddr*, socklen_t)

 

클라이언트의 연결 요청을 수락하는 메서드, 성공 여부를 리턴값으로 반환한다.

  1. sock : 소켓의 파일 디스크럽터
  2. sockaddr : 소켓의 구조체 정보
  3. socklen_t : 소켓 구조체의 길이
  4. sys/socket.h 헤더 파일이 필요하다.

 

7. connect

int connect(int socket, const struct sockaddr*, socklen_t)

 

소켓에서 연결을 시작하는 메서드로 클라이언트에서 사용해야 한다. 성공 여부를 리턴값으로 반환한다.

  1. socket : 클라이언트의 소켓 파일 디스크럽터 정보
  2. sockaddr : 접속할 서버의 소켓 정보를 가진 구조체
  3. socklen_t : 구조체의 길이
  4. sys/socket.h 헤더 필요

 

8. read/wirte

클라이언트와 서버간의 통신을 담당한다.

위에서 언급했듯 소켓 또한 파일로 취급하므로 각 소켓의 파일 디스크럽터를 파일 처럼 매개변수로 사용할 수 있다.

 

 

9. close

int close(int socket)

 

소켓 통신의 종료 메서드, socket의 종료는 매우 중요하며 꼭 신경 써야한다.

  1. socket : 종료할 소켓의 파일 디스크럽터를 매개변수로 전달한다.
  2. 소켓도 파일 open/close형식이다.

 

10. interrupt

만약 소켓 통신 도중 이터럽트가 필요하다면 별도의 함수를 작성하여 처리해 준다.

시그널이 입력될 경우 해당 시그널을 통해 처리해 주면 된다.

 

 

참고 사항

IP 주소는 빅엔디안 형식으로 네트워크 바인트 순서로 넣어야 한다.

전 세계 네트워크 앱은 반드시 “빅 엔디안“ 방식을 사용하자고 약속되어 있다.

다행히 관련 내용을 편하게 하기 위한 메서드가 준비되어 있다.

  • htonl() – int 형 IP 를 빅엔디안으로 변경하는 API
  • htons() - int 형 PORT 를 빅엔디안으로 변경하는 API

 

Socket 의 종료는 매우 중요하다.

대부분의 Socket 은 네트워크에서 다중 접속을 위해 사용된다.
원활한 종료를 하지 않을 경우, 리소스 관리, 데이터 손실, 보안 등 많은 문제가 생긴다.

 

 

728x90