setsockopt: Protocol not available ???

kama4001의 이미지

소켓 프로그래밍을 하다가 setsockopt(), getsockopt() 함수에서

다음과 같은 에러가 나타납니다.

setsockopt: Protocol not available :shock:

어떤 문제가 있어서 위와 같은 에러가 발생하는 걸까요?

그리고 그 해결 방법은 무엇입니까?

codebank의 이미지

The option is not supported by the protocol.
즉, 프로토콜에서 지원하지 않는다는군요.
자세한건 man페이지를 이용하세요.

------------------------------
좋은 하루 되세요.

kama4001의 이미지

빠른 답변에 감사합니다.

귀찮으시겠지만 보다 명확하게 말해 줄 수 없는지요...

단순히 서버/클라이언트 프로그램을 짜다가 bind() 에러 때문에,

찾은 해결책이 setsockopt()를 이용하는 것이라고 찾았습니다.

소켓 레벨을 뜻하는 SOL_SOCKET에서 SO_REUSEADDR를

지원하지 않는다는 건지요?

만약 그렇다면 어떻게 해야 해결을 할 수 있는건지요...

제가 사용했던 프로그램 소스는 다음과 같습니다.

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }
dyks의 이미지

그 정도 소스로는 귀신 할애비가 와도 알 지 못합니다. 소켓을 만들때 어떤 프로토콜을 명시해서 만들었는지, setsockopt를 호출하는 시점이 언제인지 정도는 파악할 수 있어야 합니다.

자주 오고가는 얘기지만, 좋은 (명확한) 답변을 위해서는 좋은 (명확한) 질문이 필요합니다.

kama4001의 이미지

네.. 제가 올바르게 질문을 못한 것 같습니다.

전체 소스는 다음과 같습니다.
(결국 디버깅 하다가 제거 짠 소스가 되지 않고 웹에서 찾은 샘플 소스에
setsockopt()만 추가하였습니다)

    int sockfd, new_fd;  /* listen on sock_fd, new connection on new_fd */
    struct sockaddr_in my_addr;    /* my address information */
    struct sockaddr_in their_addr; /* connector's address information */
    int sin_size;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

	int yes=1;      // for setsockopt() SO_REUSEADDR, below

    // lose the pesky "address already in use"error message
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    my_addr.sin_family = AF_INET;         /* host byte order */
    my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
    my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
    bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
                                                                  == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    while(1) {  /* main accept() loop */
        sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
                                                      &sin_size)) == -1) {
            perror("accept");
            continue;
        }
        printf("server: got connection from %s\n", \
                                           inet_ntoa(their_addr.sin_addr));
        if (!fork()) { /* this is the child process */
            if (send(new_fd, "Hello, world!\n", 14, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);  /* parent doesn't need this */

        while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
    }
bugiii의 이미지

사용하시는 OS 가 무엇인지가 필요한 시점이겠군요.

kama4001의 이미지

OS : 레드햇 9.0
Kernel Version : 2.3.20-30-9 (레드햇에서 수정을 가한 것임)
GCC : 3.3.2

이렇게 됩니다.

codebank의 이미지

SO_REUSEADDR의 경우 TCP상태에서는 안된다고 합니다.
UDP의 상태에서만 그 기능을 발휘한다고 하네요.
현재 소스를보면 socket (AF_INET, SOCK_STREAM, 0) 즉, TCP형태로
소켓을 생성시켜서 그렇습니다.
저 옵션을 사용하려면 socket (AF_INET, SOCK_DGRAM, 0)으로 해야할 것
같네요.
그에 관련된 문서는 아래를 참조해 보세요.

http://pscal.skku.ac.kr/~angler/lecture/data_comm/data_comm_6th.ppt

------------------------------
좋은 하루 되세요.

bugiii의 이미지

codebank wrote:
SO_REUSEADDR의 경우 TCP상태에서는 안된다고 합니다.
UDP의 상태에서만 그 기능을 발휘한다고 하네요.
현재 소스를보면 socket (AF_INET, SOCK_STREAM, 0) 즉, TCP형태로
소켓을 생성시켜서 그렇습니다.
저 옵션을 사용하려면 socket (AF_INET, SOCK_DGRAM, 0)으로 해야할 것
같네요.
그에 관련된 문서는 아래를 참조해 보세요.

http://pscal.skku.ac.kr/~angler/lecture/data_comm/data_comm_6th.ppt

거꾸로 아닌가요? UDP 일 경우 일반적으로 REUSEADDR 이 안되고 REUSEPORT 가 되는 걸로 알고 있습니다만... (멀티캐스트는 예외)

sunyzero의 이미지

특별히 문제가 있어보이지는 않네요.

setsockopt 에서 문제가 생길거 같지는 않습니다.

다만 bind에서 맨뒤의 인자는 실제 sockaddr_* 구조체의 크기가 됩니다. 따라서 AF_INET 용으로 생성했으므로 sizeof(struct sockaddr_in) 이 되겠습니다.

그리고 버기님 말씀이 맞습니다. TCP의 경우에 연결지향이므로 서버가 죽더라도 클라이언트로부터의 쓰레기 패킷처리를 위해서 최대로는 2MSL시간동안 살아있습니다. 이것때문에 REUSEADDR을 사용하지 않으면 다시 listen port를 열수 없습니다.

========================================
* The truth will set you free.

indie의 이미지

    
// lose the pesky "address already in use"error message 
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { 
        perror("setsockopt"); 
        exit(1); 
    } 

에서 &yes를 (void *)&yes로 하니깐 에러 없는데요...

집에나 갈까?

lovemyin의 이미지

TCP에서 SO_REUSEADDR 은 당연히 됩니다. time wait 에 대한 문제해결인데 보통 소켓 프로그래밍을 할때 습관적으로 넣어주는 옵션입니다.
자세한 내용은 Richard Stevens가 쓴 Unix Network Programming을 보시면 쉽게 이해하실수 있을겁니다

/***************************************************
* 가장 심플한 것이 가장 아름다운 것이다.
***************************************************/

kama4001의 이미지

많은 답변에 감사합니다.

하지만 문제를 해결할 수 있는 실마리는 조금 부족한것 같습니다.

혹시 OS의 설정 문제가 있는가라는 생각에 All 로 설치를 하고

커널에서 TCP 관련 미스무리 한 부분도 다 설정해서

프로그램을 테스트했지만 역시 묵묵 무답입니다.

혹시 컴파일 시 통신 옵션 레벨을 조절하는 뭐...

그런 것이 있는건 아닌지요?

indie의 이미지

저는 위의 소스로 문제없이 돼던데
혹시 include한 헤더파일목록을 볼수 있을까요?

집에나 갈까?

kama4001의 이미지

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>

입니다.

indie의 이미지

앞의 코드에서 포트하고 backlog값
(void *)&yes,,,,
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
요거랑 또 accept()후 내용만 조금 바꿨습니다.

저는 문제 없이 실해 돼구요...

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <sys/wait.h> 

int main(void)
{
	int sockfd, new_fd;  /* listen on sock_fd, new connection on new_fd */ 
	struct sockaddr_in my_addr;    /* my address information */ 
	struct sockaddr_in their_addr; /* connector's address information */ 
	int sin_size; 
	int MYPORT = 9090;
	int yes;
	
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 
		perror("socket"); 
		exit(1); 
	} 


	// lose the pesky "address already in use"error message 
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(int)) == -1) { 
		perror("setsockopt"); 
		exit(1); 
	} 

	my_addr.sin_family = AF_INET;         /* host byte order */ 
	my_addr.sin_port = htons(MYPORT);     /* short, network byte order */ 
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* auto-fill with my IP */ 
	bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */ 

	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { 
		perror("bind"); 
		exit(1); 
	} 

	if (listen(sockfd, 5) == -1) { 
		perror("listen"); 
		exit(1); 
	} 

	while(1) {  /* main accept() loop */ 
		sin_size = sizeof(struct sockaddr_in); 
		if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { 
			perror("accept"); 
			continue; 
		} 
		printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr)); 
		{
			/// 이것 저것....
		}
		
		close(new_fd);  /* parent doesn't need this */ 

	} 

	close(sockfd);

	return 0;
}

집에나 갈까?

댓글 달기

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