[재수정]recv()함수로 동적 메모리로 지정할때...

babonara의 이미지

char *Msg;

if( (Msg=(char *)malloc(sizeof(char))) == NULL)

len=recv(fd,(char *)Msg,Msg_Size,0)

메세지를 가져올때 여러번 나누어서 받아 올경우가 생깁니다.

예를 들면 512 바이트를 가져와야 하는데

312개의 메세지가 도착 했는데 나머지 200개를 더 가져와야 하는데
312개 많큼 동적으로 이동해서 나머지를 가져와야 하는데
동적값을 증가 시키는 방법이 너무 애매합니다.

pynoos의 이미지

50바이트를 사용했다는 과정이 뭐죠?

문제의 의도를 장황하게 설명해주시어요.

펑키의 이미지

메모리 할당은 미리 해주세요!

이것을 전제 조건으로 생각해보시면 해결 방법이 손쉽게 생길수가 있습니다. 즉, 받을려고 하는 자료가 100 바이트인데 처음에 50 바이트가 날라 오고 나중에 50바이트가 날라 온다면 매모리를 두번 할당하는데 이때 두번이라기 보다는 재할당(realloc)이 되겠죠.? 이러한 방법은 아주 비효율적이게 됩니다. 따라서 받고자 하는 크기를 미리 지정해주시고 이 양만큼 받으시길 권해 드립니다. 왜냐하면 TCP 통신의 특성상 100바이트를 받아야 한다면 한번에!!! 100바이트가 온다는 보장은 하지 않거든요. (물론 100바이트 정도는 한번에 받습니다만)

따라서 두가지를 염두에 두세요.

1. 받고자 하는 데이터의 크기를 미리 알고서(예측하는 방법은 별로 효율적이지 않고 머리 아프게 하는 원인입니다) 그 크기만큼 버퍼를 잡아 놓는다. 이때 받고자 하는 데이터의 크기가 가변적이라면 미리 데이터의 크기를 상대편측에 알수 있는 방법이 존재해야 합니다. 따라서 대부분의 통신에서는 HEADER+BODY 이렇게 구분해서 HEADER(늘 일정한 크기)에 BODY의 크기를 지정해서 보내줍니다. 따라서 받는 쪽에서는 HEADER를 먼저 읽어 보고 BODY가 얼마만큼 오는지 알수가 있으니깐 그 크기만큼 버퍼를 잡아서 받아 주면 됩니다.

2. 받는쪽(보내는 쪽도 마찬가지입니다)에서는 데이터가 한번에 온다는 보장이 없는것을 염두에 두어야 하니깐 내가 받고자 하는 크기가 얼아인데 현재 받은 크기는 얼마인지를 늘 체크해야만 합니다. 즉, 보내거나 받는 함수들이 보통 지금 얼마 받았다 지금 얼마 보냈다는 크기를 리턴해주니깐 이 값과 보내거나 받을려고 하는 크기와 비교해보고 덜가거나 덜 왔다면 그 크기만큼 다시 받게 해주면 됩니다. 이것을 SEND/RECV 들을 LOOP에 두고서 반복시키면 쉽게 해결할수 있는것입니다.

그리고 올려주신 예제는 제가 잘 모르겠습니다. 어떠한것을 의도하는지 512바이트를 받으실려면 512를 먼저 버퍼로 잡아 놓으시는게 어떠실런지 하고 생각해봅니다. 이래 저래 생각해봐도 메모리를 할당하고 다시 그것을 사이즈 조정하는 방법은 좋지 않은 방법일듯 싶습니다. 매모리 재할당은 정말 이래 저래 방법이 없을 경우에 쓰시는것이 좋으실듯..

인터넷상에서 책에 나와있는 예제가 아니라 일반 프로젝트들을 보시면 SEND/RECV 모두 단일로는 사용되지 않고 반드시 LOOP 안에 들어가 있는것을 쉽게 보실수 있을겁니다.

즐거운 하루 되세요.

babonara의 이미지

답변은 감사 드립니다.
그런데 메세지를 가져올때 사이즈가 일정 하지가 않기 때문에 동적으로 할당해서 가져오려고 합니다.
앙 너무 머리가 돌겟습니다. ㅜㅜ

pynoos의 이미지

Protocol을 만드실때,

송신
1. 고정된 길이의 header를 보낸다. (보낼 데이터의 크기포함)
2. 데이터를 보낸다.

수신
1. header를 읽는다.
2. data 크기만큼의 buffer를 만든다.
3. data를 받는다.

-------------------------

위와 같이 하면 되지만, 권장하는 방법은 아닙니다.
protocol을 설계하실 때, packet의 최대 data chunk 를 제한하고,
그 chunk 의 최대 크기 만큼 미리 메모리를 확보해두고, 그 크기만큼 받도록 하는 것이 좋습니다.
물론 보내려는 데이터의 전체 크기가 작으면 상관없겠지만요.

보내려는 data의 크기가 file이라면 더더욱... 수많은 chunk가 생길것이고
갈무리 하는 쪽이나, 보내는쪽이나 동적으로 할당한 후 늘였다 줄였다 하는 것은
그다지 보기 좋지 않아 보이는 군요. 그렇다고 받는 족족 linked list 로 구현하는 것도.. data의 연속성이 없어서.. 이상하구요.

고민해보셔요...

faye의 이미지

원하시는 답인지는 모르겠지만..

ioctl 명령으로 socket buffer에 있는 데이터의 길이를 확인할수 있습니다.

ioctl(sock, FIONREAD, (char *)&len);

msg = (char *)malloc(len);

이렇게 해준다면.. 데이터가 가변적으로 들어와도 적당한 크기의 버퍼를 할당해

줄수 있을것 같내요..

도움이 되었으면 합니다..

최종호의 이미지

에 따라서 틀릴 것 같은데요,,

질문하신 제목으로 봐서는 메시지 길이가 가변이라고 하신 것 같은데,

내용에 예로 드신 것을 보면 메시지 길이는 고정(512)인데

각 recv시에 들어오는 데이터가 512가 아니라 몇개로 잘라서 들어올 수 있다

는 것 같아서 좀 모호합니다.

하나의 메시지가 여러개로 나뉘어서 들어올 수 있는 것은

readn() (표준 함수는 아니고요, Stevens 책에 보시면 있습니다.

웹에서 그냥 검색해도 나올 듯) 함수로 고정길이가 들어올 때까지

데이터를 계속 읽어들이는 식으로 하시면 될 것 같고요,,

메시지가 가변길이인 경우에는 여러가지 방법들이 있습니다.

게시판에서 몇번 다뤄진 것 같지만,

처음에 메시지길이(또는 어떤 메시지인지를 나타내는 명령코드, 메시지 코드 등)을 전송하고, 그 후에 메시지를 보내는 방법.

님 말씀처럼 그때그때 malloc 하는 방법 (근데 이것도 크기가 얼마나 되는지를 알기 위해서는 코드를 전달한다든지, 미리 사전에 정의되어 있다든지, 데이터의 일정부분에 메시지의 경계를 나타낸다는지 (ex. \n or \r\n 등으로 메시지의 끝을 나타낸다) 하는 것이 있어야 할 것 같고요.)

여러가지 방법이 있는데, 이건 각각 어플리케이션 상황에 맞게 하셔야 할 듯 하니 (ftp와 같은 파일전송과, HTTP, SMTP 또는 명령코드+데이터 등은 서로 다른 데이터 교환전략이 필요하겠지요.) 상황을 좀 구체적으로 말씀하시면 답변들도 조금 구체적이 되지 않을까 합니다. 데이터 수준에서는 readn() 을 쓰시면 되겠습니다.

고물의 이미지

char *Msg; 

if( (Msg=(char *)malloc(sizeof(char))) == NULL)  // 1아이트 메모리를 할당 받나요?

len=recv(fd,(char *)Msg,Msg_Size,0) // Msg_Size 정의가 없는데?

음.. 머 걍 예제로 대충 적으신 것 같네요..

동적 메모리 할당이라..

간단해요..

malloc으로 메모리를 잡고.. 거기에 recv된 메시지를 len 값만큼 읽어오니.. 그만큼 추가하다가 추가할 사이즈가 현재 할당된 메모리보다 클 경우에..

처음의 메모리 잡은 것을 늘려주면 됩니다.. 늘리는 폭은 처음에 보통 normal한 사이즈로 설정을 하시고 늘리는 사이즈는 만약에 늘어날때 어느정도가 적정선으로 늘어나야 속도가 괜찮은지, 아니면 메모리 의존도가 높으면 작게잡구여..

늘리는 것은 보통은 음.. 새로운 메모리를 잡아서 기존 것을 카피해주는 방식을 쓰죠.. 그리고 속도에 대해서 민감하면.. 리스트 형식을 사용해서 메모리 복사를 빼는 방식이죠모..

댓글 달기

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