소켓으로짜는 프로그램 (포크) 버젼 1-1......
글쓴이: cccc2002 / 작성시간: 금, 2003/09/05 - 5:10오후
서버와 클라이어트가 같이 있는 B부분입니다.
아직 A로부터 받은 아이피를 가지고 C로 접속을 했을때 실패한 경우 다시 A에게 답을 해줘야 하는데 그것을 아직은 구현 못했습니다.
두번째로는 fork()수를 제한 하는 문제가 남아 있지만 오늘중으로 해결하려합니다.
여기서 한가지 묻고싶습니다.
클라이언트가 비정상적으로 죽어버리면 서버가 죽어버리는데 이것을 해결하기위한 방법은어떤것이 있을까요.....
예를 들면 Ctrl +C 를 받아서 클라이언트가 죽는경우 그리고 전원이 나가서 클라이언트가 죽는경우등등 ..............
#include <errno.h> /* obligatory includes */ #include <signal.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netdb.h> #define PORTNUM 60007 // random port number, we need something #define SPORTNUM 60003 //server port number #define MAXLINE 1024 #define MAXHOSTIP 200 int establish(unsigned short); void fireman(int); int get_connection(int s); void do_something(); int read_save(int); char command[256],option[256]; char rline[MAXLINE],my_msg[MAXLINE]; struct in_addr host_ip[MAXHOSTIP]; int command_nflag,command_nsize,option_nflag,option_nsize,send_size; int main() { int s_fd,c_fd,ip_count,i; if ((s_fd= establish(PORTNUM)) < 0) // socket() bind() listen() { perror("establish"); exit(1); } signal(SIGCHLD,fireman); // this eliminates zombies while(1) { if ((c_fd= get_connection(s_fd)) < 0) // accept() { if (errno == EINTR) continue; perror("accept"); exit(1); } ip_count=read_save(c_fd); for(i=0; i<ip_count;i++) { switch(fork()) { case -1 : // fork error perror("fork"); close(s_fd); close(c_fd); exit(1); case 0 : // we're the child, do something close(s_fd); close(c_fd); do_something(i); exit(0); default : // we're the parent so look for continue; } } } } int establish(unsigned short portnum) { int server_fd,client_fd; struct sockaddr_in server_addr; if ((server_fd= socket(AF_INET, SOCK_STREAM, 0)) < 0) // create socket { perror("socket"); exit(1); } bzero((char *)&server_addr,sizeof(server_addr)); server_addr.sin_family= AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); // server ip address server_addr.sin_port= htons(portnum);// this is port number if (bind(server_fd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) < 0) { close(server_fd); return(-1); // bind address to socket } if(listen(server_fd, 3)<0) // listen { perror("listen"); exit(1); } return(server_fd); } // catches falling children. void fireman(int sig) { while (waitpid(-1, NULL, WNOHANG) > 0); return; } int get_connection(int s_fd) { int t,clilen; // socket of connection struct sockaddr_in server_addr; clilen=sizeof(server_addr); if ((t = accept(s_fd,(struct sockaddr *)&server_addr,&clilen))<0) // accept connection if there is one return(-1); return(t); } void do_something(int i) { int ser_cli_fd; struct sockaddr_in name_addr; if((ser_cli_fd=socket(AF_INET,SOCK_STREAM,0))<0) { perror("socket"); exit(1); } bzero((char *)&name_addr,sizeof(name_addr)); name_addr.sin_family=AF_INET; name_addr.sin_addr.s_addr=host_ip[i].s_addr; name_addr.sin_port=htons(SPORTNUM); if(connect(ser_cli_fd,(struct sockaddr *)&name_addr,sizeof(struct sockaddr_in))<0) { printf("Connect failed server_ip: %s\n",inet_ntoa(host_ip[0].s_addr)); exit(1); } if(send(ser_cli_fd,rline,send_size,0)<0) { perror("send error"); exit(1); } close(ser_cli_fd); } int read_save(int t_fd) { int host_ip_count,i; if((recv((int)t_fd,rline,MAXLINE,0)) <= 0) { perror("recv error"); exit(1); } memcpy(&command_nflag,rline,4); memcpy(&command_nsize,rline+4,4); memcpy(command,rline+8,command_nsize); memcpy(&option_nflag,rline+sizeof(int)*2 + command_nsize,4); memcpy(&option_nsize,rline+sizeof(int)*3 + command_nsize,4); memcpy(option,rline+sizeof(int)*4 + command_nsize,option_nsize); send_size=sizeof(int)*4 + command_nsize + option_nsize; memcpy(&host_ip_count,rline + send_size,4); for(i=0;i<host_ip_count; i++) { memcpy(&host_ip[i].s_addr,rline + send_size + sizeof(int) +sizeof(int)*i ,4); } return(host_ip_count); }
Forums:
Client가 죽는다고 해서 서버가 죽는 것은 프로그램을 잘못작성해서입니
Client가 죽는다고 해서 서버가 죽는 것은 프로그램을 잘못작성해서입니다. (우째 그런일이!)
linux 이죠?
디버깅 툴을 이용해보세요.
strace 등을 통해서 어떤일이 일어나고 있는지 알 수 있지요.
gdb를 통해서 일어나는 동안 변수 값을 확인 할 수 있습니다.
http://bbs.kldp.org/viewtopic.php?t=1045
혹 사용하지 않으신다면, gdb는 맨 위 검색에서도 많이 나오니까.. 찾아보시기 바랍니다.
---
http://coolengineer.com
Client가 죽어서 Server가 죽으면..
소켓이 비정상적으로 끊기게 되었을 때 발생하는 시그날에 대한
핸들링을 잘못 해서 그렇습니다.
발생하는 시그날은 SIGPIPE 이며
아래와 같이 처리하시면 간단합니다.
signal(SIGPIPE, SIG_IGN);
다시정정하겠습니다. 서버가 죽지는 안습니다..
다만
A에서 send로 넘겨주는 데이터 중에서 B서버의 똑 같은ip 와 port 번호를 넘겨주면 B서버의 클라이언트 부분에서 새로운 socket을 만들때 무한이 많은 fork를 생성해버립니다.
소켓생성시 자신의 포트하고 아이피가 중복이 되서 그런거 같은데 그러면 connect에서 에러가 발생하니까 멈줘야 하는데 그러지 않네요.....
그래서 쪼금 많이 포크 하고 나면 나중에서 시스템에서 알아서 처리해줍니다.
A -->send(data+ 192.168.0.60+60000 192.168.0.61+60001)
B의 아이피와 포트번호는 192.168.0.60 60000 입니다.
이경우 A로부터의 데이터가B의 아이피랑 포트번호가 같기때문에
B의 클라이언트 기능중에서 소켓을 다시 생성할때 충돌이 일어나는거 같습니다.
그래서 에러처리를 했서 잡기는 했는데....조금 이상하네요.
댓글 달기