- 본 내용은 Linux (Ubuntu 14.04 lts)를 기반으로 제작되었습니다. -
소캣 프로그래밍은 UDP 기반으로 하였습니다.
이전 게시물에서 확인한 내용을 토대로 alarm과 UDP를 이용하여 UDP에서 무작정 데이터 그램을 보내는 것이 아닌
서버가 종료되었을 때, 클라이언트에서 이를 감지한 후 반응하는 코드를 제작해 본다.
이전에 알던 UDP는 서버가 열리지 않아도 클라이언트 혼자 메시지를 전송 할 수는 있었지만,
그 메시지가 어디로 가는지, 서버가 열린지는 확인 할 수 없었다.
하지만, 이 코드에서는 서버가 열리지 않아도 클라이언트가 메시지를 보낼 순 있지만,
서버가 제시간 내에 응답하지 않으면 종료되는 방식을 알아본다.
헤더 파일
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //header.h #include <stdio.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #define PORT 20162 #define BUFFER_SIZE 4096 #define BUFF_SIZE 100 // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
서버 코드에 대한 설명 ::
일반 UDP 서버 코드와 동일하므로 생략한다. (이전 게시물을 참조하면 된다.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | //server.cpp # include "header.h" int main() { struct sockaddr_in serverSocket, clientSocket; memset(&serverSocket, 0, sizeof(serverSocket)); memset(&clientSocket, 0, sizeof(clientSocket)); serverSocket.sin_family = AF_INET; serverSocket.sin_addr.s_addr = htonl(INADDR_ANY); serverSocket.sin_port = htons(PORT); int serverSocketFD; int client_addr_size; ssize_t receivedBytes; printf("Waiting for clients...\n"); // 서버 소켓 생성(UDP니 SOCK_DGRAM이용) if((serverSocketFD = socket(AF_INET, SOCK_DGRAM, 0)) == -1) // SOCK_DGRAM : UDP { printf("Sever : can not Open Socket\n"); exit(0); } if (bind(serverSocketFD, (struct sockaddr *) &serverSocket, sizeof(serverSocket)) == -1) { printf("Can not bind.\n"); return -1; } char sendBuffer[BUFFER_SIZE]; char readBuffer[BUFFER_SIZE]; while (1) { // 클라이언트 주소크기를 받아낸다. client_addr_size = sizeof(clientSocket); receivedBytes = recvfrom(serverSocketFD, readBuffer, BUFF_SIZE, 0, (struct sockaddr *)&clientSocket, &client_addr_size); readBuffer[receivedBytes] = '\0'; printf("%s",readBuffer); fflush(stdout); sprintf(sendBuffer,"%s",readBuffer); sendto(serverSocketFD, sendBuffer, strlen(readBuffer), 0, (struct sockaddr*)&clientSocket, sizeof(clientSocket)); } return 0; } // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
클라이언트 코드에 대한 설명 ::
alarm 시그널은 다음과 같은 코드로 세팅 후 설치한다.
// alarm 세팅
struct sigaction alarmAction;
alarmAction.sa_handler = alarmHandler;
alarmAction.sa_flags = 0;
sigaction(SIGALRM, &alarmAction, NULL);
// alarm 시그널 설치
signal(SIGALRM, alarmHandler);
그 후, while문에서 서버에 문자열을 전송 한 후, alarm(1)을 통해 시그널을 보낸다.
만약 서버에서 답이 없다면 alarm 시그널에 의해 5초가 지나면 타임 아웃과 함께 클라이언트가 종료된다.
서버에서 echo로 보낸 메시지를 수신하게되면 alarm(0)에 의해 시그널이 취소되고 다음 메시지를 보낼 수 있다.
이 과정이 계속반복되어 서버가 열려있는지 닫혀있는지를 판별 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | //client.cpp # include "header.h" # define TIMEOUT 5 int count = 0; char sendBuffer[BUFFER_SIZE]; char receiveBuffer[BUFFER_SIZE]; int receiveBytes; void alarmHandler(int sig) { count++; if(count == TIMEOUT) { printf("\ncount :: %d\n",count); printf("Time Out\n"); exit(0); } // 받은 값이 없으면 alarm 시그널 호출 if(receiveBytes == 0) { printf("\ncount :: %d\n",count); alarm(1); } else { //응답을 받았으면 alarm 시그널을 취소. alarm(0); count = 0; receiveBytes = 0; } } int main(int argc, char** argv) { // alarm 세팅 struct sigaction alarmAction; alarmAction.sa_handler = alarmHandler; alarmAction.sa_flags = 0; sigaction(SIGALRM, &alarmAction, NULL); // alarm 시그널 설치 signal(SIGALRM, alarmHandler); if (argc != 2) { printf("Usage: %s IPv4-address\n", argv[0]); return -1; } struct sockaddr_in serverSocket; memset(&serverSocket, 0, sizeof(serverSocket)); serverSocket.sin_family = AF_INET; inet_aton(argv[1], (struct in_addr*) &serverSocket.sin_addr.s_addr); serverSocket.sin_port = htons(PORT); int clientSocketFD = socket(AF_INET, SOCK_DGRAM, 0); while (1) { //사용자로부터 문자열을 입력을 받는다. printf("서버에 보낼 말을 입력하세요 :: "); fgets(sendBuffer,BUFF_SIZE,stdin); //서버에 입력받은 문자열을 전송한다. sendto(clientSocketFD, sendBuffer, strlen(sendBuffer), 0, (struct sockaddr*)&serverSocket, sizeof(serverSocket)); //alarm 시그널을 이용해 5초 동안 응답이 없으면 에러 메시지를 출력. alarm(1); //서버로부터 입력받은 문자열을 출력한다. int server_addr_size = sizeof(serverSocket); receiveBytes = recvfrom(clientSocketFD, receiveBuffer, BUFF_SIZE, 0, (struct sockaddr *)&serverSocket, &server_addr_size); receiveBuffer[receiveBytes] = '\0'; printf("%s",receiveBuffer); fflush(stdout); } return 0; } // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
UDP 서버만 열린 상황
클라이언트 각자 서버와 메시지 송수신을 하는 과정
서버가 종료되었을 때 클라이언트가 메시지를 보내면 alarm시그널이 발동하는 과정
TIME OUT 되는 화면. 클라이언트가 종료되었다.
나머지 클라이언트 모두 종료되는 과정
'Applied > Network' 카테고리의 다른 글
소켓 프로그래밍 - (16) Posix Thread 개념 (0) | 2016.10.29 |
---|---|
소켓 프로그래밍 - (15) Thread 개념 (0) | 2016.10.29 |
소켓 프로그래밍 - (13) TCP/IP 다중 통신 소스 코드 (fork 이용) (0) | 2016.10.27 |
소켓 프로그래밍 - (12) TCP/IP 다중 통신 개념 (fork 이용) (0) | 2016.10.15 |
소켓 프로그래밍 - (11) SIGALRM 사용 방법 (1) | 2016.10.15 |