[몇일째 흑흑 도와주세요] socket 프로그램에서...

살자의 이미지

select를 이용하여 간단한 메아리 서버를 만들었습니다.
하지만 클라이언트와 종료시 문제점이 있습니다.
클라이언트 하나만 연결시에는 괜찮지만 둘이상일때는 :
1 A클라이언트 접속 이상 무
2 B클라이언트 접속 이상 무
3.A클라이언트 종료 --> 이때 문제점이 발생 합니다.
문제점은 아직 연결되어 있는 B클라이언트가 입력을 하면 서버로 전송이 되지 않습니다. 하지만 A클라이언트가 다시 접속하면 그전에 B클라이언트가 전송하려다 실패한 메세지가 이때 전달됩니다.

그리고 클라이언트 접속 하고 종료한 만큼 TIME_WAIT가 생김니다.
제가 알기로는 금방 TIME_WAIT상태에서 없어져야 하는데 몇분후에야 없어짐니다. 밑에 내용은 4개의 클라이언트가 접속후 종료한 상태 입니다.

bash-2.03$ netstat -a | grep 7894
*.7894 *.* 0 0 24576 0 LISTEN
crs.35319 crs.7894 32768 0 32768 0 TIME_WAIT
crs.35320 crs.7894 32768 0 32768 0 TIME_WAIT
crs.35321 crs.7894 32768 0 32768 0 TIME_WAIT
crs.35322 crs.7894 32768 0 32768 0 TIME_WAIT
---- 서버 ----------

int main(int argc,char *argv[])
{
        int i,listenfd,connfd,sockfd;
        int maxfd,maxi,n,j;
        int nready,clilen,client[FD_SETSIZE];
        fd_set rset,allset;
        char buf[MAXSIZE];

        struct sockaddr_in cliaddr,servaddr;

        if((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        {
                perror("Can not open socket");
                exit(1);
        }

        bzero((char *)&servaddr,sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(PORT);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

        if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0)
        {
                perror("error bind");
                exit(1);
        }

        if(listen(listenfd,WQUEUE) < 0)
        {
                perror("error listen");
                exit(1);
        }

        maxfd = listenfd;
        maxi = -1;
        for(i = 0;i < FD_SETSIZE;i++) client[i] = -1;
        FD_ZERO(&allset);
        FD_SET(listenfd,&allset);

        for(;;)
        {
                rset = allset;          /*allset에서 설정된 bit를 rset으로 넘겨준다.*/
                nready = select(maxfd + 1,&rset,NULL,NULL,NULL); /* return value */

                if(FD_ISSET(listenfd,&rset))    /* client connection */
                {
                        clilen = sizeof(cliaddr);
                        if((connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen)) < 0)
                        {
                                perror("error accept");
                                exit(1);
                        }

                        printf("connection clientt.... \n");
                        for(i = 0;i < FD_SETSIZE;i++)
                        {
                                if(client[i] < 0)
                                {
                                        client[i] = connfd;
                                        break;
                                }
                        }

                        if(i == FD_SETSIZE) perror("too many clients");
                        FD_SET(connfd,&allset);
                        if(connfd > maxfd) maxfd = connfd;
                        if(i > maxi) maxi = i;
                }
                for(i = 0;i <= maxi;i++) /* request client search */
                {
                        if((sockfd = client[i]) < 0) continue;
                        if(FD_ISSET(sockfd,&rset))      /* client communication */
                        {
                                switch((n = recv(sockfd,buf,MAXSIZE,0)))
                                {
                                        case -1:
                                        case  0: close(sockfd);
                                                 FD_CLR(sockfd,&rset);
                                                 client[i] -1;
                                                 break;

                                        default : printf("Recv Message : %s , Size : %d byte\n",buf,n);
                                                  n = send(sockfd,buf,n,0);
                                                  printf("Send Message : %s , Size : %d byte\n",buf,n);

                                }
                        }
                }
        }
}

-------클라이언트---------------------------------

int main(int argc,char *argv[])
{
        int serverfd,maxfd;
        struct sockaddr_in server;
        fd_set rset;
        char buf[MAXSIZE];
        int stdineof,n,ch; /* stdineof is check EOF of file*/

        if((serverfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        {
                perror("can not open socket");
                exit(1);
        }

        bzero((char *)&server,sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(PORT);
        server.sin_addr.s_addr = inet_addr(argv[1]);

        if(connect(serverfd,(struct sockaddr *)&server,sizeof(server)) < 0)
        {
                perror("error connect :");
                exit(1);
        }

        maxfd = serverfd;
        FD_ZERO(&rset);
        stdineof = 0;
        while(1)
        {
                if(stdineof == 0) FD_SET(fileno(stdin),&rset); /*file not EOF*/
                FD_SET(serverfd,&rset);

                if(!select(maxfd +1,&rset,NULL,NULL,NULL))
                {
                        perror("error select");
                        exit(1);
                }
 if(FD_ISSET(serverfd,&rset))
                {
                        int n;
                        if((n = recv(serverfd,buf,MAXSIZE,0)) <= 0)
                        {
                                if(stdineof == 1) return 0;
                                else
                                {
                                        perror("error recv");
                                        exit(1);
                                }
                        }
                        printf("recv message from server: %s ,size = %d\n",buf,n);

                }
                if(FD_ISSET(fileno(stdin),&rset))
                {
                        n = 0;
                        while((ch = getchar()) != '\n') *(buf + n++) = ch;
                        *(buf + n) = '\0';
                        if(!strlen(buf)) /* if file EOF */
                        {
                                stdineof = 1; /* file EOF */
                                shutdown(serverfd,SHUT_WR); /* close write */
                                FD_CLR(fileno(stdin),&rset);
                                continue;
                        }
                        else
                        {
                                n = send(serverfd,buf,strlen(buf)+1,0);
                                printf("send date %s, size = %d\n",buf,n);
                        }
                }
        }
}
xfmulder의 이미지

select 하기위해서 FD_ZERO ,FD_SET 등의 초기화는 for(;;) 안에서 매번 하세요.

아참, printf 를 믿지마세요. 화면에 바로 뿌리지 않고 버퍼링 됩니다.

printf("메세지\n"); 한 후 즉시 flush(stdout); 처럼 곧바로 내용을 화면에 뿌리도록 하시든지...

내 자식들도 나처럼 !!

cjy1126의 이미지

printf는 line buffering이기때문에 메세지 마지막에 '\n'가 있다면 fflush(stdout); 가 필요없는걸로 압니다.

낙엽의 이미지

Quote:
printf는 line buffering이기때문에 메세지 마지막에 '\n'가 있다면 fflush(stdout); 가 필요없는걸로 압니다.

unix 에서는 개행문자가 있더라도 해줘야 할 때가 있더군요..

towngo의 이미지

서버에서 소켓을 close 하실때

case  0: close(sockfd); 
        FD_CLR(sockfd,&rset); 
        client[i] -1; 
        break; 

이 부분을..

 case  0: 
            close(sockfd); 
            FD_CLR(sockfd,&allset); 
            client[i] = -1; 
            break; 

이렇게 바꿔 주세요.. :wink:
잠시 fd set 을 혼동하셨나보네욤..

Dr_stein의 이미지

printf로 디버깅 하실려면.. setbuf(stdout, 0);
이걸 사용해 보시는것도 괜찮을꺼 같네요.

앞마당 먹고 시작한 저그의 8할은 뮤탈 테크를 먼저 탄다. 하지만 나머지 2할때문에 항상 스켄이 모자란다. - _-;

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.