【网络编程基础笔记】struct sockaddr和struct sockaddr_in的区别和用法
2013-04-26 19:36
627 查看
编写网络应用程序时,经常会用到sockaddr和sockaddr_in这两个结构体,对于新手来说,比较容易搞混它们的区别和使用方法。本文的笔记试图讲清楚它们之间的关系和正确的用法。
1. struct sockaddr_in(针对IPv4使用)
struct sockaddr_in是linux kernel针对IPv4用到的socket address structure(针对IPv6则定义了struct sockaddr_in6来实现类似的结构),写网络应用程序时,我们需要引用其头文件<netinet/in.h>文件。
以sockaddr_in为例,其定义代码如下(严格地说,应该是redhat linux 2.6.9中的定义,vendor或kernel version不同,相关结构的定义形式可能会有差别,但底层的数据表示其实是一致的):
由struct sockaddr_in定义的最后1行可知,sockaddr_in的size其实是依赖struct sockaddr的size的,通过sin_zero字段的padding,可以使这两个structs的size始终保持相等,以方便在调用socket api时两种类型的指针互转。
如果感兴趣,可以在下面的源文件中查看sockaddr_in在linux kernel source tree中的定义:
a. 若是linux 2.6.x版本,可在include/linux/in.h中查看
b. 若是linux 3.x版本,可在include/uapi/linux/in.h中查看
另外需要说明的是,在某些版本提供的linux kernel(如4.3 BSD-Reno)中,struct sockaddr_in的定义会多一个uint8_t sin_len字段(这种情况下,与此对应的struct sockaddr也会有uint8_t
sin_len字段)。根据《UNIX Network Programming Volume 1》3.1节中的说法,我们可以不关注这个细节(即可以认为这个sin_len字段存在与否对我们的应用程序是透明的)。这个字段不是每种Linux版本都提供,且POSIX标准中对struct sockaddr_in的定义是否需包含该字段不做要求。
2. struct sockaddr
与struct sockaddr_in的定义相比,struct sockaddr的定义相对简单些。其被称为"Generic Socket Address Structure",在<sys/socket.h>中的定义如下:
常用的库函数如bind,accept,connect,sendto,recvfrom,getpeername及getsockname等,其函数原型中均以Generic Socket Address Structrues的指针(struct sockaddr *)作为地址参数。
如果感兴趣,可以在下面的源文件中查看sockaddr在linux kernel source tree中的定义:
a. 若是linux 2.6.x版本,可在include/linux/socket.h中查看
b. 若是linux 3.x版本,可在include/linux/socket.h中查看
3. 两种structs的使用方法
关于如何正确使用这两个结构体,UNP一书中有所说明:
From an application programmer's point of view, the only use of these generic socket address structures is to cast pointers to protocol-specific structures.
总之,对于编写网络应用程序的程序员来说,通常的做法是定义struct sockaddr_in类型的变量,对其family、port、addr等字段赋值后,在调用socket相关api时,将其指针强制转换为struct sockaddr *类型即可(由它们的定义代码可知,二者的size始终保持相等,均为16 bytes,因此,对其指针做强制类型转换后不会引起问题),内核会根据sockaddr.sin_family字段指定的协议类型做进一步的底层操作。
此外,UNP中还提到的API不用void *作为通用参数(这是屏蔽细节的惯用做法,如memset/memcpy系列函数的参数类型),而选择struct sockaddr *作为参数的原因:
From the kernel's perspective, another reason for using pointers to generic socket address structures as arguments is that the kernel must take the caller's pointer,
cast it to a struct sockaddr *, and then look at the value of sa_family to determine the type of the structure. But from an application programmer's perspective, it would be simpler if the pointer type was void *, omitting the need for the explicit cast.
【参考资料】
UNIX Network Programming Volume 1. 第3章
================== EOF ====================
1. struct sockaddr_in(针对IPv4使用)
struct sockaddr_in是linux kernel针对IPv4用到的socket address structure(针对IPv6则定义了struct sockaddr_in6来实现类似的结构),写网络应用程序时,我们需要引用其头文件<netinet/in.h>文件。
以sockaddr_in为例,其定义代码如下(严格地说,应该是redhat linux 2.6.9中的定义,vendor或kernel version不同,相关结构的定义形式可能会有差别,但底层的数据表示其实是一致的):
/* Type to represent a port. */ typedef uint16_t in_port_t; /* Internet address. */ typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; /* 由于TCP/IP发展的历史原因,这里只有1个字段还用struct包装起来 */ /*《UNIX Network Programming Volume 1》3.1节对此有一段解释,这里不再赘述 */ }; /* Structure describing an Internet socket address. */ struct sockaddr_in { __SOCKADDR_COMMON (sin_); /* 本行等价为: sa_family_t sin_family */ /* gcc -E查看preprocess阶段宏展开后的源码可以确认这一点 */ in_port_t sin_port; /* Port number. */ struct in_addr sin_addr; /* Internet address. */ /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)]; };
由struct sockaddr_in定义的最后1行可知,sockaddr_in的size其实是依赖struct sockaddr的size的,通过sin_zero字段的padding,可以使这两个structs的size始终保持相等,以方便在调用socket api时两种类型的指针互转。
如果感兴趣,可以在下面的源文件中查看sockaddr_in在linux kernel source tree中的定义:
a. 若是linux 2.6.x版本,可在include/linux/in.h中查看
b. 若是linux 3.x版本,可在include/uapi/linux/in.h中查看
另外需要说明的是,在某些版本提供的linux kernel(如4.3 BSD-Reno)中,struct sockaddr_in的定义会多一个uint8_t sin_len字段(这种情况下,与此对应的struct sockaddr也会有uint8_t
sin_len字段)。根据《UNIX Network Programming Volume 1》3.1节中的说法,我们可以不关注这个细节(即可以认为这个sin_len字段存在与否对我们的应用程序是透明的)。这个字段不是每种Linux版本都提供,且POSIX标准中对struct sockaddr_in的定义是否需包含该字段不做要求。
2. struct sockaddr
与struct sockaddr_in的定义相比,struct sockaddr的定义相对简单些。其被称为"Generic Socket Address Structure",在<sys/socket.h>中的定义如下:
struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };
常用的库函数如bind,accept,connect,sendto,recvfrom,getpeername及getsockname等,其函数原型中均以Generic Socket Address Structrues的指针(struct sockaddr *)作为地址参数。
如果感兴趣,可以在下面的源文件中查看sockaddr在linux kernel source tree中的定义:
a. 若是linux 2.6.x版本,可在include/linux/socket.h中查看
b. 若是linux 3.x版本,可在include/linux/socket.h中查看
3. 两种structs的使用方法
关于如何正确使用这两个结构体,UNP一书中有所说明:
From an application programmer's point of view, the only use of these generic socket address structures is to cast pointers to protocol-specific structures.
总之,对于编写网络应用程序的程序员来说,通常的做法是定义struct sockaddr_in类型的变量,对其family、port、addr等字段赋值后,在调用socket相关api时,将其指针强制转换为struct sockaddr *类型即可(由它们的定义代码可知,二者的size始终保持相等,均为16 bytes,因此,对其指针做强制类型转换后不会引起问题),内核会根据sockaddr.sin_family字段指定的协议类型做进一步的底层操作。
此外,UNP中还提到的API不用void *作为通用参数(这是屏蔽细节的惯用做法,如memset/memcpy系列函数的参数类型),而选择struct sockaddr *作为参数的原因:
From the kernel's perspective, another reason for using pointers to generic socket address structures as arguments is that the kernel must take the caller's pointer,
cast it to a struct sockaddr *, and then look at the value of sa_family to determine the type of the structure. But from an application programmer's perspective, it would be simpler if the pointer type was void *, omitting the need for the explicit cast.
【参考资料】
UNIX Network Programming Volume 1. 第3章
================== EOF ====================
相关文章推荐
- Java基础知识强化之网络编程笔记19:Android网络通信之 HttpClient和传统Post、Get方式的区别
- linux网络编程之sockaddr_in和in_addr区别
- struct sockaddr_in和struct sockaddr有什么区别
- 整理:Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解
- 整理:Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解
- Java基础知识强化之网络编程笔记21:Android网络通信之 Android常用OAuth登录(获取令牌信息)
- 转载 :struct sockaddr_in等Socket编程相关数据类型定义
- 【Linux网络编程笔记】TCP短连接产生大量TIME_WAIT导致无法对外建立新TCP连接的原因及解决方法—基础知识篇
- 网络编程笔记一:基础概念及相关java类入门
- struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系
- 黑马程序员_java基础笔记(08)...GUI,网络编程,正则表达式
- python 网络编程基础学习笔记(1)-网络客户端-socket
- 黑马程序员 JAVA基础之网络编程笔记
- 网络编程里几个结构 in_addr 、sockaddr_in 、pcap_addr 之间的关系
- Java基础知识强化之网络编程笔记09:TCP之客户端键盘录入服务器写到文本文件中
- Java基础知识强化之网络编程笔记25:Android网络通信之 Future接口介绍(Java程序执行超时)
- struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系
- 网络编程1--毕向东java基础教程视频学习笔记
- struct sockaddr、sockaddr_in、sockaddr_un的区别和联系
- struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系