我自学了套接字是如何工作的。 承认,我不是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);
}
有人可以告诉我什么是真正传递给关于结构演员的绑定函数?
我们在该结构中拥有哪些成员?
我该如何检查?
由于
答案 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_family
和struct
的共同点(和#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 *
,并且不需要演员,但是没有写过因为:
它在语义上更有意义 - struct sockaddr *
没有被写入接受任何指针,只有一个bind()
是struct
&#34;衍生&#34;来自struct sockaddr
;以及
原始套接字API于1983年发布,早于1989年的ANSI C标准,其前身--K&amp; RC - 只是没有void *
,所以你要去在任何情况下都必须把它投射到某个东西。
答案 1 :(得分:2)
强制转换显示在套接字代码中,因为C没有继承。
struct sockaddr
是struct sockaddr_in
和朋友的抽象超类型。系统调用采用抽象类型,您希望传递派生类型的实际实例,而C不知道将struct sockaddr_in *
转换为struct sockaddr *
是自动安全的,因为它不知道他们之间的关系。