timer 구현

andro000의 이미지

안녕하세요

UDP를 사용해 데이터 많은 데이터를 송수신 하려합니다.(실시간영상)
UDP를 사용한 이유는 어디에선가 이런 글을 읽은 기억이 나서 UDP를 사용했습니다.

"그러나 인터넷을 기반으로 실시간 영상 및 음성을 전송하는 경우에는 얘기가 조금 다르다. 멀티미디어 데이터는 그 특성상 일부가 손실이 되어도 크게 문제가 되지 않는다. 잠깐 동안의 화면 떨림 내지는 아주 작은 잡음 정도는 그냥 넘어가 줄만하다. 하지만 실시간 서비스를 해야 하므로 속도는 상당히 중요한 요소가 된다. 이러한 경우가 UDP소켓을 사용해야 하는 좋은 후보가 된다"

그래서 지금까지 UDP를 사용하여 설계하고 코딩을 시작했는데 막히는 부분이 있어서 이렇게 글을 올립니다.

1. 전송하는 소스
Remote에서 원하는 데이터(Video/Audio)를 전송한다.
전송한 패킷(seqnum)에 대해 timer를 설정한다.
전송한 후에 응답을 기다리는데 응답이 정해진 시간내에 오지 않으면 재전송
한다. 그리고 다시 timer를 설정한다.

2. 수신하는 소스
데이터를 수신한다.
수신하면 응답을 전송한다.
원하는 데이터가 오지 않을시 버퍼에 저장해 두고 원하는 데이터에 대한
seqnum을 재전송 요구한다. 그리고 timer를 설정한다.

대강 이런식인데 여기서 "timer" 이 timer를 제작하고 싶습니다. 각 id(sequnece)마다 독립적으로 동작해야 할 것 같으데... 어떻게 하면 좋겠습니까. 답변 부탁드립니다.

avatar80의 이미지

작업을 하시는지 알아야 할꺼 같은데요..
물론 타이머 아이디별로 동작하게 하겠지만..
타이머도 종류가 여러개 있으니까요~
자세한 상황을 말씀해 주세요^^

^^ 함께 커가는 세상

andro000의 이미지

다시 질문드리겠습니다.

그렇니까 tcp 프로토콜에 관한 내용을 보니까 이런 내용이 나오더라구요

timer가 네개정도 있는데(Retransmit, persistence, Keepalive, Time-waited timer) 여기에서 Retransmit timer를 제작하고 싶습니다.

어떤 sequnce번호에 대한 재전송을 한다음 타이머를 걸어 그 시간대에
응답이 오질 않으면 재전송을 다시하고 타이머를 초기화 시키고.. 이런 기능이요

정보 공유 하길 원하는 andro000

mach의 이미지

Quote:
"그러나 인터넷을 기반으로 실시간 영상 및 음성을 전송하는 경우에는 얘기가 조금 다르다. 멀티미디어 데이터는 그 특성상 일부가 손실이 되어도 크게 문제가 되지 않는다. 잠깐 동안의 화면 떨림 내지는 아주 작은 잡음 정도는 그냥 넘어가 줄만하다. 하지만 실시간 서비스를 해야 하므로 속도는 상당히 중요한 요소가 된다. 이러한 경우가 UDP소켓을 사용해야 하는 좋은 후보가 된다"

이 부분에서는 패킷손실을 허가하는 방향을 묘사하고 있습니다.
즉, 패킷이 도달하지 않아도, 재전송하지 않음(또는, 1번이나 아주 작은 재전송시도만을 수행함)에 대한 내용으로 보입니다. 재전송을 최소화(또는 없음)하는 전략이라고 봐야겠지요?

Quote:
1. 전송하는 소스
Remote에서 원하는 데이터(Video/Audio)를 전송한다.
전송한 패킷(seqnum)에 대해 timer를 설정한다.
전송한 후에 응답을 기다리는데 응답이 정해진 시간내에 오지 않으면 재전송
한다. 그리고 다시 timer를 설정한다.

2. 수신하는 소스
데이터를 수신한다.
수신하면 응답을 전송한다.
원하는 데이터가 오지 않을시 버퍼에 저장해 두고 원하는 데이터에 대한
seqnum을 재전송 요구한다. 그리고 timer를 설정한다.


그러나, 님이 제시한, 이 알고리즘에서는 재전송을 수행하는 부분에 대한 언급만이 있습니다. 재전송을 중단하는 전략에 대해서는 언급이 없습니다. 즉, 신뢰성있는전송(reliability)에 대해 기술하고 있습니다. 신뢰성있는 전송이란, 보내면 언젠가는 간다!라는 명제를 구현한 것인데, 즉, 타임아웃걸고 재전송을 반복수행하는 시나리오지요. 이 부분에 대한 참고자료는 Stevens의 Unix Network Programming에서 볼수 있습니다. 책에서 UDP와 Reliable(-ity) 이 두단어를 키워드로 책을 찾아보시면 한개의 Chapter에서 언급과 소스를 볼 수 있습니다. 약간 진보된 UDP라는 부분에 대체로 위치할 것입니다. 정확한 장수를 기억하지 못하네요--; 물론, Stevens의 구현에서는 ARQ방식중 가장 단순한 방법으로 구현되어 있습니다만 공부에는 보탬이 될것입니다..

* 둘다를 만족시키는(님의 목적을 만족하는?) 참조 프로그램으로는 RTP를 추천합니다. RTP는 검색하면 널렸습니다. 참고로 RTP는 바로 UDP상에서 구현한 프로토콜입니다. 님이 구현하고자 하는 프로토콜인듯한데요. 아니면 님이 이의 축소판을 구현하시고자 하는것 같군요. 참고하세요.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

익명 사용자의 이미지

대략 Bitrate를 지키기 위한 패킷과 패킷사이의 delay 계산은
다음과 같은 식이 되겠군요.
delay의 경우 Intel계열에서는 10ms이하의 정확도를 기대하기
어려워서 align 을 하도록 재귀적인 계산이 필요할거 같구요.
그리고 최종적으로 Packet을 쏠때 얼마나 시간이 걸렸는지
gettimeofday를 이용해서 측정하고 계속 그 값을 보정하여
다음 delay에서 +/- 해가면서 시간 보정을 취해야 할겁니다.
정확한 시간을 맞춘다는 것은 좀 어려운 문제지만
보정만 정확히 해준다면 될듯 합니다.

char *s_TempString;
  t_u64 s_Bitrate = 1000000, s_PacketSize = 32768, s_Delay = 10000;
  s_TempString = MZ_SearchArgument(s_Argument, s_Option, 1);
  if(s_TempString)sscanf(s_TempString, "%llu", &s_Bitrate);
  s_TempString = MZ_SearchArgument(s_Argument, s_Option, 2);
  if(s_TempString)sscanf(s_TempString, "%llu", &s_PacketSize);
  L_ReCalc:;
  s_Delay = (s_PacketSize * 8000000llu) / s_Bitrate;
  fprintf(stdout, "Bitrate=%llu, PacketSize=%llu, Delay=%llu\n", s_Bitrate, s_PacketSize, s_Delay);
  if(s_Delay % 10000llu)
  {
   s_PacketSize ;
   goto L_ReCalc;
  }
  if( s_Delay < 40000llu )
  {
   s_PacketSize ;//s_PacketSize = (s_Delay * s_Bitrate) / 8000000llu;
   goto L_ReCalc;
  }
  if( s_Delay > 1000000llu )
  {
   s_PacketSize--; //s_PacketSize = (s_Delay * s_Bitrate) / 8000000llu;
   goto L_ReCalc;
  }
 }

대충 다음과 같은 구성이 되겠군요.

delay = 위에예제로 써둔 delay구하는 공식;
do
{
  gettimeofday( &시간1 );
   do
   {
    Sendto( ... );
   }while( 패킷이 보내질때까지 );
  gettimeofday( &시간2 );
  시간3 = 시간2 - 시간1;
   delay( 지연시간 - 시간3);
}while( 다보낼동안 );

위에서 delay 를 위한 함수로는 usleep 보다는
아래처럼 select 를 이용한 지연을 추천하겠습니다.

void MZ_uSleep(int s_uSec) 
{ 
 struct timeval s_TimeVal; 
 if(s_uSec > 1000000) /* uSec의 큰 값은 초단위로 환산 */ 
 { 
  s_TimeVal.tv_sec = s_uSec / 1000000; 
  s_uSec %= 1000000; 
 } 
 else s_TimeVal.tv_sec = 0; 
 s_TimeVal.tv_usec = s_uSec; 
 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &s_TimeVal); 
} 

예전에 이런거 해본적이 있는데 골치 무지 아프던데...
꼭 이런거 구현하실려구요?

익명 사용자의 이미지

andro000 wrote:
전송한 후에 응답을 기다리는데 응답이 정해진 시간내에 오지 않으면 재전송 한다.

패킷을 보낸후 응답을 기다리는 것은 좀 깊이 생각해 보실것을
권하고 싶네요.

거리가 멀수록 그 응답 시간이 엄청나게 느려질수 있겠는데
그러면 Stream이 끊기지 않을까요?
차라리 완벽한 Packet전송보다는 그냥 상대방이 받겠거니 하고
꾸준히 보내는데 보다 중점을 두어야 할거 같다는 의견 적어봅니다.

응답때문에 영상이 끊기는것보다 중간에 Loss나서 영상이 끊기는것이
좀 더 낳을듯 합니다.

garuna의 이미지

UDP 는 아시다시피 전송의 신뢰성을 보장해주지 않습니다. 처음부터 UDP 를 고려했다면, 재전송은 없다는 상황이라고 생각합니다.

인용하신 글 그대로, 중간에 패킷이 사라진다하더라도 멀티미디어 서비스에서는 큰 문제가 아니므로, 재전송 로직은 필요없다고 생각합니다.

그리고, 경험적으로 생각보다 UDP 가 패킷을 잃어버리는 경우는 극히 드물더군요... (물론 멀티미디어 서비스를 하진 않았습니다만...)

익명 사용자의 이미지

경험적으로 생각보다 UDP 가 패킷을 잃어버리는 경우는 극히 드물더군요

정말로 극히 적습니다.
하지만 다음과 같은 경우 Loss율이 엄청 높아진다는 것을 학습하는게
매우 중요한거 같습니다.

1. 한번에 보내는 Packet size가 너무 큰경우
(통상 32KByte 미만을 추천할께요.)

2. Packet과 Packet사이에 delay가 전혀 없이 전송될경우
(상황에 따라 다르겠지만 적어도 20ms이상을 delay를 주시는것이
멀리갈겁니다.)

3. TTL을 짧게 준 경우
(설명이 필요없는 실수중의 실수. 적어도 망의 구성을 살피세요.)
(너무 크게 주면 주변의 시선이 따가우니 라우터의 갯수를 고려한
적당량의 수치를 주세요. 이건 뭐라 할수 없고 그냥 해보고 결정하는...)

4. 받는쪽에서 해당 bitrate를 감당하지 못할정도로 처리할때.
(버퍼링 로직이 잘못되서 고생한적이 있다는 경험에 비추어서...)

위경우는 Loss를 증가시키는 원인이 좀 될겁니다.
이것만 고려한다면 안정성이 상당히 확보될거라 생각합니다.
혹시 제가 생각 못한것이 또 있을까요? 있으면 계속 리플요망.

andro000의 이미지

답글 정말 감사합니다.

한 번에 전송하는 사이즈는 지금 테스트로 40KB씩 보내고 있습니다.
무턱대고 40KB씩 보내니 받는 쪽에서는 다 받질 못하더군요(송수측의
sequnece number는 제대로 전송되는 걸 볼 수 있는데, 받는 쪽에서는 드문드문 패킷을 받음)

그래서 다시 테스트로 40KB를 전송하고 sleep(1) 1초의 delay를 두어 데이터
를 전송합니다.

그럼 잘 몰라서 질문 드리는데 20ms정도의 delay를 두려면 어떻게 해야 하나요? 정말 초보입니다. 막 네트워크 이론을 공부하고 프로그램을 작성하는데
막막한게 한두가지가 아닙니다. 답글 부탁드립니다.

정보 공유 하길 원하는 andro000

운형의 이미지

Quote:
20ms정도의 delay를 두려면 어떻게 해야 하나요?

단순히 딜레이만 두려고 한다면 sleep을 사용하면 되는데 1초단위입니다.
좀더 작은 단위를 사용하려면 usleep...(단위가 usec이죠)
그러나 이런 단위는 os마다 지원여부가 다름니다.
정확히 기억은 안나는데 어떤 os는 10ms, 어떤놈은 100ms....
이건 확인 해봐야 합니다.(레드햇 8.0에서 100ms까지는 테스트 해봤습니다.)

단순 딜레이아닌 network i/o관련 이라면 select를 사용합니다. 마지막 인자가
usec까지의 단위를 사용합니다 물론 os마다 정밀도는 다를 수 있습니다.

참고가 되려나..

Do you think that's the air you are breathing now?

andro000의 이미지

감사합니다. 답글 정말로 감사드립니다.

정보 공유 하길 원하는 andro000

mastercho의 이미지

그거 Effective TCP/IP Programming 책에도 나오고 스티븐스 책에도 나옵니다

UDP를 가지고 TCP처럼 타이머를 두고 쓰는것이죠

근데.... UDP로 타이머 맞추고 할봐엔 TCP 쓰고 만다는 생각이 들더군요

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

댓글 달기

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