named pipe의 packet loss 현상에 대한 질문입니다.
글쓴이: jazzbluey / 작성시간: 금, 2008/10/31 - 1:47오후
pipe로 server와 client를 구성하여 string을 연속하여 send 합니다.
이경우,
1. client의 packet이 server에 전달되지 못하고 loss되는 경우가 발생
2. 일정 갯수의 packet을 send하던 cliant는 sigpipe가 발생하여 죽음
왜 이런 현상이 생기는지 알수 있는 분이 계시다면 한수 가르침을 청합니다.
환경은 HP itanium 11.23 입니다.
<<<서버측 화면>>> realread is 8 Serv : fdkjal-1, 8 realread is 8 Serv : fdkjal-7, 8 realread is 0 Serv : , 0
<<<클라이언트측 화면>>>
send string :8
send string :fdkjal-1
send string :8
send string :fdkjal-2
send string :8
send string :fdkjal-3
send string :8
send string :fdkjal-4
send string :8
send string :fdkjal-5
send string :8
send string :fdkjal-6
send string :8
send string :fdkjal-7
write` error: Broken pipe
<<< 서버측 소스 >>>
#include <stdio.h> #include <errno.h> #include <ctype.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd, ret_val, count = 0, numread, realread, nready; fd_set rset, allset; char buf[8092]; /* Create the named - pipe */ ret_val = mkfifo("./song", 0666); if ((ret_val == -1) && (errno != EEXIST)) { perror("Error creating the named pipe"); exit (1); } FD_ZERO(&rset); while (1) { count ++; /* Open the pipe for reading */ fd = open("./song", O_RDONLY); if ( fd < 0) { perror("open error"); close(fd); exit(0); } FD_SET(fd, &rset); /* read a number of characters */ nready = select(fd+1, &rset, NULL, NULL, NULL); if ( FD_ISSET(fd, &rset )) { memset(buf, 0x00, 32); numread = read(fd, buf, 32); realread = atoi(buf); printf("realread is %d\n", realread); } else { close(fd); exit(0); } /* Read from the pipe */ nready = select(fd+1, &rset, NULL, NULL, NULL); if ( FD_ISSET(fd, &rset )) { memset(buf, 0x00, realread+1); numread = read(fd, buf, realread); //buf[numread] = '0'; printf("Serv : %s, %d\n", buf, numread); } else { close(fd); exit(0); } close(fd); } }
<< 클라이언트측 소스 >>>
#include <stdio.h> #include <errno.h> #include <ctype.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <sys/socket.h> int main(int argc, char *argv[]) { int fd, wsize = 0, rsize=0, nready, count = 0; char buf[8092]; char sbuf[8092]; fd_set wset; signal(SIGPIPE, SIG_IGN); /* Check if an argument was specified. */ if (argc != 2) { printf("Usage : %s <string to be sent to the server>n", argv[0]); exit (1); } FD_ZERO(&wset); while(1) { /* Open the pipe for writing */ fd = open("./song", O_WRONLY); if (fd < 0) { perror("open error"); close(fd); exit(0); } FD_SET(fd, &wset); count++; memset(sbuf, 0x00, 8092); sprintf(sbuf, "%s-%d", argv[1],count); /* at first you should send a number of write */ memset(buf, 0x00, 32); sprintf(buf, "%d", strlen(sbuf)); nready = select(fd+1, NULL, &wset, NULL, NULL); if ( FD_ISSET(fd, &wset) ) { // rsize = recv(fd, buf, sizeof(buf)-1, MSG_PEEK); // printf ("recv buff size :%d\n", rsize); if ( (wsize = write(fd, buf, 32)) != 32 ) { perror("write` error"); close(fd); exit(0); } } else { perror("FD_ISSET error"); close(fd); exit(0); } printf ("send string :%s\n", buf); /* Write to the pipe */ nready = select(fd+1, NULL, &wset, NULL, NULL); if (FD_ISSET(fd, &wset)) { // rsize = recv(fd, buf, sizeof(buf)-1, MSG_PEEK); // printf ("recv buff size :%d\n", rsize); if ( (wsize = write(fd, sbuf, strlen(sbuf))) != strlen(sbuf)) { perror("write error"); close(fd); exit(0); } } else { perror("FD_ISSET error"); close(fd); exit(0); } printf ("send string :%s\n", sbuf); // usleep(100); close(fd); } }
Forums:
뭔가 좀 거시기 하군요...
대충 살펴보긴 했습니다만, 뭔가 코드가 이상합니다.
뭐 다 이유가 있어서 저렇게 만드셨을 수는 있겠지만, 별로 일반적인 방식은 아닌듯 싶습니다.
1. 보통은 open/close 는 loop 밖에서 하지요. 즉 지금처럼
while (1) {
open
read
...
close
}
가 아니라
open
while (1) {
read
...
}
close
와 같은 식 입니다.
2. 보아하니 blocked I/O인데다 fd도 하나밖에 없는데 select를 사용할 필요가 있나 싶습니다. select 는 보통 nonblocked I/O 로 설정한 뒤 여러 fd에서 오는 입력을 처리하기 위해 사용되지요. (즉 select 없이 바로 read/write 를 사용하시면 된다는 것입니다.)
3. 1, 2 번을 수정하면 상관 없겠습니다만, 그렇지 않다면 해 주셔야 할 것이, loop구문 안에서 FD_ZERO 로 fdset 을 닦아 주어야 합니다. 이전 loop에서 사용한 fd가 fdset 안에 들어가 있을 텐데, 보통은 fd를 close한 후 다시 open을 했으니 reuse를 했을 테고 별 문제가 없겠지만, 만에 하나 fd가 바뀐다면, 이미 close된 fd가 fdset에 남아있게 되고, 그 fd가 문제를 일으킬 수 있습니다. 따라서 위의 코드에서 loop 문 안에 FD_SET을 부르기 직전에 FD_ZERO로 fdset을 닦아주는 부분을 추가해야 할 듯 합니다.
댓글 달기