2011년7월22일_Talk Server & Client SIGALRM 시그널 사용시 문제점, 멀티플렉싱과 select( )의 사용법
● Talk Server & Client SIGALRM 시그널 사용시 문제점 ALARM( )에 설정된 시간이 경과 후 발생한 시그널에 의해 서버와 클라이언트의 블로킹함수들, |
하기의 코드는 심각한 오류가 있으니 절대 실행하지 말 것. ㅎㅎ
● talk_server_pipe.c
1: // talk_server_pipe.c 2: // TCP 1:1 채텅프로그램 3: // 프로세스가 올바르게 종료될 수 있도록 부모/자식 프로세스간 4: // 파이프를 연결하여 종료메시지를 건네준다. 5: // 특징: 서버와 클라이언트간 메시지가 아닌 동기제어신호를 전송함. 6: // read()가 블록이 되지 않으므로 두 가지 장치로 부터 수신가능. 7: // 8: // 작성자: 김수만 9: // 작성일자: 2011년 7월 21일 10: // 수정일자: 2011년 7월 22일 11: #include <stdio.h> 12: #include <string.h> 13: #include <stdlib.h> 14: #include <sys/types.h> 15: #include <signal.h> 16: #include <sys/socket.h> 17: #include <sys/wait.h> 18: #include <netinet/in.h> 19: #include <arpa/inet.h> 20: #include <unistd.h> 21: #include <signal.h> 22:
23: #define MAXLINE 512 24: #define SYNC 1 25:
26: char *escapechar = "exit"; //종료문자열 27: int server_sock; 28: int client_sock; 29: int fd[2]; //파이프 30:
31: void timer(int); //알람 시그널 처리함수 32:
33: int main(int argc, char *argv[]) 34: {
35: int clntlen; 36: int num; 37: char sendline[MAXLINE]; 38: char buffer[MAXLINE]; 39: char recvline[MAXLINE + 1]; 40: int size; 41: pid_t fork_ret;
42: struct sockaddr_in client_addr; 43: struct sockaddr_in server_addr; 44: // signal사용하기 위해 추가된 변수들 45: int state; 46: struct sigaction act; 47:
48: if(argc != 2) 49: {
50: printf("Usage : %s PORT \n", argv[0]); 51: exit(0);
52: }
53:
54: // pipe생성 55: state = pipe(fd);
56: if(-1 == state) 57: {
58: fprintf(stderr, "pipe() error. \n"); 59: exit(1);
60: }
61:
62: // signal설정 63: act.sa_handler = timer;
64: sigemptyset(&act.sa_mask);
65: act.sa_flags = 0;
66:
67: //타이머 이벤트사용 68: if(SIG_ERR == sigaction(SIGALRM, &act, 0)) 69: {
70: fprintf(stderr, "sigaction() error. \n"); 71: exit(1);
72: }
73:
74: // 소켓 생성 75: if((server_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) 76: {
77: printf("Server: can't open stream socket. \n"); 78: exit(0);
79: }
80:
81: // 소켓주소 구조체에 주소 세팅 82: bzero((char *)&server_addr, sizeof(server_addr)); //소켓주소 구조체 초기화 83: server_addr.sin_family = AF_INET;
84: server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
85: server_addr.sin_port = htons(atoi(argv[1]));
86:
87: // 소켓에 서버 주소 연결 88: if(bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 89: {
90: printf("Server: can't bind local address. \n"); 91: exit(0);
92: }
93:
94: printf("Server started. \nWaiting for client..\n"); 95: listen(server_sock, 1);
96:
97: // 클라이언트의 연결요청 수락 98: clntlen = sizeof(client_addr); 99: if((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &clntlen)) < 0) 100: {
101: printf("Server: failed in acceptiong. \n"); 102: exit(0);
103: }
104:
105: alarm(1); //1초 후에 알람시그널 발생 106: sleep(1);
107: fork_ret = fork();
108: if(-1 == fork_ret) 109: {
110: fprintf(stderr, "fork() error\n"); 111: exit(1);
112: }
113:
114: if(0 < fork_ret) 115: {
116: // 부모 프로세스는 키보드 입력을 클라이언트로 송신 117: while(1) 118: {
119: fgets(sendline, MAXLINE, stdin);
120: strcpy(buffer, "수만 : "); 121: strcat(buffer, sendline);
122: size = strlen(buffer);
123: if(write(client_sock, buffer, strlen(buffer)) != size) 124: {
125: printf("Error in write. \n"); 126: }
127:
128: if(strstr(sendline, escapechar) != NULL) //종료문자열 입력시 처리 129: {
130: printf("Good bye. \n"); 131: close(client_sock);
132: write(fd[1], escapechar, sizeof(escapechar)); 133: sleep(3); //3초 후 종료 134: waitpid(-1, &state, WNOHANG); // wait()를 쓰면 더 좋음. 135: printf("부모프로세스 종료!\n"); 136: break; 137: }
138: }
139: }
140: else if(0 == fork_ret) 141: {
142: // 자식 프로세스는 클라이언트로부터 수신된 메시지를 화면에 출력 143: while(1) 144: {
145: // 클라이언트 -> 서버 146: if((size = read(client_sock, recvline, MAXLINE)) < 0) 147: {
148: printf("Error if read. \n"); 149: close(client_sock);
150: printf("자식프로세스 종료! - 1\n"); 151: exit(0);
152: }
153:
154: recvline[size] = '\0'; 155:
156: if(strstr(recvline, escapechar) != NULL) //종료문자열 입력시 처리 157: {
158: printf("자식프로세스 종료! - 2\n"); 159: break; 160: }
161: else if(SYNC == recvline[0]) //동기신호 162: {
163: // 아무 일도 하지 않음 164: }
165: else 166: {
167: printf("%s", recvline); //화면 출력 168: }
169:
170: // 자식 <- 부모 171: if((size = read(fd[0], recvline, MAXLINE)) < 0) 172: {
173: printf("Error if read. \n"); 174: close(client_sock);
175: printf("자식프로세스 종료! - 3\n"); 176: exit(0);
177: }
178:
179: recvline[size] = '\0'; 180:
181: if(strstr(recvline, escapechar) != NULL) //종료문자열 입력시 처리 182: {
183: //클라이언트에게 이스케이프 문자열 전송 184: write(client_sock, escapechar, sizeof(escapechar)); 185: printf("자식프로세스 종료! - 4\n"); 186: break; //자식프로세스 종료 187: }
188: else if(SYNC == recvline[0]) //동기신호 189: {
190: // 아무 일도 하지 않음 191: }
192: else 193: {
194: // 아무 일도 하지 않음. 195: }
196: }
197: }
198:
199: close(server_sock);
200: close(client_sock);
201:
202: printf("서버는 정상종료 되었음!\n"); 203:
204: return 0; 205: }
206:
207: //시그널 처리함수 208: void timer(int sig) 209: {
210: int sync = SYNC; 211:
212: alarm(1); // 타이머 재시작 213:
214: write(fd[1], &sync, 1); // 파이프로 동기신호 발송 215: write(client_sock, &sync, 1); // 클라이언트로 동기신호 발송 216: }
|
● talk_client_pipe.c
1: // talk_client_pipe.c 2: // TCP 1:1 채텅프로그램 3: // 프로세스가 올바르게 종료될 수 있도록 부모/자식 프로세스간 4: // 파이프를 연결하여 종료메시지를 건네준다. 5: // 특징: 서버와 클라이언트간 메시지가 아닌 동기제어신호를 전송함. 6: // read()가 블록이 되지 않으므로 두 가지 장치로 부터 수신가능. 7: // 8: // 작성자: 김수만 9: // 작성일자: 2011년 7월 21일 10: // 수정일자: 2011년 7월 22일 11: #include <stdio.h> 12: #include <string.h> 13: #include <stdlib.h> 14: #include <sys/types.h> 15: #include <signal.h> 16: #include <sys/socket.h> 17: #include <netinet/in.h> 18: #include <arpa/inet.h> 19: #include <sys/wait.h> 20:
21: #define MAXLINE 1024 22: #define SYNC 1 23:
24: char *escapechar = "exit"; //종료문자열 25: int s; 26: int fd[2]; //파이프 27:
28: void timer(int); //알람 시그널 처리함수 29:
30: int main(int argc, char *argv[]) 31: {
32: char line[MAXLINE]; 33: char sendline[MAXLINE]; 34: char recvline[MAXLINE + 1]; 35: char buffer[MAXLINE]; 36: int n; 37: int size; 38: int comp; 39: int addr_size; 40: pid_t fork_ret;
41: static struct sockaddr_in server_addr; 42: // signal사용하기 위해 추가된 변수들 43: int state; 44: struct sigaction act; 45:
46: if(argc != 3) 47: {
48: printf("Usage : ./%s serverIP serverPORT \n", argv[0]); 49: exit(0);
50: }
51:
52: // pipe생성 53: state = pipe(fd);
54: if(-1 == state) 55: {
56: fprintf(stderr, "pipe() error. \n"); 57: exit(1);
58: }
59:
60: // signal설정 61: act.sa_handler = timer;
62: sigemptyset(&act.sa_mask);
63: act.sa_flags = 0;
64:
65: //타이머 이벤트사용 66: if(SIG_ERR == sigaction(SIGALRM, &act, 0)) 67: {
68: fprintf(stderr, "sigaction() error. \n"); 69: exit(1);
70: }
71:
72: if(0 != state) 73: {
74: fprintf(stderr, "sigaction() error. \n"); 75: exit(1);
76: }
77:
78: // 소켓 생성 79: if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) 80: {
81: printf("Client: can't open stream socket. \n"); 82: exit(0);
83: }
84:
85: // 소켓주소 구조체에 주소 세팅 86: bzero((char *)&server_addr, sizeof(server_addr)); //소켓주소 구조체 초기화 87: server_addr.sin_family = AF_INET;
88: server_addr.sin_addr.s_addr = inet_addr(argv[1]);
89: server_addr.sin_port = htons(atoi(argv[2]));
90:
91: // 서버에 연결 요청 92: if(connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 93: {
94: printf("Client: can't connect to server. \n"); 95: exit(0);
96: }
97:
98: alarm(1); //1초 후에 알람시그널 발생 99: sleep(1);
100: fork_ret = fork();
101:
102: if(0 < fork_ret) 103: {
104: // 자식 프로세스는 키보드 입력을 클라이언트로 송신 105: while(1) 106: {
107: fgets(sendline, MAXLINE, stdin);
108: strcpy(buffer, "수만: "); 109: strcat(buffer, sendline);
110: size = strlen(buffer);
111: if(write(s, buffer, strlen(buffer)) != size) 112: {
113: printf("Error in write. \n"); 114: }
115:
116: if(strstr(sendline, escapechar) != NULL) //종료문자열 입력시 처리 117: {
118: printf("Good bye. \n"); 119: close(s);
120: sleep(3); //3초 후 종료 121: waitpid(-1, &state, WNOHANG); // wait()를 쓰면 더 좋음. 122: exit(0);
123: }
124: }
125: }
126: else if(0 == fork_ret) 127: {
128: // 부모 프로세스는 클라이언트로부터 수신된 메시지를 화면에 출력 129: while(1) 130: {
131: if((size = read(s, recvline, MAXLINE)) < 0) 132: {
133: printf("Error if read. \n"); 134: close(s);
135: exit(0);
136: }
137:
138: recvline[size] = '\0'; 139:
140: if(strstr(recvline, escapechar) != NULL) //종료문자열 입력시 처리 141: {
142: break; 143: }
144: else if(SYNC == recvline[0]) //동기신호 145: {
146: // 아무 일도 하지 않음 147: }
148: else 149: {
150: printf("%s", recvline); //화면 출력 151: }
152:
153: // 자식 <- 부모 154: if((size = read(fd[0], recvline, MAXLINE)) < 0) 155: {
156: printf("Error if read. \n"); 157: close(s);
158: exit(0);
159: }
160:
161: recvline[size] = '\0'; 162:
163: if(strstr(recvline, escapechar) != NULL) //종료문자열 입력시 처리 164: {
165: //클라이언트에게 이스케이프 문자열 전송 166: write(s, escapechar, sizeof(escapechar)); 167: break; //자식프로세스 종료 168: }
169: else if(SYNC == recvline[0]) //동기신호 170: {
171: // 아무 일도 하지 않음 172: }
173: else 174: {
175: // 아무 일도 하지 않음 176: }
177: }
178: }
179:
180: close(s);
181:
182: return 0; 183: }
184:
185: //시그널 처리함수 186: void timer(int sig) 187: {
188: int sync = SYNC; 189:
190: alarm(1); // 타이머 재시작 191:
192: write(fd[1], &sync, 1); // 파이프로 동기신호 발송 193: write(s, &sync, 1); // 클라이언트로 동기신호 발송 194:
195: return ; 196: }
|
<실행결과>
'내장형하드웨어 > 일일보고서' 카테고리의 다른 글
2011년7월25일_멀티프로세스와 멀티플렉싱비교, 멀티플렉싱서버를 위한 select( )의 사용법과 다중접속이 가능한 echo서버 (0) | 2011.07.25 |
---|---|
2011년7월25일_숙제 Makefile (20110720_storage) (0) | 2011.07.25 |
2011년7월22일_JAVA class복습과 생성자, 접근제어수식어와 getter/setter (0) | 2011.07.22 |
2011년7월21일_Talk Server & Client TCP소켓통신과 부모프로세스와 자식프로세스간 PIPE 연결(IPC) (0) | 2011.07.22 |
2011년7월21일_JAVA class, 연습문제들 (0) | 2011.07.22 |