IT이야기

C 소켓 Sockaddr 및 Sockaddr_storage의 배후 추론

cyworld 2022. 5. 2. 21:23
반응형

C 소켓 Sockaddr 및 Sockaddr_storage의 배후 추론

다음과 같은 기능을 보고 있다.connect()그리고bind()C 소켓에서 그들이 포인터를 가져가는 것을 알아차린다.sockaddr구조상의읽었는데 당신의 애플리케이션을 AF-Independent로 만들려면, 그 어플리케이션을 사용하는 것이 유용하다.sockaddr_storage포인터를 구조화하여 a에 주조하다.sockaddr더 큰 주소를 위한 여분의 공간 때문에 포인터.

내가 궁금한 것은 어떻게 기능하는가 이다.connect()그리고bind()A를 필요로 하는sockaddr포인터는 예상한 것보다 더 큰 구조를 가리키는 포인터에서 데이터에 액세스한다.물론, 당신이 제공하고 있는 구조의 크기를 전달하지만, 당신이 캐스트한 더 큰 구조로 IP 어드레스를 빼내기 위해 함수가 사용하는 실제 구문은 무엇인가?struct *sockaddr?

아마 OOP언어 출신이라서 그런 것 같은데, 좀 해킹이 되고 좀 지저분해 보인다.

포인터를 사용할 것으로 예상되는 함수struct sockaddr아마도 당신이 그들에게 보내는 포인터를 타이프로 보낼 것이다.sockaddr당신이 그들에게 포인터를 보낼 때struct sockaddr_storage. 그런 식으로 접근한다.struct sockaddr.

struct sockaddr_storage두 가지 모두에 적합하도록 설계됨struct sockaddr_in그리고struct sockaddr_in6

당신은 당신만의 것을 만들지 않는다.struct sockaddr, 당신은 보통 a를 만든다.struct sockaddr_in또는 astruct sockaddr_in6사용 중인 IP 버전에 따라 달라짐.어떤 IP 버전을 사용할지 알아보려는 시도를 피하기 위해 a를 사용할 수 있다.struct sockaddr_storage둘 중 하나를 지탱할 수 있다.이것은 다음에 타이프로 방송될 것이다.struct sockaddrconnectivate bindsuch 등 기능들에 의해 그리고 그러한 방법으로 접근했다.

아래 모든 구조물을 볼 수 있다(패딩은 맞춤을 위해 구현마다 다름).

struct sockaddr {
   unsigned short    sa_family;    // address family, AF_xxx
   char              sa_data[14];  // 14 bytes of protocol address
};


struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};


struct sockaddr_in6 {
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

struct sockaddr_storage {
    sa_family_t  ss_family;     // address family

    // all this is padding, implementation specific, ignore it:
    char      __ss_pad1[_SS_PAD1SIZE];
    int64_t   __ss_align;
    char      __ss_pad2[_SS_PAD2SIZE];
};

보시다시피 함수가 IPv4 주소를 예상할 경우 처음 4바이트를 읽는다(구조체가 유형이라고 가정하기 때문에).struct sockaddr. 그렇지 않으면 IPv6에 대한 전체 16바이트를 읽는다.)

C++ 클래스에 가상 기능이 하나 이상 있는 경우 TAG가 지정된다.그 태그는 네가 할 수 있다.dynamic_cast<>()당신의 클래스는 어느 클래스에서나 유래되고 그 반대의 경우도 마찬가지 입니다.TAG가 허락하는 것은dynamic_cast<>()일하기 위해다소, 숫자 또는 문자열일 수 있음...

C에서 우리는 구조물에 제한되어 있다.그러나 구조물에 TAG를 할당할 수도 있다.실제로 프롤이 그의 답변에 올린 모든 구조를 보면, 모두 우리가 주소의 패밀리라고 부르는 2바이트(서명되지 않은 쇼트)로 시작하는 것을 알 수 있을 것이다.이것은 구조가 정확히 무엇이며 따라서 그 크기, 필드 등을 규정한다.

그러므로 다음과 같은 일을 할 수 있다.

int bind(int fd, struct sockaddr *in, socklen_t len)
{
  switch(in->sa_family)
  {
  case AF_INET:
    if(len < sizeof(struct sockaddr_in))
    {
      errno = EINVAL; // wrong size
      return -1;
    }
    {
      struct sockaddr_in *p = (struct sockaddr_in *) in;
      ...
    }
    break;

  case AF_INET6:
    if(len < sizeof(struct sockaddr_in6))
    {
      errno = EINVAL; // wrong size
      return -1;
    }
    {
      struct sockaddr_in6 *p = (struct sockaddr_in6 *) in;
      ...
    }
    break;

  [...other cases...]

  default:
    errno = EINVAL; // family not supported
    return -1;

  }
}

은 보다시피, 보다시피 할 수 .len길이가 예상 구조물에 맞도록 충분히 길어서 가능한지 확인하는 매개변수reinterpret_cast<>()(C++로 불릴 것처럼) 포인터를 사용하십시오.구조의 데이터가 올바른지 여부는 발신자에게 달려 있다.그 목적에는 선택의 여지가 별로 없다.이 기능들은 데이터를 사용하기 전에 모든 종류의 것들을 검증하고 -1과errno문제가 발견될 때마다

그래서 사실상, 여러분은struct sockaddr_in또는struct sockaddr_in6한 것.struct sockaddr그리고bind() 그 로 되돌아가다.struct sockaddr_in또는struct sockaddr_in6그들이 확인한 후에sa_family회원가입을 하고 사이즈를 확인했다.

참조URL: https://stackoverflow.com/questions/16010622/reasoning-behind-c-sockets-sockaddr-and-sockaddr-storage

반응형