插座结构:铸造?

时间:2014-04-28 20:38:06

标签: c sockets struct casting

上下文

我自学了套接字是如何工作的。 承认,我不是C大师,但学得很快。

我读了这页:

http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzab6/rzab6xafunixsrv.htm

问题

我被困在这一行:

rc = bind(sd, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr));

我无法想象我们从这个演员(struct sockaddr *)& serveraddr得到什么。

到目前为止我的测试:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>


int main(void)
{

/*JUST TESTING THE CAST THING NOTHING ELSE HERE*/

struct sockaddr_in localaddr ;
struct sockaddr_in * mi;
struct sockaddr * toto;

localaddr.sin_family = AF_INET;

localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_port = 38999;

/* DID I DEFINED MI CORRECTLY ? */
mi = (struct sockaddr*)&localaddr;
toto = (struct sockaddr*)&localaddr;

printf("mi %d\n",mi->sin_family);
printf("mi %d\n",mi->sin_port);
printf("toto %d\n",toto->sa_family);
/*ERROR*/
printf("toto %d\n",toto->sa_port);

}

SUM UP

有人可以告诉我什么是真正传递给关于结构演员的绑定函数?

我们在该结构中拥有哪些成员?

我该如何检查?

由于

2 个答案:

答案 0 :(得分:6)

此处struct sockaddr

struct sockaddr {
    uint8_t      sa_len;
    sa_family_t  sa_family;
    char         sa_data[14];
};

,例如,这里struct sockaddr_in

struct sockaddr_in {
    uint8_t        sa_len;
    sa_family_t    sa_family;
    in_port_t      sin_port;
    struct in_addr sin_addr;
    char           sin_zero[8];
};

struct sockaddr_in6

struct sockaddr_in6 {
    uint8_t         sa_len;
    sa_family_t     sa_family;
    in_port_t       sin_port;
    uint32_t        sin6_flowinfo;
    struct in6_addr sin6_addr;
};

你会注意到他们都共享前两个成员。因此,像bind()这样的函数可以接受指向通用struct sockaddr的指针,并且知道,无论它实际指向哪个struct,它都会sa_len sa_familystruct的共同点(和#34;共同点#34;这里的意思是&#34;在内存和#34中的布局相同;所以两个{{{ 1}} 拥有 sa_family成员,但他们在两个不同的struct中处于完全不同的位置。技术上sa_len是可选的,但是如果它不存在,struct没有一个会拥有它,那么sa_family仍将以相同的方式对齐,并且sa_family_t的数据类型通常是增加以弥补大小的差异)。因此,它可以访问sa_family并确切地确定它是struct的类型,并相应地进行,例如类似的东西:

int bind(int socket, const struct sockaddr *address, socklen_t address_len) {
    if ( address->sa_family == AF_INET ) {
        struct sockaddr_in * real_struct = (struct sockaddr_in *)address;

        /*  Do stuff with IPv4 socket  */

    }
    else if ( address->sa_family == AF_INET6 ) {
        struct sockaddr_in6 * real_struct = (struct sockaddr_in6 *)address;

        /*  Do stuff with IPv6 socket  */

    }

    /*  etc  */
}

(迂腐说明:从技术上讲,根据C标准[C11第6.5.2.3.6节],如果嵌入它们,您只应该检查struct的常见初始部分在union范围内,但在实践中,它几乎总是在没有一个的情况下工作,为简单起见,我还没有在上面的代码中使用过一个。)

当你实际上没有真正的OOP结构时,它基本上是一种获取多态性的方法。换句话说,这意味着您不必拥有诸如bind_in()bind_in6()等所有其他函数,以及其他所有函数,一个bind()函数可以处理它们所有这些都是因为它可以确定您实际拥有的struct类型(假设您正确设置了sa_family成员)。

你需要实际演员的原因是因为C&type的类型系统需要它。你在void *中有一个通用指针,但除此之外一切都必须匹配,所以如果一个函数接受struct sockaddr *,它就会让你传递任何其他东西,包括{{1} }。演员基本上告诉编译器&#34;我知道我在做什么,在这里,相信我&#34;,它会为你放松规则。 struct sockaddr_in * 可以编写接受bind()而不是void *,并且不需要演员,但是没有写过因为:

  1. 它在语义上更有意义 - struct sockaddr *没有被写入接受任何指针,只有一个bind()struct &#34;衍生&#34;来自struct sockaddr;以及

  2. 原始套接字API于1983年发布,早于1989年的ANSI C标准,其前身--K&amp; RC - 只是没有void *,所以你要去在任何情况下都必须把它投射到某个东西。

答案 1 :(得分:2)

强制转换显示在套接字代码中,因为C没有继承。

struct sockaddrstruct sockaddr_in和朋友的抽象超类型。系统调用采用抽象类型,您希望传递派生类型的实际实例,而C不知道将struct sockaddr_in *转换为struct sockaddr *是自动安全的,因为它不知道他们之间的关系。