이 간단한 서버 코드에 문제가 있습니다. 신호를 수신 할 때까지 예상대로 작동합니다. 일반적으로리눅스 서버 C 코드가 신호 수신 후 멈춤
fprintf(stderr,"server_socket_fd=%d client_socket_fd=%d fd_max=%d\n", server_socket_fd, client_socket_fd, fd_max);
를 실행하는 경우가
server_socket_fd=3 client_socket_fd=4 fd_max=4
인쇄를 계속하지만이 신호를 수신 할 때 한 번
을이 행을 인쇄 : 디버그를 들어 나는 라인으로 선택 호출하기 전에 서버 및 클라이언트 파일 기술자를 인쇄server_socket_fd=3 client_socket_fd=-1 fd_max=3
그리고 프로그램이 정지합니다. GDB를 사용
은 내가 signal_handler에 중단 점을 넣고 그것이 내가 client_socket_fd 변수를 볼 수 없습니다 나누기 때, GDB는
No symbol "client_socket_fd" in current context.
을 말한다 내가 보는 경우가 있습니다 .. signal_handler 함수에서 제대로 반환하지 않습니다 백 추적 :
(gdb) bt
#0 0xb7fdccf9 in ??()
#1 0xb7e26af3 in __libc_start_main (main=0x8048bdd <main>, argc=1, argv=0xbfffef24, init=0x8049a00 <__libc_csu_init>,
fini=0x8049a70 <__libc_csu_fini>, rtld_fini=0xb7fed160 <_dl_fini>, stack_end=0xbfffef1c) at libc-start.c:287
#2 0x08048b01 in _start()
나는 더 깊은 디버깅 방법을 모른다.
char receive_buf[2048];
int main(int argc, char *argv[]){
int server_socket_fd;
int client_socket_fd = -1;
int fd_max;
struct sockaddr_in s_in;
int one = 1;
int status;
fd_set readfds;
int port;
int next_option;
const char* short_options = "hp:d:";
const struct option long_options[] = {
{ "help", 0, NULL, 'h'},
{ "port", 1, NULL, 'p'},
{ "debug", 1, NULL, 'd'},
{ NULL, 0, NULL, 0}
};
program_name = argv[0];
port = DEFAULT_PORT;
debug = 0;
do{
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
switch(next_option){
case 'h':
print_usage(stdout, 0);
break;
case 'p':
port = atoi(optarg);
if((port < 0)||(port > 65535)){
fprintf(stderr, "Invalid port number (%d), using default: %d", port, DEFAULT_PORT);
port = DEFAULT_PORT;
}
break;
case 'd':
debug = atoi(optarg);
if(debug < 0 || debug > 3)
debug = 0;
break;
case '?':
print_usage(stderr, 1);
break;
case -1:
break;
default:
abort();
}
}while(next_option != -1);
/************************* SIGNAL DEFINITIONS ***************************/
signal_action.sa_handler = (void *)signal_handler;
sigemptyset(&signal_action.sa_mask);
signal_action.sa_flags = SA_RESTART; // | SA_NOCLDSTOP;
if(sigaction(SIGINT, &signal_action, NULL) == -1){
fprintf(stderr, "Error setting SIGINT signal handler\n");
exit(1);
}
if(sigaction(SIGTERM, &signal_action, NULL) == -1){
fprintf(stderr, "Error setting SIGTERM signal handler\n");
exit(1);
}
if(sigaction(SIGWINCH, &signal_action, NULL) == -1){
fprintf(stderr, "Error setting SIGWINCH signal handler\n");
exit(1);
}
/* // ALSO TRIED WITH SIGNAL WITH SAME RESULT
if(signal(SIGWINCH, signal_handler) == SIG_ERR){
fprintf(stderr, "signal error\n");
return 1;
}
*/
s_in.sin_family = PF_INET;
s_in.sin_port = htons(port);
s_in.sin_addr.s_addr = INADDR_ANY;
if ((server_socket_fd = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1){
perror("Error creating socket");
return 1;
}
if(setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1){
perror("Error setting socket parameters");
return 1;
}
////////////////////////////////////////////
int x;
x=fcntl(server_socket_fd,F_GETFL,0); // Get socket flags
fcntl(server_socket_fd,F_SETFL,x | O_NONBLOCK); // Add non-blocking flag
////////////////////////////////////////////
if(bind(server_socket_fd, (struct sockaddr*) &s_in, sizeof(s_in)) == -1){
perror("Error binding socket");
return 1;
}
if(listen(server_socket_fd, 1) == -1){
perror("Error creating listening socket");
return 1;
}else{
printf("Server (%d) listening on port %d\n", server_socket_fd, port);
}
memset(receive_buf, '\0', sizeof(receive_buf));
gettimeofday(&t_print, NULL);
while(1){
// SERVER
FD_ZERO(&readfds);
FD_SET(server_socket_fd, &readfds);
fd_max = server_socket_fd;
// ADD CLIENT IF CONNECTED
if(client_socket_fd > 0){
FD_SET(client_socket_fd, &readfds);
if(client_socket_fd > server_socket_fd)
fd_max = client_socket_fd;
}
// ADDED THIS FPRINTF TO CHECK VARIABLES <----------------------------------
fprintf(stderr,"server_socket_fd=%d client_socket_fd=%d fd_max=%d\n", server_socket_fd, client_socket_fd, fd_max);
if(select(fd_max+1, &readfds, NULL, NULL, NULL) == -1){
if(errno != EINTR){
perror("select failed");
}
}
// ACCEPT CLIENT
if(FD_ISSET(server_socket_fd, &readfds)){
struct sockaddr_in s_in;
socklen_t len;
len = sizeof(s_in);
if((client_socket_fd = accept(server_socket_fd, (struct sockaddr*) &s_in, &len)) < 0){
if(errno != EWOULDBLOCK){
perror("En accept");
}
}else
printf("New client connected from %s\n", inet_ntoa(s_in.sin_addr));
}
// RECEIVE FROM CLIENT
if(client_socket_fd > 0){
if(FD_ISSET(client_socket_fd, &readfds)){
handle_client(client_socket_fd);
}
}
}
return 0;
}
int handle_client(int cl_fd){
int n;
n = recv(cl_fd, receive_buf, sizeof(receive_buf) - 1, MSG_DONTWAIT);
if(n == 0){
fprintf(stderr,"--------------> DEBUG: handle_client:client %d closed connection\n", cl_fd);
}else if(n < 0){
if(errno == EAGAIN){
return 0;
}else{
fprintf(stderr,"--------------> DEBUG: handle_client: recv ERROR: client %d closed connection (errno: %d : %s)\n", cl_fd, errno, strerror(errno));
memset(receive_buf, 0, sizeof(receive_buf));
return -1;
}
}else{
receive_buf[n] = '\0';
fprintf(stderr, "%s\n", receive_buf);
}
return 0;
}
void signal_handler(int sig){
switch(sig){
case SIGINT:
exit_properly(0);
break;
case SIGTERM:
exit_properly(1);
break;
case SIGABRT:
fprintf(stderr, "SIGABRT signal received\n");
break;
case SIGWINCH:
fprintf(stderr, "\33[2J");
fflush(stdout);
break;
default:
fprintf(stderr, "Unhandled signal %d received\n",sig);
break;
}
}
나는이 문제를 디버깅 할 내가 끼 었어 수있는 다른 모르겠어요 :
이 주요 코드입니다. 어떤 도움을 주시면 감사하겠습니다!
편집 : 실패 할 때 당신이 인쇄 참조 (및 용도를 선택) 올바른 파일 설명을하고 신호가 발생한 후 다음의 client_socket_fd 때문에 실패 동의를 잘못 수
이것은의 strace를 출력입니다 EAGAIN. exit_properly 호출 및 SIGTERM 및 SIGINT에 대한 신호 처리에 대해 주석을 달았습니다. SIGWINH 신호에 대해서는 아무것도하지 않고 그냥 반환합니다.
strace를 출력 :
write(2, "server_socket_fd=3 client_socket"..., 47server_socket_fd=3 client_socket_fd=4 fd_max=4
) = 47
select(5, [3 4], NULL, NULL, NULL) = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
sigreturn() (mask []) = -1 EINTR (Interrupted system call)
accept(3, 0xbf981e7c, [16]) = -1 EAGAIN (Resource temporarily unavailable)
write(2, "server_socket_fd=3 client_socket"..., 48server_socket_fd=3 client_socket_fd=-1 fd_max=3
) = 48
select(4, [3], NULL, NULL, NULL) = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
sigreturn() (mask []) = -1 EINTR (Interrupted system call)
accept(3, 0xbf981e7c, [16]) = -1 EAGAIN (Resource temporarily unavailable)
write(2, "server_socket_fd=3 client_socket"..., 48server_socket_fd=3 client_socket_fd=-1 fd_max=3
) = 48
select(4, [3], NULL, NULL, NULL
지금 signal_handler :
또한SA_RESTART
플래그 ... 동일한 결과없이 시도
void signal_handler(int sig){
switch(sig){
/*
case SIGINT:
exit_properly(0); //sigint_flag = 1;
break;
case SIGTERM:
exit_properly(1); //sigterm_flag = 1;
break;
*/
case SIGWINCH:
//sigwinch_flag = 1;
/*
fprintf(stderr, "\33[2J");
fflush(stdout);
*/
break;
default:
//fprintf(stderr, "Unhandled signal %d received\n",sig);
break;
}
}
... :/
fprintf()는 비동기 안전하지 않습니다. – EOF
문제가 발생하면 프로그램에서 어떤 특정 신호가 발생합니까? 디버깅을 위해서조차도 fprintf()를 시그널 핸들러에서 사용하면 안되며, 프로그램이 교착 상태에 빠질 수 있습니다 (문제가 원인 일 수 있음). 예 : write()를 직접적으로 사용하지만 FILE *에서 작동하는 함수를 사용하지 않거나 그렇지 않으면 신호 처리기를 호출하기에 안전하지 않은 함수를 사용하지 마십시오. strace 도구 (예 : strace -f ./myprogram)를 사용하여 실행할 경우 프로그램이 수행하는 작업에 대한 단서를 얻을 수도 있습니다. 이는 어떤 시스템 콜이 – nos
에 머물러 있는지 알려주고 exit_properly 무엇입니까? 방금 SA_RESTART를 설정하는 것은 좋은 생각이 아닙니다. 신호를 받으면 select 문에 영향을 주어 영원히 기다려 무한정 계속할 수 있습니다. exit_properly는 정상적인 종료를 위해 어떤 이유로이 선택 항목이 죽을 때까지 기다릴 수 있습니다 (누락 된 기호를 설명 할 수 있음). 그냥 여기에 야생 짐작은 – Aviv