Lar*_*rry 1 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));
Run Code Online (Sandbox Code Playgroud)
我无法想象我们从这个演员(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);
}
Run Code Online (Sandbox Code Playgroud)
有人可以告诉我什么是真正传递给关于结构演员的绑定函数?
我们在该结构中拥有哪些成员?
我怎么检查呢?
谢谢
这是struct sockaddr
:
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
Run Code Online (Sandbox Code Playgroud)
例如,这里是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];
};
Run Code Online (Sandbox Code Playgroud)
并且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;
};
Run Code Online (Sandbox Code Playgroud)
你会注意到他们都共享前两个成员.因此,类似的函数bind()
可以接受指向泛型的指针,struct sockaddr
并且知道,无论struct
它实际指向什么具体,它都具有sa_len
和sa_family
共同(并且"共同"在这里意味着"在内存中以相同的方式布局",所以两个struct
s 都有一个sa_family
成员,但是它们在两个不同的struct
s中处于完全不同的位置是没有任何奇怪的.技术上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 */
}
Run Code Online (Sandbox Code Playgroud)
(迂腐说明:从技术上讲,根据C标准[C11第6.5.2.3.6节],struct
如果你将它们嵌入到一个中union
,你应该只检查这样的常见初始部分,但实际上它几乎是总是在没有一个的情况下工作,为简单起见,我没有在上面的代码中使用过一个.
当你实际上没有真正的OOP结构时,它基本上是一种获取多态的方法.换句话说,这意味着你不必有一堆类似的功能bind_in()
,bind_in6()
以及它所有的休息,一个单一的bind()
功能可以处理所有这些,因为它可以找出是什么类型的struct
反倒(前提是你是你设定sa_family
当然是正确的成员).
你需要实际演员的原因是因为C的类型系统需要它.你有一个通用指针void *
,但除此之外一切都必须匹配,所以如果一个函数接受struct sockaddr *
它只是不会让你传递任何其他东西,包括一个struct sockaddr_in *
.演员基本上告诉编译器"我知道我在做什么,在这里,相信我",它会为你放松规则.bind()
本来可以写成接受一个void *
而不是一个struct sockaddr *
和一个演员阵容是没有必要的,但它不是那样写的,因为:
它在语义上更有意义 - bind()
不写入接受任何指针,只是一个struct
从"派生"的struct sockaddr
; 和
最初的套接字API是在1983年发布的,它早在1989年的ANSI C标准之前,它的前身--K&R C - 就没有了void *
,所以你不得不在任何情况下将其转换为某种东西.
归档时间: |
|
查看次数: |
957 次 |
最近记录: |