[소켓 프로그래밍] setsockopt & getsockopt & kqueue

오젼·2022년 11월 19일
0

setsockopt

int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len);
int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);

socket: socket으로 소켓 디스크립터
level : 프로토콜 레벨 (SOL_SOCKET, IPPROTO_IP, IPPROTO_TCP, IPPROTO_IPV6 등)
option_name : 옵션 이름
option_value : 설정할 옵션 값.다양한 형태의 option value가 올 수 있기 때문에 void *로 선언되어 있음
option_len : len of option_value

프로토콜 레벨마다 지정할 수 있는 option이 다름
https://learn.microsoft.com/ko-kr/windows/win32/winsock/socket-options
https://m.blog.naver.com/kbm0996/221040731183

SOL_SOCKET

socket programming 관련 예제에선 SOL_SOCKET 레벨의 SO_REUSEADDR 옵션을 보통 추가로 세팅해주는 것 같다.

https://m.blog.naver.com/kbm0996/221041496905

getsockopt

현재 socket option을 가져올 수 있는 함수. setsockopt랑 똑같이 사용하면 된다. 대신 이번엔 option_value랑 option_len에 값이 담겨 옴.

kqueue

https://www.freebsd.org/cgi/man.cgi?query=EV_SET&sektion=3&apropos=0&manpath=FreeBSD%2B10.0-RELEASE

커널 큐를 새로 만들고 해당 kqueue descriptor 를 리턴해줌.
kqueue는 fork() 시 복사되지 않음.

kevent

특정 kqueue에 모니터링할 이벤트를 등록할 수 있음

int
     kevent(int	kq, const struct kevent	*changelist, int nchanges,
	 struct	kevent *eventlist, int nevents,
	 const struct timespec *timeout);

kq : kqueue descriptor
changelist : 등록할 이벤트 목록
nchanges : 등록할 이벤트 개수
eventlist : 감지된 이벤트 목록
nevents : 감지된 이벤트 개수
timeout : blocking이 몇 초 이상 지속되면 timeout시킬지. 0으로 세팅하면 이벤트 일어나기까지 계속 blocking.

EV_SET

kevent struct를 쉽게 세팅할 수 있는 매크로 함수.
kevent의 구조는 다음과 같음

 struct kevent {
	     uintptr_t	ident;	     /*	identifier for this event */
	     short     filter;	     /*	filter for event */
	     u_short   flags;	     /*	action flags for kqueue	*/
	     u_int     fflags;	     /*	filter flag value */
	     int64_t   data;	     /*	filter data value */
	     void      *udata;	     /*	opaque user data identifier */
	     uint64_t  ext[4];	     /*	extensions */
};

ident : event를 구분할 수 있는 식별자. 보통 file descriptor.
filter : 커널 필터
flags : 이벤트에서 수행할 작업 플래그
fflags : 필터별 플래그
data : 필터별 데이터 값
udata : 사용자 정의값
변경되지 않고 커널 안팎으로 전달되며 어떤 방식으로도 사용되지 않는다. 전적으로 애플리케이션에 따르게 된다. kevent의 애플리케이션용 식별자로 이용될 수 있다.
ext : 커널과 주고받는 확장 데이터
ext[0]과 ext[1]의 사용은 filter에 의해 정의 된다. 만약 필터가 사용하지 않는다면 변경되지 않고 그대로 복사된다. ext[2]와 ext[3]은 항상 커널을 통해 전달된다. 애플리케이션이 추가 컨텍스트를 사용할 수 있게 한다.

flags

flagmeagning
EV_ADDkqueue에 이벤트를 추가한다. re-adding시 기존 이벤트의 매개변수가 수정되며, 중복 항목이 생성되진 않는다.
EV_ENABLEkevent가 트리거된 경우 event를 반환하도록 허용한다.
EV_DISABLEkevent가 이벤트를 반환하지 않도록 이벤트를 비활성화한다. 필터 자체는 비활성화 되지 않는다.
EV_DISPATCHevent가 전달된 직후 이벤트를 disable하게 만든다.
EV_DELETEkqueue에서 이벤트를 지운다. close(fd)를 할 때 fd에 관련된 이벤트가 자동으로 삭제된다.
EV_RECEIPT대량의 changes를 만드려 할 때 그 중 하나라도 error를 일으키면, eventlist에 에러를 일으킨 이벤트가 배치되고, flags가 EV_ERROR로 세팅된다. 이렇게 하면 changelist에서 어떤 이벤트가 에러를 발생시켰는지 식별할 수 있다.
EV_ONESHOT특정 이벤트가 트리거된 이후 사용자가 이벤트를 수집하면 kqueue에서 삭제된다. DISABLE은 비활성화만 하는 것. ONESHOT은 아예 kqueue에서 삭제해버리는 것.
EV_CLEAR사용자가 이벤트를 수집하고 나면 상태를 리셋시킬 수 있는 플래그.(여기서 말하는 states가 정확히 뭔진 모르겠음.) 현재 state가 아니라 state transitions를 보고하는 filter에서 유용함. 일부 filter에선 자동으로 이 플래그를 설정하고 있을 수 있음
EV_EOF필터별 EOF를 나타내기 위해 사용할 수 있음. socket programming의 경우 disconnection을 감지하는 데 사용할 수 있음
EV_ERRORchangelist 처리 도중 오류가 발생하면 EV_ERROR와 함께 eventlist에 이벤트를 배치한다.

filter

사실상 EVFILT_READ, EVFILT_WRITE만 보면 될 듯

filtermeaning
EVFILT_READdescriptor를 identifier로 사용하고 읽을 수 있는 데이터가 있을 때마다 return 된다. listen()으로 전달된 Socket의 경우 보류중인 incomming connection이 있을 때 return 된다. data에는 listen backlog가 포함된다. 다른 Socket의 경우 읽을 수 있는 데이터가 있을 때 return 된다. data에는 읽을 수 있는 protocol data의 바이트가 포함된다.
EVFILT_WRITEdescriptor를 identifier로 사용하고 디스크립터에 쓸 수 있을 때마다 return 된다. Socket의 경우 data에는 쓰기 버퍼에 남아 있는 공간의 양이 포함된다. reader가 연결이 끊기면 filter는 EV_EOF로 세팅된다.
EVFILT_EMPTYdescriptor를 identifier로 사용하고 쓰기 버퍼에 남은 데이터가 없을 때마다 return 된다.
EVFILT_AIOasynchronous I/O system 관련된 필터. kevent()에 바로 등록되진 않는 대신 aio_sigevent 멤버로 등록된다고 한다. 비동기 I/O관련 필터인듯.
EVFILT_VNODEfile descriptor를 identifier, 감시할 events, fflags로 사용한다. 디스크립터에서 요청된 이벤트 중 하나 이상이 발생하면 return 된다.
EVFILT_PROCprocess ID를 identifier, 감시할 events, fflags로 사용한다. 프로세스가 요청된 이벤트 중 하나 이상을 수행하면 return 된다.
EVFILT_PROCDESCpdfork()로 받은 process descriptor를 identifier, 감시할 events, fflags로 사용한다. 관련 프로세스가 요청된 이벤트 중 하나 이상을 수행하면 return 된다.
EVFILT_SIGNAL모니터할 signal 번호를 identifiler로 사용하고 프로세스로부터 해당 signal이 전달되면 return 된다. signal(), sigaction()과 coexist하며 우선순위는 더 낮다.
EVFILT_TIMERident로 식별되는 임의의 타이머를 설정한다. timer를 추가하는 순간, data는 타이머를 작동할 순간을 지정한다. 반환시 data에는 kevent()에 대한 마지막 호출 이후 timeout이 만료된 횟수가 포함된다.
EVFILT_USER커널 메커니즘과 관련이 없지만 user level code에 의해 트리거 되는 ident로 식별되는 사용자 이벤트를 설정한다.

0개의 댓글