注意:结构体之间不能直接进行强制转换, 必须先转换成指针类型才可以进行结构体间的类型转换, 这里需要明确的定义就是什么才叫强制转换.

强制转换是将内存中一段代码以另一种不同类型的方式进行解读, 因此转换的空间必须与源空间一一对应.

而结构体则是由不固定的多种类型变量组合而成, 因此强制转换时并不确定原格式与目标格式确定的对应关系, 例如一个结构体为3个变量, 而另一个则为2个, 那么就无法确定如何分配.

因此最简单的让计算机可以理解的方式就是先将结构体转换成指针, 然后将指针转换成目标格式, 再读取转换后的指针, 这样计算机就会按照指针的格式读取特定目标代码段了.

 1、sockaddr 、sockaddr_in 、addrinfo比较

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

sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。

sa_data是14字节协议地址。

此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。

但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构sockaddr_in,在netinet/in.h中定义:

struct  sockaddr_in
{
short int sin_family; /* Address family */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
unsigned char sin_zero[8]; /* Same size as struct sockaddr */
};
struct in_addr
{
unsigned long s_addr;
}; typedef struct in_addr
{
union
{
struct
{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
} S_un_b;
struct
{
unsigned short s_w1,
s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
} IN_ADDR;

sin_family指代协议族,在socket编程中只能是AF_INET

sin_port存储端口号(使用网络字节顺序)

sin_addr存储IP地址,使用in_addr这个数据结构

sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。

s_addr按照网络字节顺序存储IP地址。

addrinfo结构是getaddrinfo函数用来保存主机地址信息的结构体。在头文件Ws2tcpip.h中定义。

typedef struct addrinfo
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfo* ai_next; } ADDRINFOA, *PADDRINFOA;

ai_flags:表示getaddrinfo要使用的选项,可赋的值在Winsock2.h中有定义,且可以是几个值的组合。

ai_family:地址族。一般为AF_INET。

ai_socktype:套接字类型。SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_RDM,SOCK_SEQPACKET。

ai_protocol:协议类型。可取的值取决于ai_address和ai_socktype的值。IPPROTO_TCP,IPPROTO_UDP,IPPROTO_RM。

如果ai_family置为AF_IRDA,则ai_protocol必须为0。

ai_addrlen:ai_addr指向的缓冲区的字节数。

ai_canonname:主机的规范化名称(canonical name)。

ai_addr:指向sockaddr结构的指针。

2、IP地址的网络字节顺序和机器字节顺序

210.25.132.181属于IP地址的ASCII表示法,也就是字符串形式。英语叫做IPv4 numbers-and-dots notation。

如果把210.25.132.181转换为整数形式,是3524887733,这个就是整数形式的IP地址。英语叫做binary data。(其实binary是二进制的意思)

Internet地址用“.”间隔的地址可有下列几种表达方式: a.b.c.d,a.b.c,a.b,a   当四个部分都有定值时,每个都解释成一个字节数据,从左到右组成Internet四字节地址。Internet地址以网络字节顺序返回(字节从左到右排列。请注意,当一个Internet地址在Intel机器上表示成一个32位整型数时,则上述的字节为“d.c.b.a”。这是因为Intel处理器的字节是从右向左排列的。
上述中的“a.b.c.d”就为网络字节顺序,而“d.c.b.a”则为机器字节顺序。

 

3、ntohs, ntohl, htons,htonl的比较和详解

ip地址是32位的,端口号是16位的 。

ntohs =net to host short int 16位

htons=host to net short int 16位

ntohs =net to host long int 32位

htonl=host to net long int  32位

u_short PASCAL FAR ntohs( u_short netshort);

netshort:一个以网络字节顺序表达的16位数。本函数将一个16位数由网络字节顺序转换为16位主机字节顺序。

u_short PASCAL FAR htons( u_short hostshort);

hostshort:一个主机字节顺序表达的16位数。 本函数将一个16位数从主机字节顺序转换成16位网络字节顺序。

u_long PASCAL FAR htonl( u_long hostlong);

hostlong:一个主机字节顺序表达的32位数。本函数将一个32位数从主机字节顺序转换成32位网络字节顺序。

u_long PASCAL FAR ntohl( u_long netlong);

 netlong:一个以网络字节顺序表达的32位数。
本函数将一个32位数由网络字节顺序转换为32位的主机字节顺序。

4、 inet_network()、inet_addr()、inet_aton()、inet_ntoa()

int inet_aton(const char *string, struct in_addr *addr);

in_addr_t inet_addr(const char *cp);

in_addr_t inet_network(const char *cp);

char FAR* PASCAL FAR inet_ntoa( struct in_addr in);

函数inet_addr():将IP地址从 点数格式转换成无符号长整型。使用方法如下:

ina.sin_addr.s_addr = inet_addr("132.241.5.10");

注意,inet_addr()返回的地址已经是网络字节格式,所以你无需再调用 函数htonl()。

函数inet_network():inet_network和inet_addr函数都是用于将字符串形式转换为整数形式用的,两者区别很小,inet_addr返回的整数形式是网络字节序,而inet_network返回的整数形式是主机字节序。

函数int inet_aton(const char *string, struct in_addr *addr):是一个改进的方法来将一个字符串IP地址转换为一个32位的网络序列IP地址。输入参数string包含ASCII表示的IP地址。  输出参数addr是将要用新的IP地址更新的结构。   返回值: 如果这个函数成功,函数的返回值非零。如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以他的值会被忽略。
inet_aton函数和上面这俩小子的区别就是在于他认为255.255.255.255是有效的,他不会冤枉这个看似特殊的IP地址。inet_aton函数返回的是网络字节序的IP地址。如:inet_aton("127.0.0.1",&adr_inet.sin_addr))

函数inet_ntoa():将网络地址转换成“.”点隔的字符串格式。本函数将一个用in参数所表示的Internet地址结构转换成以“.” 间隔的诸如“a.b.c.d”的字符串形式。请注意inet_ntoa()返回的字符串存放在WINDOWS套接口实现所分配的内存中。应用程序不应假设该内存是如何分配的。在同一个线程的下一个WINDOWS套接口调用前,数据将保证是有效。返回值:
  若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NULL。其中的数据应在下一个WINDOWS套接口调用前复制出来。函数 inet_ntoa()("ntoa"的含义是"network to ascii"),就像这样: printf("%s",inet_ntoa(ina.sin_addr)); 它将输出IP地址。

5、inet_pton() 和inet_ntop()

Linux下这2个IP地址转换函数,可以在将IP地址在“点分十进制”和“整数”之间转换   而且,inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6。算是比较新的函数了。

inet_pton函数原型如下[将“点分十进制” -> “整数”]   #include <sys/types.h>   #include <sys/socket.h>   #include <arpa/inet.h>   int inet_pton(int af, const char *src, void *dst);   这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中 。

inet_pton 是inet_addr的扩展,支持的多地址族有下列:   af = AF_INET   src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址   转换为in_addr的结构体,并复制在*dst中   af =AF_INET6   src为指向IPV6的地址,,函数将该地址   转换为in6_addr的结构体,并复制在*dst中   如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。

inet_ntop函数原型如下[将“点分十进制” -> “整数”]   #include <sys/types.h>   #include <sys/socket.h>   #include <arpa/inet.h>   const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);   这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和上面相同,只是多了一个参数socklen_t
cnt,他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。

6、gethostbyname和gethostbyaddr

这两个函数仅仅支持IPv4,getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个sockaddr结构的链表而不是一个地址清单。这些sockaddr结构随后可由套接口函数直接使用。如此以来,getaddrinfo函数把协议相关性安全隐藏在这个库函数内部。应用程序只要处理由getaddrinfo函数填写的套接口地址结构。该函数在 POSIX规范中定义了。



#include<netdb.h>

int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );

返回0:  成功

返回非0:  出错



hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串)

service:一个服务名或者10进制端口号数串。

hints:可以是一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。



本函数通过result指针参数返回一个指向addrinfo结构链表的指针,而addrinfo结构定义在头文件netdb.h中:

struct addrinfo{

    int       ai_flags; 

    int       ai_family;

    int       ai_socktype;

    int       ai_protocol;

    socklen_t ai_addrlen;

    char    *ai_canonname;

    struct sockaddr *ai_addr;

    struct addrinfo *ai_next;

};



如果本函数返回成功,那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表。可以导致返回多个addrinfo结构的情形有以下2个:

    1.    如果与hostname参数关联的地址有多个,那么适用于所请求地址簇的每个地址都返回一个对应的结构。

    2.    如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。



我们必须先分配一个hints结构,把它清零后填写需要的字段,再调用getaddrinfo然后遍历一个链表逐个尝试每个返回地址。



getaddrinfo解决了把主机名和服务名转换成套接口地址结构的问题。



其中,如果getaddrinfo出错,那么返回一个非0的错误值。

socket编程相关的结构体和字节序转换、IP、PORT转换函数的更多相关文章

  1. 【网络编程一】主机字节序与网络字节序以及ip地址转换函数

    在计算机设计之初,对内存中数据的处理也有不同的方式,(低位数据存储在低位地址处或者高位数据存储在低位地址处),然而,在通信的过程中(ISO/OSI模型和TCP/IP四层模型中),数据被一步步封装(然后 ...

  2. c#中关于结构体和字节数组转化

    最近在使用结构体与字节数组转化来实现socket间数据传输.现在开始整理一下.对于Marshal可以查阅msdn,关于字节数组与结构体转代码如下: using System; using System ...

  3. Golang面向对象编程-struct(结构体)

    Golang面向对象编程-struct(结构体) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是面向对象编程 面向对象编程(Object Oriented Program ...

  4. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  5. C#结构体和字节数组的转换函数

    在通信过程中,一般我们都会操作到字节数组.特别是希望在不同语言编程进行操作的时候. 虽然C#提供了序列化的支持,不用字节数组也行.但操作字节数组肯定会碰到.   一般都会采用结构来表示字节数组.但结构 ...

  6. C与C# socket 跨平台通讯传输结构体

    最近需要写一个C组成的服务器端与C#的客户端进行交互的软件,刚开始写的时候发现C#端解析时候出现了故障,经过仔细研究后发现原因是发送方传输太快,出现了所谓粘包的现象.也就是在C#端的Receive() ...

  7. 【C语言】结构体占用字节数及存储与空间分配

    我们都知道在数据类型中,char类型占1个字节,short占2个字节,int占4个字节,long占8个字节等等. 在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取 ...

  8. socket编程基础-字节序/IP/PORT转换/域名

    socket编程基础 网络IP操作函数 字符串的IP和32位的IP转换 #include <sys/socket.h> #inlcude <netinet/in.h> #inc ...

  9. Go -- 中结构体与字节数组能相互转化

    编码时如下,假设默认你的结构体为data func Encode(data interface{}) ([]byte, error) { buf := bytes.NewBuffer(nil) enc ...

随机推荐

  1. Opencv结构与内容

    一.Opencv的结构分类: cxcore.cv.ML(Machine Learning).HighGUI.cvcam.cvaux 二.常见结构的内容与算法: 1.cxcore库(基本结构和算法.XM ...

  2. Chrome渲染Transition时页面闪动Bug

    前段时间,有同事和会员反馈使用Chrome访问淘宝首页会出现画面闪动的现象,但是我在Mac和Win下面的Chrome都无法重现这个问题,后来重装了一遍Win7下的Chrome Beta版本,终于重现了 ...

  3. (转)分布式深度学习系统构建 简介 Distributed Deep Learning

    HOME ABOUT CONTACT SUBSCRIBE VIA RSS   DEEP LEARNING FOR ENTERPRISE Distributed Deep Learning, Part ...

  4. python笔记集合

    1.win_64下编译pyd(编译器用的tdm-gcc-5.1) gcc test.c -shared -Ic:\Python27\include -Lc:\Python27\libs -lpytho ...

  5. 【转】C++怎么读写windows剪贴板的内容?比如说自动把一个字符串复制.

    // 复制数据至剪切板BOOL CopyToClipboard(const char* pszData, const int nDataLen){ if(::OpenClipboard(NULL)) ...

  6. Java多线程——同步(一)

    好习惯要坚持,这是我第二篇博文,任务略重,但是要坚持努力!!! 1.竞争条件 首先,我们回顾一下<Java核心技术卷>里讲到的多线程的"竞争条件".由于各线程访问数据的 ...

  7. thrift demo

    基于上一篇博客,安装thrift complier之后,就需要进行跑跑程序,来看看是否如同预期的那种效果. 前面的thrift compiler的主要作用,其实就是为了IDL的,就是防止客户端和服务端 ...

  8. UISwitch控件的使用

    UISwitch控件的作用是提供一个开关给用户,用户可以选择打开或者关闭. UISwitch的基本属性包括: 1.onTintColor:打开状态下的背景颜色 2.thumbTintColor:滑块的 ...

  9. python---hashlib

    简介 用于加密相关的操作,代替了md5模块和sha模块,主要提供SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法. 在python3中已经废弃了md5和sha模块,简单说明 ...

  10. 【MySQL】优化—工欲善其事,必先利其器之EXPLAIN

    接触MySQL已经有一段时间了,了解如何优化它也迫在眉睫了,话说工欲善其事,必先利其器.最近我就打算了解下几个优化MySQL中经常用到的工具.今天就简单介绍下EXPLAIN. 环境准备 Explain ...