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을 닦아주는 부분을 추가해야 할 듯 합니다.
댓글 달기