sigaction 함수는 signal 함수를 대체할 수 있고 더 안정적입니다. sigaction 함수는 유닉스 계열 운영체제 별 동작방식에 따른 차이를 보이지 않기 때문입니다. 따라서 요즘은 signal 함수 대신 sigaction 함수를 사용합니다. #include int sigaction(int signo, const struct sigaction * act, struct sigaction * oldact); //success: 0 fail: -1 //signo: 시그널의 정보 //act : 시그널 발생시 호출될 함수의 정보 //oldact: 이전에 등록되었던 시그널 핸들러의 함수 포인터를 얻는데 사용, 필요 없으면 0 전달 위 함수의 호출을 위해서는 sigaction이라는 이름의 구조체를 선언 및 ..
현생/TCP 소켓 프로그래밍
부모 프로세스에서 자식 프로세스의 종료를 계속 확인하기에는 비효율적입니다. 자식 프로세스의 종료를 인식하는 주체는 운영체제이므로 운영체제가 부모 프로세스에게 자식 프로세스의 종료를 알릴 수 있다면 더 효율적일 것입니다. #include void (*signal(int signo, void(*func)(int)))(int); // 시그널 발생시 호출되도록 이전에 등록한 함수의 포인터 반환 위 함수를 시그널 등록 함수라고 표현하는데요, 프로세스가 자식 프로세스의 종료 발생 시 특정 함수의 호출을 운영체제에게 요구하는 "시그널 등록"을 하기 때문입니다. 위 함수를 정리하면 다음과 같습니다. 함수 이름: signal 매개변수 선언: int signo, void(*func)(int) 반환형 : 매개변수형이 int..
프로세스가 할 일을 다 하고도 사라지지 않고 리소스를 차지하고 있는 모습을 가리켜 좀비 프로세스라고 합니다. fork() 함수의 호출로 생성된 프로세스를 종료하는 방법은 인자를 전달하면서 exit를 호출하거나, main 함수에서 return문을 실행하면서 값을 반환하는 경우가 있습니다. exit의 인자 값, return의 반환 값 모두 운영체제로 전달되고, 운영체제는 이 값이 부모 프로세스에게 전달될 때까지 자식 프로세스를 소멸시키지 않는데, 이 상황의 프로세스를 좀비 프로세스라 칭합니다. 따라서 자식 프로세스가 종료되며 나온 반환값이나 인자값이 부모 프로세스에게 전달되어야 좀비 프로세스를 없앨 수 있습니다. 부모 프로세스가 자식 프로세스의 전달 값을 요청하는 방법은 두 가지가 있습니다. 먼저 wait ..
프로세스의 현재 상태를 확인하는 방법은 Process Status의 약자인 ps 명령어를 사용합니다. 그냥 ps만 입력하면 다음과 같이 PID, TTY, TIME, CMD를 출력합니다. PID TTY TIME CMD 211 pts/4 00:00:00 bash 685 pts/4 00:00:00 ps 그리고 ps [옵션] 꼴으로 옵션을 사용할 수 있습니다. 대쉬(-)가 붙거나 붙지 않는 옵션들이 있는데, 이는 Unix98, BSD, GNU 모두 사용법이 다른 옵션들이 있습니다. Unix98에서는 대쉬(-), BSD에서는 대쉬를 사용하지 않고 GNU에서는 대쉬 2개(--)를 사용합니다. 먼저 이 시리즈에서 자주 사용하는 "ps au" 명령어의 a와 u는 다음과 같습니다. a : 현재 터미널의 사용자 고유 프로..
서버가 한 번에 한 요청만 받을 수 있다면 연결요청이 무수히 쌓였을 때 후순위에 있는 요청은 받아들여지기까지 긴 시간이 걸릴 것입니다. 또, 네트워크 프로그램은 데이터의 송수신 시간이 큰 비중을 차지하기에 한 번에 한 요청보단 여러 요청을 받는 것이 더 유리합니다. 그래서 둘 이상의 클라이언트에게 동시에 서비스를 제공하는 다중접속 서버가 필요합니다. 멀티프로세스 기반 서버 : 다수의 프로세스를 생성하는 방식 멀티플렉싱 기반 서버 : 입출력 대상을 묶어서 관리하는 방식 멀티쓰레딩 기반 서버 : 클라이언트의 수만큼 쓰레드를 생성하는 방식 위는 대표적인 세 가지 다중접속 서버입니다. 이 문서에서는 제목에서 말했듯 멀티프로세스 기반 서버에 대해서 다룰 것입니다. 먼저 프로세스란, 메모리 공간을 차지한 상태에서 ..
Nagle 알고리즘은 네트워크 상에서 돌아다니는 패킷들의 오버플로우를 막기 위해 1984년 제안된 알고리즘으로, 앞서 전송한 데이터에 대한 ACK 메시지를 받아야만 다음 데이터를 전송하는 알고리즘입니다. TCP상에서 적용되는 간단한 알고리즘이고, 적용여부에 따른 데이터 송수신 방식의 차이는 다음과 같습니다. 문자열 "Nagle"을 전송할 때 알고리즘을 적용했을 때와 적용하지 않았을 때의 극단적인 상황을 보여주는 예시입니다. 왼쪽 그림에서, 데이터 'N'을 보내고, ACK가 올 때까지 출력버퍼에 a, g, l, e를 쌓다가 ACK가 도착하자 데이터 'agle'를 하나의 패킷으로 보내는 모습입니다. 1바이트의 데이터를 보내더라도 패킷의 헤더정보의 크기가 수십바이트기 때문에 위 예시에선 알고리즘을 적용했을 때..
이 소켓의 옵션을 소개하기 이전에, Time-wait 상태를 얘기하겠습니다. 우리가 서버를 키고 종료할 때 컨트롤-C 등으로 강제 종료하고 즉시 다시 키려고 시도하면 bind()함수에서 에러가 발생하는 모습을 이미 보셨을 수도 있습니다. 이 상황이 발생한 이유는 Time-wait 상태 때문인데, 데이터 송수신 중에 먼저 연결의 종료를 요청한 호스트는 Time-wait 상태를 거치게 됩니다. 만약 클라이언트와 통신 중에 위의 예시와 같이 강제종료 하는 등 서버가 먼저 종료되면, 서버가 Time-wait 상태를 거치게 되는 것입니다. 이 상태는 소켓이 소멸되지 않고 남아있게 됩니다. (TCP에서 송수신이 종료되는 과정을 모르신다면 https://pupuduck.tistory.com/35를 참고해주시기 바랍니..
소켓이 생성되면 기본적으로 입력버퍼와 출력버퍼가 생성됩니다. SO_RCVBUF는 입력버퍼의 크기와 관련된 옵션이고 SO_SNDBUF는 출력버퍼의 크기와 관련된 옵션입니다. 이 두 옵션을 이용해 입출력 버퍼의 크기를 참조할 수 있고, 변경 또한 할 수 있습니다. 다음 소스코드는 입출력버퍼의 크기를 얻는 예제입니다. #include #include #include #include void error_handling(char *message); int main(int argc, char *argv){ int sock; int snd_buf, rcv_buf, state; socklen_t len; sock=socket(PF_INET, SOCK_STREAM, 0); // 출력버퍼의 크기를 얻는다. len=size..