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 에서
실행되냐에 따라 틀린 값이 왜 나오는 걸까요?.
갈켜주시면 감사하겠습니다.
Re: getsockopt 의 문제점?...
음... 일단 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 를 쓰셨네요?
Re^2: getsockopt 의 문제점?...답변감사드립니다.그리고 추가질
네
그래서 초기화 부분을 다 넣어 줬더니..
main 에서나 print_sockopt 부분에서도
동일한 값이 나왔습니다.
optval = 0;
optlen = sizeof(optval);
이런식으로 초기화 주고 호출해 주었습니다.
그렇지만
제가 원하는 결과는 15000 이었는데.
모두가 30000 이라는 getsockopt 결과 반환을 해주더군요..
왜 RECVBUF 를 15000 으로 설정하였는데..
get 으로 확인해 보면 30000 으로 바뀌어 있는 걸까요..
꼭 2배씩 그렇게 되거든요.
아시면 답변 달아주세요..감사드립니다...
Re^3: 앗.. 정말 그런데여? 왜 그러져?
앗.. 그렇네요?
Sun에서 했을 때는 문제없이 먹던데 (15000 설정했더니 15008로 설정됨.
특정 OS에서는 MSS의 짝수배로 설정된다나여.)
리눅스에서는 무조건 두배로 먹네여? 신기신기..
Re^4: 앗.. 정말 그런데여? 왜 그러져?
한남대학교에서 실험한 데이터가 있더군요.
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배로 늘어나는 이유는 알았네요.
Re^5: 앗.. 그렇네여..
올려주신 글 보고 검색을 하다 보니까 관련된 내용이 조금 나오네여.
그렇게 한 이유는 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
댓글 달기