(소켓관련)udp에서 select 함수를 어떻게 사용해야 하나요?

sonjae318의 이미지

여기 저기 검색을 해서 찾아 보면 tcp에 대한 select 사용법만 있더군요

udp와 tcp가 사용법이 같은건가요?

tcp방식은 accept할때 마다 소켓디스크립터를 증가 시켜주는데 비해

udp방식은 하나의 소켓디스크립터를 사용하기 때문에

select함수 사용을 어떻게 해야 할지 도무지 감이 안옵니다.

제가 지금 p2p 프로그램을 짜려고 하는데

udp로 select + thread로 구현하려고 합니다.

가능한지요?

책을 읽어 봐도 잘 모르겠네요.

그럼 부탁 드려요.

익명 사용자의 이미지

좀알려 주세요 되는지 안되는지 라도...

계속 이것때문에 진행이 안되고 있네요

따른일도 손에 안잡히고

그럼 부탁드려요.

bugiii의 이미지

udp 는 그 패킷의 크기를 받을 때 이미 알 수 있고 상태가 없기 때문에 대부분 루프 반복문으로도 충분히 쓸만해서 그런지 select 예제가 좀 없는 것 같습니다. unp 책에 보면 udp 와 tcp 를 같이 서비스하는 에코 서버 예제가 있었던 걸로 기억합니다. 한번 참고해보세요.

pynoos의 이미지

소스를 올려주시죠? :)

select는 기본적으로 둘 이상의 작업을 동시에 하고자할 때 사용하는 것입니다.
그런 상황이 아니라면 그냥 recvfrom 으로 대기하고있어도 아무 문제없을 것 같군요.

yeppiguy의 이미지

udp와 tcp와 select사용법은 동일합니다.
select하고 recvfrom으로 수신하시면 됩니다.
2개이상의 소켓을 쳐다보기 위한 건가요?
하나의 소켓과 다른 이벤트를 번갈아 가면서 처리하기 위함인가요?
TCP보다는 훨씬 단순하게 코딩하시면 됩니다.(물론 에러처리는 다릅니다)
단, UDP는 한번에 수신하기 때문에 버퍼 사이즈를 잘 고려하셔야 합니다.

sonjae318의 이미지

yeppiguy wrote:
udp와 tcp와 select사용법은 동일합니다.
select하고 recvfrom으로 수신하시면 됩니다.
2개이상의 소켓을 쳐다보기 위한 건가요?
하나의 소켓과 다른 이벤트를 번갈아 가면서 처리하기 위함인가요?
TCP보다는 훨씬 단순하게 코딩하시면 됩니다.(물론 에러처리는 다릅니다)
단, UDP는 한번에 수신하기 때문에 버퍼 사이즈를 잘 고려하셔야 합니다.

지금 서버에서 클라이언트에게 검색단어를 recvfrom 하고 다른 클라이언트에게
그 단어를 sendto 해준후 그 클라이언트 이외에 클라이언트들에게 다시 확인 결과를 server에서 recvfrom해줘 검색요청을 한 클라이언트에게 결과를
sendto해주려고 합니다.

방법이 똑같이 select 를 사용한다는 걸 잘 이해를 못하겠네요.

소스동봉 합니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
 
#define BUFSIZE 100
void error_handling(char *message);
 
int main(int argc, char **argv)
{
  int serv_sock;
  struct sockaddr_in serv_addr;
 
  fd_set reads, temps;
  int fd_max;
   
  char message[BUFSIZE];
  int str_len;
  struct timeval timeout;
 
  if(argc!=2){
    printf("Usage : %s <port>\n", argv[0]);
    exit(1);
  }
 
  serv_sock = socket(PF_INET, SOCK_STREAM, 0);
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(atoi(argv[1]));
 
  if(bind(serv_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)))
    error_handling("bind() error");
  if(listen(serv_sock, 5)==-1)
    error_handling("listen() error");
   
  FD_ZERO(&reads);
  FD_SET(serv_sock, &reads);
  fd_max=serv_sock;
 
  while(1)
  {
    int fd, str_len;
    int clnt_sock, clnt_len;
    struct sockaddr_in clnt_addr;

 
    temps=reads;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
     
    if(select(fd_max+1, &temps, 0, 0, &timeout)==-1)
                error_handling("select() error");
 

    for(fd=0; fd<fd_max+1; fd++)
    {
            printf("fd=%d\n",fd);
      if(FD_ISSET(fd, &temps))
      {
---------------------------------------------------------
                if(fd==serv_sock) { /* 연결 요청인 경우 */

                  clnt_len = sizeof(clnt_addr);
                  clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_len);
                  FD_SET(clnt_sock, &reads);
                  if(fd_max<clnt_sock)

                    fd_max=clnt_sock;
                  printf("클라이언트 연결 : 파일 디스크립터 %d max= %d\n", clnt_sock,fd_max);
                }
                else {

                  str_len = read(fd, message, BUFSIZE);

                  if(str_len ==0){ /* 연결 종료 요청인 경우 */

                    FD_CLR(fd, &reads);
                    close(fd);
                    printf("클라이언트 종료 : 파일 디스크립터 %d max= %d\n", fd,fd_max);
                  }
                  else{
                    printf("9\n");
                    write(fd, message, str_len);
                  }
                }
      } //if(FD_ISSET(fd, &temps))
-----------------------------------------------------------
    } //for(fd=0; fd<fd_max+1; fd++)
  } //while(1)
}
 
void error_handling(char *message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}

위에 점선으로 된 부분이 tcp로 사용하는 부분인데 udp로 처리해 주려면

어떻게 해야 할지 감이 안잡히네요.

tcp경우 클라이언트 소켓이 accept될때마다 디스크립터가 1씩증가해서

for문에서 0부터 각 소켓까지 반복하면서 각 클라이언트를 감시하는데

udp에서는 각 소켓이 하나로 동일 하므로 어떻게 각 클라이언트를 감시해야

할지 모르겠네요.

그럼 조언 부탁 드립니다.

leilei의 이미지

위 소스 정도라면 그냥 select 없이 사용하시면 될 것 같네요....

보통 UDP는 accept 없이 recvfrom()에서 메세지의 원주소가 채워져 있습니다.
그 주소로 sendto()하시면 되겠죠..

자세한건 unp 등이나 맨페이지 정도 참고 하시면 될 것 같습니다..

익명 사용자의 이미지

예전에 저도 UDP와 pthread를 사용할려고 한적이 있었습니다. 그래서 google에서 UDP에서 pthread 관련된 글을 찾아 보았는데..

결론은, UDP에서는 thread를 쓸 필요가 없다라고 하더군요..

그 사이트를 찾아 볼려고 했는데, 못 찾겠네요...

익명사용자의 이미지

Quote:

예전에 저도 UDP와 pthread를 사용할려고 한적이 있었습니다. 그래서 google에서 UDP에서 pthread 관련된 글을 찾아 보았는데..
결론은, UDP에서는 thread를 쓸 필요가 없다라고 하더군요..
그 사이트를 찾아 볼려고 했는데, 못 찾겠네요...

이부분에 관심이 많습니다. 관련 정보주시면 좋겠습니다.

vuccell의 이미지

udp/tcp에 대해 잘 모르는 사람입니다만..

모르면서도 소스는 있어서.. 그냥 흉내내기로.. 복사한다지요.. 제가 가지고 있는 둘사이의 원칙은 한가지입니다.

정확하고 다양한 서비스를 할때는 TCP,
간단하고 빠른 서비스를 할때는 UDP

UDP socket을 물고 있는 멀티프로세스든 멀티쓰레드든 하나의 프로세스가 있으면, UDP connection을 맺은 이후에 동작하는 것은 아주 간단한 경우에만 씁니다.

즉, connect -- 100바이트 받기 -- 16바이트 주기 -- 100바이트 받기 끝...

이런경우죠... 받은 바이트에 따라서.. 이게 제대로된 데이터다 아니다.. 그딴걸 고려해야 된다면, UDP를 잘 사용하지 않습니다. 구체적인 다른예를 든다면, 시간서비스를 하는 것이라면, UDP가 적절하다고 생각합니다.

프로토콜로 보자면..
"몇시야" "10시 25분 30초" "끝"

이죠.... 더군다나.. "몇시야?"라고 조차도 묻지 않고,
connection하고 바로 recvFrom 해버리는 경우가 많죠.. 그리고 끝

TCP는 이보다 복잡한 경우에 사용합니다.
WEB서버의 예를 들자면,
CONNECTION - HEADER가 뭐니? - HEADER는 이거야! - 아 이미지 파일이구나 보내줘 - 였다 받아라 - 잘 받았음...

여기서 이미지 파일이냐, HTML파일이냐, TXT냐에 따라서 웹브라우저는 다른 프로그램을 해야합니다.

이런경우엔 tcp를 쓰는것이지요...

udp를 쓰든 tcp를 쓰든간에 어느것이든 다 구현이 가능하기는 합니다만... 직접 써보면.. 이런 기준으로 코딩하는 것도 나쁘지 않다고 봅니다. tcp는 보통 데이터를 주고 받을때 잘 받았다는 프로토콜을 끼어넣게 되니... 좀 더 정확하다고 할수는 있겠지요..

udp도 recvFrom으로 받은 데이터에 따라서 그 다음 알고리즘을 정할수 있으니 불가능하지는 않지만.... 암튼 그렇게 짤려면 좀 불편하다는 생각입니다.

sonjae318의 이미지

leilei wrote:
위 소스 정도라면 그냥 select 없이 사용하시면 될 것 같네요....

보통 UDP는 accept 없이 recvfrom()에서 메세지의 원주소가 채워져 있습니다.
그 주소로 sendto()하시면 되겠죠..

자세한건 unp 등이나 맨페이지 정도 참고 하시면 될 것 같습니다..

지금 제가 p2p 프로그램을 하려고 하는데 서버에서 A라는 클라이언트가 검색

요청을하면 서버는 그 검색단어를 서버에 접속되어 있는 모든 클라이언트에게

보내주고 다시 결과가 있는 클라이언트들에게 결과를 받아서 다시 A클라이언

트에게 결과를 보내 줘야하는데 그냥 sendto() 명령어 가지고는 안될꺼 같은

데요. 그래서 생각한게 select함수나 스레드를 이용하려고 하는 이유입니다.

각각의 작업이 각각 동작을 해야 하기 때문에요.

p2p 프로그래밍 해보신 분들 있으시면 도움좀 부탁 바라겠습니다.

그럼 답변들 감사 드려요.

datamind의 이미지

TCP 의 fd 는 MY IP, PORT and PEER IP, PORT 로 구성이 되어 있어서,
accept 하면, 새로운 fd 가 생기고 위 정보를 가지고 들어오는 패킷을 검사해서
fd 로 던져 주게 되어 있지만,
UDP 의 경우는 MY IP 와 PORT 만을 가지고 있어서, fd 를 bind 를 하면
들어오는 패킷은 해당 fd 로 던져 주게 됩니다.
그러므로, 각 클라이언트 마다 다른 fd 를 사용하고자 한다면,
각각마다 다른 PORT 를 사용해서 fd 를 bind 해서 사용해야 합니다.
그리고, UDP 를 select 한다음에 recv 하는게 효율이 좋다구 하네요...

댓글 달기

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