getsockopt 의 문제점?...

익명 사용자의 이미지

#include
#include
#include
#include
#include

#define DEFAULT_PORT 1111
#define DEFAULT_BACKLOG_NUM 50
#define MESSAGE_BUFFER_SIZE 20001

int client_socket_id = 0;

typedef struct sockaddr *SOCKADDR;

void print_sockopt(int socket_id);

int main(int argc,char **argv)
{
struct sockaddr_in client_sockaddr;
int server_port;
int result;
char receive_buffer[MESSAGE_BUFFER_SIZE];
char send_buffer[MESSAGE_BUFFER_SIZE];
int read_n;
int write_n;
int total_write_n;
int i,j;
pid_t child_pid;
int optval,optlen;

client_socket_id = socket(PF_INET,SOCK_STREAM,0);
if ( client_socket_id == -1 ) {
exit(1);
//error_print_and_exit(" client socket create error ",-1);
}
optval = 15000;
result = setsockopt(client_socket_id,SOL_SOCKET,SO_RCVBUF,(void *)&optval,sizeof(optval));
if ( result < 0 ) {
perror("error");
}
result = getsockopt(client_socket_id,SOL_SOCKET,SO_RCVBUF,(void *)&optval,&optlen);
printf("before optval = %d ",optval);

print_sockopt(client_socket_id);
result = getsockopt(client_socket_id,SOL_SOCKET,SO_RCVBUF,(void *)&optval,&optlen);
printf("after optval = %d \n",optval,client_socket_id);
}

void print_sockopt(int socket_id)
{
int optval,optlen;
int result;
result = getsockopt(client_socket_id,SOL_SOCKET,SO_RCVBUF,(void *)&optval,&optlen);
printf("print_sockopt optval = %d \n",optval);
}

위의 프로그램을 실행시켜 보면요..

before optval = 15000 print_sockopt optval = 30000
after optval = 15000

이렇게 나오는데요..

원래 15000 / 15000 / 15000

이렇게 나와야 하는거 아닙니까?.

단지 print_sockopt 에서 socket_id 를

인자로 받아서 소켓에 대한 옵션값을 출력해 주는 건데..

이렇게 결과가 나오는 이유를 모르겠습니다.

getsockopt 가 main 에서

실행되냐.... print_sockopt 에서

실행되냐에 따라 틀린 값이 왜 나오는 걸까요?.

갈켜주시면 감사하겠습니다.

익명 사용자의 이미지


음... 일단 getsockopt() 함수를 호출하신 다음에 리턴값을 확인안하셨네
여. 확인해 보니까 -1이 나오고 이때 errno = EINVAL (Solaris에서는 22
번)이 나왔습니다.
그러니까 제대로 getsockopt가 수행이 안됐다는 것이죠.
그러니까 optval에 전에 있던 값, 즉 main의 경우에는 15000이겠고,
print_sockopt() 의 경우에는 optval인데 이 값은 초기화안되었으니까
임의의 값이 나왔겠져? 제가 수행했을 때는 30000이 아니라 5가 나왔었습
니다.

EINVAL 같은 경우는 보통 파라메터가 비정상적인 경우에 나는 오류죠?
getsockopt에서는 맨 끝의 optlen 이 value-result 입니다.
즉, 호출하시기 전에 값을 설정해 주고, 호출된 프로그램에서 다시
상황에 맞도록 값을 설정해 주도록 되어있져.
그러니까 getsockopt() 부르시기 전에 optlen = sizeof(optval) 함
해주시고 불러보세여.
일단 optlen의 크기 설정은 getsockopt() 호출 전 매번 하시는 것이
안전합니다. 비슷하게 value-result를 사용하는게 accept() 함수도
있었져?

그리고 이건 프로그램 수행과는 상관없겠지만,
print_sockopt() 에서 아규먼트로 받은 socket_id를 사용하지 않고
전체변수 client_socket_id 를 쓰셨네요?

익명 사용자의 이미지

그래서 초기화 부분을 다 넣어 줬더니..

main 에서나 print_sockopt 부분에서도

동일한 값이 나왔습니다.

optval = 0;
optlen = sizeof(optval);

이런식으로 초기화 주고 호출해 주었습니다.

그렇지만

제가 원하는 결과는 15000 이었는데.

모두가 30000 이라는 getsockopt 결과 반환을 해주더군요..

왜 RECVBUF 를 15000 으로 설정하였는데..

get 으로 확인해 보면 30000 으로 바뀌어 있는 걸까요..

꼭 2배씩 그렇게 되거든요.

아시면 답변 달아주세요..감사드립니다...

익명 사용자의 이미지


앗.. 그렇네요?

Sun에서 했을 때는 문제없이 먹던데 (15000 설정했더니 15008로 설정됨.
특정 OS에서는 MSS의 짝수배로 설정된다나여.)

리눅스에서는 무조건 두배로 먹네여? 신기신기..

익명 사용자의 이미지

한남대학교에서 실험한 데이터가 있더군요.

http//netwk.hannam.ac.kr/data/linux_socket/chap12.ppt

내용중에 아래 소스를 가리키며 보라고 되어있는데

/usr/src/linux-2.2.16/net/core/socket.c

물론 내용도 따라 나옵니다.
정확한 해설은 없지만 설정값이 256보다 작으면 256으로
그보다 크면 들어온값 * 2를 하는군요.
물론 SNDBUF도 * 2를 하는데...
자세한 내막은 모르겠고 일단은 2배로 늘어나는 이유는 알았네요.

익명 사용자의 이미지


올려주신 글 보고 검색을 하다 보니까 관련된 내용이 조금 나오네여.

그렇게 한 이유는 Linux에서는 소켓버퍼의 반을 메타데이터(skbuff
header 등)를 위해 예약해 두었기 때문이라네여.
BSD는 그렇게 하지 않고있고요.
전통적인 BSD계열에서는 메타 어카운팅을 하지 않기 때문에
SO_SNDBUF/SO_RCVBUF를 이용하는 대부분의 프로그램은 이걸 (반을 메타데
이터를 위해 쓰는것이겠죠?) 기대하지 않았고,
리눅스에서는 사용자가 지정한 공간만을 할당한다면 실제로 유효한
공간이 상당히 작아지게 된다네요. (반으로 작아지겠죠.. ㅡ.ㅡ;;)
그래서 이것을 해결하기 위해서 리눅스는 내부적으로 버퍼를 두배로 해서
호환성을 유지하려고 한다네요.

이 문제가 여러번 메일링 리스트에 나왔었나 보네요.
음.. 그중 다른 어떤 사용자가 올린 글이 제겐 맞을 듯 한데..
그 사람 이야기가 set할 때 내부적으로 2배를 늘렸으면,
get할때는 내부적으로 1/2 로 나눈값을 돌려줘야 하지 않겠느냐고 하네
요.

원문 일부입니다.
- /* FIXME is this lower bound the right one? */
+
+ /* People regularly wonder whether the "*2" here
+ is correct. Linux reserves half of the socket
+ buffer for metadata (skbuff headers etc.)
+ BSD doesn't do that. Most programs using
+ SO_SNDBUF/SO_RCVBUF didn't expect this, because
+ traditional BSD does not do metadata accounting,
+ and on Linux they ended up with too small effective
+ buffers. To fix this Linux always doubles the
+ buffer internally to stay compatible.
+ See also socket(7). */
+
sk->rcvbuf = max(val*2,SOCK_MIN_RCVBUF);
break;

Of course everybody will regard a system broken that has a getfoo()
that does not return what was given to setfoo().
No documentation will change that.

Andries

링크 참조하세여.

http//www.geocrawler.com/archives/3/8358/2002/1/0/7686737/

http//www.uwsg.iu.edu/hypermail/linux/kernel/0108.0/0300.html

댓글 달기

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