==================================================================================================
interrupt signal service routin으로 클라이언트의 비정상적인 종료를 서버에서 확인하는 간단한 예제..
얼마든지 응용해서 다양한 signal interrupt 에 대한 처리를 할 수 있게 만든 예제 코드 (TCP/IP)
참고 : 윤성우의 TCP/IP 프로그래밍
==================================================================================================
[실행화면]
- Echo_Server : 서버는 계속 돌아야 한다....
- Echo_Client
=================================================================================================
[소스코드]
/**************************************************************/
/* 내 용 : 에코 서버 */
/* 작성자 : creazier (블로그 주인장) */
/* 블로그 : http://blog.daum.net/creazier */
/**************************************************************/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#define BUFSIZE 1024
void signal_init(struct sigaction *zombi, struct sigaction *act, int *state1, int *state2);
void handler(int signal);
void conn_init(int *serv_socket, struct sockaddr_in *serv_addr, int port);
void error_handling(char *message);
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock, clnt_addr_size, str_len, state1, state2;
struct sockaddr_in serv_addr, clnt_addr;
struct sigaction act, zombi_exit;
char message[BUFSIZE];
pid_t pid;
if(argc != 2) // 메인함수 인자 확인 및 사용법 출력
{
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
signal_init(&zombi_exit, &act, &state1, &state2);
if(state1 != 0 && state2 != 0) // 시그널 세팅 확인
error_handling("sigaction() Error!");
memset(&serv_addr, 0, sizeof(serv_addr));
conn_init(&serv_sock, &serv_addr, atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1)
error_handling("bind() Error!");
if(listen(serv_sock, 5) == -1)
error_handling("listen() Error!");
while(1)
{
clnt_addr_size = sizeof(clnt_addr);
clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size);
if(clnt_sock == -1)
continue;
if((pid = fork()) == -1) // 멀티 태스킹 (멀티 프로세스)이 제대로 이뤄졌는지 확인
{
close(clnt_sock);
continue;
}
if(pid > 0) // 부모 프로세스
{
puts("연결 생성!");
close(clnt_sock);
continue;
}
else // 자식 프로세스
{
close(serv_sock);
while((str_len = read(clnt_sock, message, BUFSIZE)) != 0)
{
write(clnt_sock, message, str_len);
if(!strcmp(message, "SIGNAL_INTERRUPT")) // 클라이언트 인터럽트 메시지를 확인하고
{
raise(SIGTSTP); // 자기 자신에게 인터럽트를 건다.
break;
}
write(1, message, str_len);
}
puts("연결 종료!");
close(clnt_sock);
exit(0);
}
}
return 0;
}
void signal_init(struct sigaction *zombi, struct sigaction *act, int *state1, int *state2)
{ // 시그녈 관련 처리 세팅
act -> sa_handler = handler; // 인터럽트 서비스 루틴 등록
sigemptyset(&(act->sa_mask));
act -> sa_flags = 0;
*state1 = sigaction(SIGTSTP, act, 0);
sigemptyset(&(zombi->sa_mask));
zombi -> sa_flags = 0;
*state2 = sigaction(SIGCHLD, act, 0);
}
void z_handler(int signal) // 좀비 프로세스 해결 (반복문 돌려서 wait() 시키는 것의 대안)
{
pid_t pid;
int rtn;
pid = waitpid(-1, &rtn, WNOHANG);
WEXITSTATUS(rtn);
}
void handler(int signal) // 인터럽트 서비스 루틴
{
printf("클라이언트가 비정상적으로 종료되었습니다.\n");
// exit(0); // 서버는 종료되서는 안되므로....
}
void conn_init(int *serv_socket, struct sockaddr_in *serv_addr, int port) // 주소 정보 초기화
{
*serv_socket = socket(PF_INET, SOCK_STREAM, 0);
serv_addr->sin_family = AF_INET;
serv_addr->sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr->sin_port = htons(port);
}
void error_handling(char *message) // 에러 처리 함수
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
-------------------------------------------------------------------------------------------------
/**************************************************************/
/* 내 용 : 에코 클라이언트 */
/* 작성자 : creazier (블로그 주인장) */
/* 블로그 : http://blog.daum.net/creazier */
/**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#define BUFSIZE 1024
void signal_init(struct sigaction *act, int *state);
void signal_handler(int signal);
void conn_init(int *clnt_sock, struct sockaddr_in *serv_addr, const char *IP_Address, const int port);
void error_handling(char *message);
static int clnt_sock;
int main(int argc, char *argv[])
{
int str_len, state;
struct sockaddr_in serv_addr;
struct sigaction act;
char message[BUFSIZE];
if(argc != 3) // 메인함수 인자 및 사용법 출력
{
printf("Usage : %s <IP> <PORT>\n", argv[0]);
exit(1);
}
signal_init(&act, &state);
if(state != 0) // 시그널 관련 세팅이 제대로 됐는지 확인
error_handling("sigaction() Error!");
memset(&serv_addr, 0, sizeof(serv_addr));
conn_init(&clnt_sock, &serv_addr, argv[1], atoi(argv[2]));
if(connect(clnt_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect() Error!");
while(1)
{
fputs("전송할 메시지를 입력하세요 (q = Quit) : ", stdout);
fgets(message, BUFSIZE, stdin);
if(!strcmp(message, "q\n")) // q를 입력하면 클라이언트의 정상적인 종료
break;
write(clnt_sock, message, strlen(message));
str_len = read(clnt_sock, message, BUFSIZE-1);
message[str_len] = 0;
printf("서버로부터 전송되 메시지 : %s\n", message);
}
close(clnt_sock);
return 0;
}
void signal_init(struct sigaction *act, int *state) // 시그녈 관련 처리 세팅
{
act -> sa_handler = signal_handler; // 인터럽트 서비스 루틴 등록
sigemptyset(&(act->sa_mask));
act -> sa_flags = 0;
*state = sigaction(SIGTSTP, act, 0);
}
void signal_handler(int signal) // 인터럽트 서비스 루틴
{
char *signal_message = "SIGNAL_INTERRUPT";
printf("인터럽트 시그널 발생! 비정상으로 종료됩니다.\n");
write(clnt_sock, signal_message, strlen(signal_message));
close(clnt_sock);
exit(1);
}
void conn_init(int *clnt_sock, struct sockaddr_in *serv_addr, const char *IP_Address, const int port)
{ // 주소 정보 초기화
*clnt_sock = socket(PF_INET, SOCK_STREAM, 0);
serv_addr -> sin_family = AF_INET;
serv_addr -> sin_addr.s_addr = inet_addr(IP_Address);
serv_addr -> sin_port = htons(port);
}
void error_handling(char *message) // 에러 처리 함수
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
=================================================================================================
'IT_Programming > Network Programming' 카테고리의 다른 글
[펌] 멀티 프로세스 / 멀티 쓰레드 / 멀티 플렉싱 기법의 장점과 단점 (0) | 2009.07.02 |
---|---|
[Winsock] TCP_IP Half Close를 이용한 파일전송 (0) | 2009.07.02 |
[WinSock] 열린 포트 검색하기 (0) | 2009.07.01 |
[UDP] strftime()를 이용해서 날짜와 시간 문자열 구하기 (0) | 2009.06.30 |
[펌] TCP/IP 소켓 프로그래밍 with C# (0) | 2009.03.05 |