[급질문] 아주 돌아버리겠습니다.

leolo의 이미지

제가 UDP 서버를 하나 돌리고 있습니다.
이 서버에는 최대 삼천개 정도의 클라이언트가 붙습니다.
하지만, 아래 상황은 약 30개만 붙어도 이런 경우가 생겼습니다.

UDP 서버의 프로그램 구성은 이렇습니다.

스레드1 : 서버가 클라이언트로 부터 데이터를 받으면, queue에 바로 넣습니다.
스레드2 : queue 정보를 pop하고 가공하여 DB에 클라이언트의 IP와 기타 정보를 insert합니다.
스레드3 : 다른 내부 프로세스로 부터 정보를 받아 DB의 클라이언트의 IP로 관련 정보를 보냅니다.

간단히 설명 드리면 이러한 구조입니다.
문제는 어느 순간 클라이언트가 접속하면 접속이 안됩니다.
문제는 보시면 제 UDP 서버가 9097 포트를 열고 있는데요.
netstate -l 해서 보시면,
udp 261856 0 localhost:10008 *:*
라인처럼 Recv-Q 가 full이 되어버립니다. 왜. 이렇게 되는지 모르겠습니다.
저는 recvfrom해서 데이터 얻고, 바로 queue에 넣기 때문에 문제 없을 것으로 판단이 되는데요.

또한, 제 서버는 9097 포트로 데이터를 받는데요. 프로세스를 실행시키면, *:9097 뿐만 아니라, localhost:10008 도 같이 나타나는데.. 이건 무슨 의미인지요?

좀 두서 없더라고 답변 꼭 부탁드립니다...


[ering@localhost ering]$ netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 localhost:32768         *:*                     LISTEN
tcp        0      0 *:2244                  *:*                     LISTEN
tcp        0      0 localhost:8005          *:*                     LISTEN
tcp        0      0 *:8009                  *:*                     LISTEN
tcp        0      0 *:mysql                 *:*                     LISTEN
tcp        0      0 *:sunrpc                *:*                     LISTEN
tcp        0      0 *:webcache              *:*                     LISTEN
tcp        0      0 *:http                  *:*                     LISTEN
tcp        0      0 *:ftp                   *:*                     LISTEN
tcp        0      0 *:ssh                   *:*                     LISTEN
tcp        0      0 *:telnet                *:*                     LISTEN
udp        0      0 *:9097                  *:*
udp        0      0 localhost:10001         *:*
udp        0      0 localhost:10002         *:*
udp        0      0 localhost:10003         *:*
udp        0      0 localhost:10004         *:*
udp        0      0 localhost:10005         *:*
udp        0      0 localhost:10006         *:*
udp        0      0 localhost:10007         *:*
udp   261856      0 localhost:10008         *:*
udp        0      0 localhost:10009         *:*
udp        0      0 *:sunrpc                *:*
Active UNIX domain sockets (only servers)


fromdj의 이미지

9097 은 현재 UDP 로 서버로서 대기하고 있는 포트이구요
나머지는 클라이언트들이 붙으면서 순간적으로 열리는 포트일껍니다.
제 생각엔 코드조각을 좀 보여주셔야 단서를 잡겠네요

^^ be cool ~
http://fromdj.pe.kr

leolo의 이미지

첫번째 쓰레드 queue에 넣는 부분..


    while(is_running)
    {
        FD_ZERO(&read_fd);
        FD_SET(sock, &read_fd);
        maxfd = MAX(maxfd, sock);

        memset(recvBuf, 0x00, sizeof(recvBuf));
        result = select(maxfd + 1, &read_fd, NULL, NULL, NULL);
        if(result < 0)
        {
            if(errno != EINTR)
             {
             }
             continue;
        }

        if(FD_ISSET(sock, &read_fd))
        {
            if((rc = recvfrom(sock, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&svr_host.adr, &si)) < 0)
            {
                
            }
            memset(&smessage, 0x00, sizeof(smessage));
            memcpy(&smessage, recvBuf, sizeof(smessage));

            qs = queue_push(g_recv_queue, &smessage, sizeof(smessage));
            if(qs != QUEUE_SUCCESS)
            {
            .....

큐에 들어간 메시지를 팝해서 처리함.

    while(is_running)
    {
        r = queue_pop(g_recv_queue, buf, 1);
        if(r == QUEUE_EMPTY)
            continue;

        msg = (msghd *)buf;
        switch(ntohl(msg->type))
        {
            case REQ_CLI_LOGIN :
                   memset(query, 0x00, sizeof(query));
                   sprintf(query, "INSERT INTO MESS_CLIENT_INFO (PHONE, IP, FORWARD) VALUES('%s', '%s', %d)", login_req->phone,
                            inet_ntoa(svr_host.adr.sin_addr), ntohl(login_req->forward));
                   if((ret = insert_mysql(query)) == K_SUCCESS)
                            send_login_res(svr_host.sock, ntohl(login_req->idx), 0x01);  // LOGIN 성공.
                  .................

다른 프로세스에서 데이터 받아 클라이언트로 전송함.

    while(is_running)
    {
        memset(packet, 0x00, sizeof(packet));
        rc = comm_recv(m_mess_transport, packet, sizeof(packet), 1000);
        if(rc <= 0)
        {
            if(rc != EPE_TIMEOUT)
            {
                continue;
            }
        }
        else
        {
            pheader  = (pointheader *)packet;
            switch(ntohl(pheader->msgid))
            {
                case REQ_MESS_ANI_INFO :
                    {
                        ANI_INFO_REQ *ani_req = (ANI_INFO_REQ *)packet;
                        if(svr_host.sock > 0)   // 서버 socket이 살아있음.
                        {
                         .... 클라이언트에게 메세지 보냄..

실력이 있으면 삶이 편하다... 영차 영차...

leolo의 이미지

현재 고려한 부분은 굳이 UDP이니까. select 없이, 그냥..recvfrom 만 사용해서 blocking 모델로 수정하고 있습니다.

실력이 있으면 삶이 편하다... 영차 영차...

leolo의 이미지

zoocmic wrote:
9097 은 현재 UDP 로 서버로서 대기하고 있는 포트이구요
나머지는 클라이언트들이 붙으면서 순간적으로 열리는 포트일껍니다.
제 생각엔 코드조각을 좀 보여주셔야 단서를 잡겠네요

그런데요. UDP 서버 프로그램을 수행하면 바로 localhost:10008 가 나옵니다. 죽이면 없어지고요.. 물론 9097 라인도 마찬가지 입니다.

[ering@localhost mess]$ netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:32768 *:* LISTEN
tcp 0 0 localhost:32769 *:* LISTEN
tcp 0 0 *:2244 *:* LISTEN
tcp 0 0 localhost:8005 *:* LISTEN
tcp 0 0 *:8009 *:* LISTEN
tcp 0 0 *:mysql *:* LISTEN
tcp 0 0 *:sunrpc *:* LISTEN
tcp 0 0 *:webcache *:* LISTEN
tcp 0 0 *:http *:* LISTEN
tcp 0 0 *:ftp *:* LISTEN
tcp 0 0 *:ssh *:* LISTEN
tcp 0 0 localhost:ipp *:* LISTEN
tcp 0 0 *:telnet *:* LISTEN
tcp 0 0 localhost:smtp *:* LISTEN
udp 0 0 *:32768 *:*
udp 0 0 *:9097 *:*
udp 0 0 localhost:10008 *:*
udp 0 0 *:sunrpc *:*
udp 0 0 *:758 *:*
udp 0 0 *:631 *:*

실력이 있으면 삶이 편하다... 영차 영차...

codebank의 이미지

잘 알지는 못하지만... maxfd의 값을 한번 printf를 이용해서 찍어보세요.
그것과 관련있을듯 한데...
FD_ISSET이후에 accept를 한후에 그 소켓값을 close해야 다른 client가 사용할
포트가 생깁니다.(잘 아시겠지만요...)
알아서 소켓을 닫아주는건 프로그램이 끝날때 하는일이고(물론 그 이후 얼마까지는
해당 포트에 접근하지도 못하지만요...)

혹시 30여개의 client만 붙고나면 다른 client가 붙지 않는 이유가 close를 지정하지
않아서 일까해서 적어봤습니다.

(근거는
http://www.cis.ksu.edu/~singh/CIS725/Fall99/programs/sock_ipc_tut.html

tut7.c정도가 될듯하네요. :oops: )

------------------------------
좋은 하루 되세요.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.