[질문, 꼭좀 부탁합니다] 많은 데이터를 sendto를 이용해서 보낼

ulsiguya의 이미지

제가 멀티미디어 데이터를 전송하는 프로그램을 작성하고 있습니다.
구조는 간단한데요...

thread가 두개인데, 한쪽(thread1)에서는 보낼 데이터를 만들고 큐(list로 구현된)에다가 넣으면 다른 한쪽(thread2)에서는 sendto로 UDP로 네트웍으로 날립니다.

그런데, thread1에서 만들어지는 데이터의 양이 매우 많습니다. 그래서 thread2에서 빨리 전송을 해줘야 하는데요. 그냥 while문을 돌면서 큐에서 뺀데이터를 sendto를 하니깐 반정도는 전송이 되지 않습니다.

값을 찍어보면 sendto 함수는 전송을 했다고 리턴을 합니다. 하지만, sniffing을 해보면 패킷이 반 정도는 네트웍으로 전송을 하지 않고 있습니다.

그래서 sendto함수 실행 후에 ulseep(0) 정도로 잠깐 쉬어주니, 손실되는 패킷은 없어집니다. 하지만, 패킷을 전송할때마나 쉬어주니, 큐안에 내용이 싸여서 점점 늘어나게 됩니다.

시스템이 CPU가 XScale이고 Ethernet이 10M라서 리소스가 부족한 편입니다. 그래서 usleep으로 전송시에 잠깐 쉬어주는 것은 무리가 있습니다.

이런 경우 혹시 보셨나요? 혹시 아시는 분은 조언을 꼭 좀 해주세요...

stoneshim의 이미지

쉬지 않고 looping 으로 돌릴때의 대역폭을 계산해 보세요.
네트웍 대역폭을 넘는다면, 방법이 없지 않겠습니까?

100 M bps 라인을 사용하시거나, 아쉬운대로 채널 본딩으로 대역폭을 2배~4배 로 늘릴 수는 있겠습니다만...

하드웨어에서의 병목을 소프트웨어적으로 해결할 수는 없으니까요.

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

ulsiguya의 이미지

전송할 데이터의 크기는 200kbps 정도 됩니다. 10M 로는 가능하다고 생각하는데요...
제 생각엔 딴 문제가...

mycluster의 이미지

한번 보낼때의 패킷사이즈가 얼마인가요? 그러면 계산이 나오겠지요.
설마 10M 라인이라고 10Mbps로 전송이 가능할 것이라고 믿고 계시는 것은 아니겠지요?

--------------------------------
윈도위의 리눅스 윈도위의 윈도우 리눅스위의 익스플로러

ulsiguya의 이미지

1024 바이트를 최대 사이즈로 설정했습니다.
멀티미디어 데이터가 그 이상일 경우 APP에서 잘라서 따로 따로 패킷을 구성하여 전송했습니다. 특이한건 최대 전송사이즈를 줄이면 줄일수록 패킷 손실이 더 많아 집니다... 1400 바이트로도 해봤는데, 이때는 패킷 손실이 좀 줄어듭니다...
아무래도 I/O 관련된 문제인것 같은데요...

참고로, 보내는 데이터를 합해서 초단위로 나눠보니 초당 200kbit 정도로 보내는것 같습니다. 음... 어떻게 해야 할지...

stoneshim의 이미지

제 경우는 아직 물리적인 대역폭을 넘지 않는 상황에서 랜카드 밖으로 나가지도 않고 손실이 되는 경우는 못본것 같습니다. 특이한 경우네요.

혹시 send 버퍼의 크기를 최대로 잡으셨나요?

그리고 송/수신단이 동일 서브넷 환경이 아닌 경우라도, UDP 전송시에 대개 8K 정도는 하나의 데이터그램에 담아서 보내는 경우를 많이 보았습니다.
데이터그램 크기를 조금더 늘려서 테스트 해보시는것도 좋을것 같습니다.

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

mycluster의 이미지

Quote:

멀티미디어 데이터가 그 이상일 경우 APP에서 잘라서 따로 따로 패킷을 구성하여 전송했습니다. 특이한건 최대 전송사이즈를 줄이면 줄일수록 패킷 손실이 더 많아 집니다... 1400 바이트로도 해봤는데, 이때는 패킷 손실이 좀 줄어듭니다...
아무래도 I/O 관련된 문제인것 같은데요...

지극히 정상적인 문제로, I/O하고는 상관이 없다고 보여지는군요. 1024바이트라면 아마 최대 얻을 수 있는 대역폭은 잘해야 2Mbps도 넘지 못할겁니다. 10Mbps의 대역폭을 얻을려면 적어도 패킷사이즈를 1Mbyte정도로 해야됩니다. latency 때문이죠.

따라서 이런 경우 가장 좋은 방법은 통신 횟수를 줄이는 방법이 제일 좋습니다. 즉, 최대한 전송할 데이타사이즈를 크게 만들어서 많이 모은 다음에 한방에 날려서 보내는 것이 가장 빨리 전송하는 방법입니다.

간단하게 식을 만들어보면(이거 정확한거 아닙니다)

통신시간 = latency + 전송될데이타크기/bandwidth 일겁니다.

1byte씩 1024byte를 보낸다면 얼마가 걸리냐면

Total_time = (latency+1byte/10Mbps) * 1024 (sec) 일것이고,
1024byte를 한번에 보낸다면
Total_time = (latency+1024byte/10Mbps) (sec) 입니다.

당연히 후자가 훨씬 시간이 적게 걸릴것은 당연하겠지요.

--------------------------------
윈도위의 리눅스 윈도위의 윈도우 리눅스위의 익스플로러

ssehoony의 이미지

소켓이 블럭킹 모드인지 비블럭킹인지에 따라 send 함수 같은 경우는 반환값이 의미가 조금 달라집니다.
전 tcp 만 사용해봐서 잘 모르겠는데,
send 용 버퍼 가 비워지는 시간 보다 채워지는 속력이 빠르면 별도의 처리가 필요할지 모르겠네요.

stoneshim의 이미지

Quote:
지극히 정상적인 문제로, I/O하고는 상관이 없다고 보여지는군요. 1024바이트라면 아마 최대 얻을 수 있는 대역폭은 잘해야 2Mbps도 넘지 못할겁니다. 10Mbps의 대역폭을 얻을려면 적어도 패킷사이즈를 1Mbyte정도로 해야됩니다. latency 때문이죠.

글쎄요... 제가 테스트 해 본 결과는 좀 다릅니다.

전송 데이터그램의 크기가 1K 인 경우만 해도 10M bps는 훨씬 넘었고, 8K 정도에서 5~70M bps가 나왓으며, 16K까지 늘렸을때에는 이미 100M bps 를 넘어서 물리적인 대역폭을 넘어섰습니다.

500MHz dual cpu, 256M 메모리, 100Mbps Lan, Linux 커널 2.4.20 에서의 결과였습니다.

Application 단에서 데이터그램을 잘게 쪼개서 보내는 것보다는 latency가 적겠지만, 큰(ethernet frame보다) 데이터그램을 한번에 보내는 경우에는 커널에서 ip fragmentation이 일어나게 되어 어차피 여러개의 ethernet frame으로 쪼개져서 나가게 되니, 데이터그램 하나의 입장에서 볼때에는 패킷 로스가 일어날 가능성도 많아집니다.

현재의 환경에서 적당한 데이터그램의 크기를 테스트해서 결정하는 것이 가장 좋을것 같습니다.

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

쎄피로의 이미지

쓰레드에서 usleep을 써주기에 무리가 있다기 보다 사용하지 않아서 무리가 생기는게 아닌가 싶습니다. 로직 사이 사이 약간의 usleep은 좋은 효과를 낼 수 있다고 생각합니다. 쓰레드간 균형을 맞춰주는 셈이죠. 너무 빠른 것도 문제가 충분히 될 수 있습니다.

세상은 넓고, 할 일은 많은데, 난 숨만 쉬고 있니?

버려진의 이미지

큐에 추가는 어떻게 하시나요? 포인터로 넘기시나요? 락을 거시나요?

mangg의 이미지

저는
두 쓰레드 간의 동기화 부분에서 접근하고 싶습니다.
두 쓰레드간의 동기화는 준비 하셨는지요?

또한 큐에 집어 넣었다고 했는데..
어떤식인지요?

-------------------
나는 Copy&Paster 이다. 나의 화려한 기술 조합에 모두들 나를 두려워 한다. 나도 코드 Maker 이고 싶다.

gurugio의 이미지

하드웨어상으로 그정도의 데이터 전송을 충분하지 않을까요?

그래서 소프트웨어적인 병목현상이 아닐까 하는 생각이 듭니다.

네트워크로 전송하는 스레드와

데이터를 처리하는 스레드가 있을 때

전송하는 속도가 아무래도 늦지 않을까요?

전송할 때는 TCP의 특성상 지연현상이 있으니

스레드가 같은 시간동안 돌아간다고 해도

데이터 처리는 활당받은 시간 모두 데이터 처리에 사용하고

네트워크 스레드는 좀더 많은 시간이 필요하지 않을까요?

동기화를 할 때 네트워크 스레드에게 좀더 자원을 주는건 어떨까요?

그리고 사실적으로 하드웨어가 이미 결정된 상태라서

하드웨어를 바꾸기가 많이 힘들기 때문에 어떻게든 소프트웨어 적으로

해봐야 하기도 합니다.

winix의 이미지

sendto 를 사용할때 버퍼의 크기를 올린다 해도

/proc/sys/net/core/rmem_max 값 이상 올라가지 않습니다.
이 값을 충분히 올린 다음에 해보세요..

혹여 버퍼 문제라면 도움이 될겁니다..

alsong의 이미지

해결책은 아니고 혹시 에러가 안뜨는건 아래랑 관계 있지 않을까요?

Quote:
ENOBUFS
The output queue for a network interface was full.
This generally indicates that the interface has
stopped sending, but may be caused by transient
congestion. (This cannot occur in Linux, packets
are just silently dropped when a device queue over-
flows.)

그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.

mushim의 이미지

에러없이 패킷이 없어졌다면, 아마 network device queue 가 꽉 차서 생긴 문제일것 같군요.

해당 디바이스가 eth0 이라면 다음 명령으로 조절 할 수 있습니다.

ifconfig eth0 txqueuelen

최종호의 이미지

alsong wrote:
해결책은 아니고 혹시 에러가 안뜨는건 아래랑 관계 있지 않을까요?

Quote:
ENOBUFS
The output queue for a network interface was full.
This generally indicates that the interface has
stopped sending, but may be caused by transient
congestion. (This cannot occur in Linux, packets
are just silently dropped when a device queue over-
flows.)

이건 좀 문제가 있을 수 있다고 보여지는데요,
이런 상황이 발생할 수 있는 상황과 그에 대한 일반적인 처리방식에 대해서
조금 더 언급해 주실 수 있을까요?

UDP에서만 발생하는건가요? TCP쪽에서도 발생하는건가요?
sendto 의 경우에만 발생하는 건가요?
이 경우 재전송은 개발자가 작성한 코드에서 처리해 주어야 하는건가요?
아니면 라이브러리나 시스템콜에서 처리해 주는 문제인가요?

alsong의 이미지

매뉴얼을 보다가 위의 현상중에 하나와 관련된 문구가 있어서 올렸습니다.
아래는 제견해입니다...
발생하는 상황은 안해봐서 잘모르겠습니다. 신뢰도가 있는 추측이 힘들군요.
UDP(TCP로 상황 재현하기는 힘들것 같군요.)로 무한루프 돌리면 발생할것 같은데^^;
send의 경우에도 에러목록에 존재하는 걸로 보아서
TCP나 UDP가 output queue의 full 여부를 무시하고 보내는 것 같습니다.
TCP에서도 발생할 가능성이 있군요. 그러나 받는쪽에 버퍼가 무한정 크지
않는한 stream control에 의해서 발생할 소지는 UDP에 비해서 작을 것 같
습니다.
TCP의 경우 재전송을 따로 해줄 필요는 없을것 같습니다. 보내는 메시지가
소실 되었다면 수신 응답이 없을 경우이므로 재전송 루틴이 작동 하겠죠.
UDP에서는 재전송자체가 없으므로 위의 상황과 관계없이 메시지가
소실되었을때를 고려 해야 될것 같군요.

그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.

ulsiguya의 이미지

여러가지 조언 주신 것 감사합니다.
문제는 말씀하신데로 sender의 소켓쪽 버퍼와 receiver의 소켓 버퍼 사이즈가 너무 작아서 그랬던것 같습니다.
setsockopt()를 이용해서 사이즈를 키워주니 에러없이 전송이 잘되고 있습니다.
다시 한번 감사를 드립니다. 꾸벅~

댓글 달기

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