`
he91_com
  • 浏览: 377224 次
文章分类
社区版块
存档分类
最新评论

Linux Socket Programming by Example-第二章 IP 地址域 读书笔记

 
阅读更多

所谓的IP地址域名,通俗的理解就是对Socket端的一个标签。

比如,我们每个人有一个独一无二的身份证,身份证则属于国内公安管理域;我们出国则须要护照,这个属于世界范围内的身份域。

而在公司则有一个工号,这个属于公司身份域。

显然,不同的域有不同的规则,存储的信息也不一样。


同样,Socket用于不同的领域,也必然有不同的地址。

由于,早期BSD Socket还没有void *来封装内部不同的地址结构,通用IP地址的结构如下:

struct sockaddr

{
 unsigned short sa_family; /* address family */ |
 char sa_data[14]; /* up to 14 bytes of direct address */

};

早期,16位机器居多,sa_family为2个字节。

下面讲解Linux进程间通信常用的本地域(AF_LOCAL),也称(AF_UNIX)

我们都知道,在Linux中,最常见的标签就是文件路径。所以,本地域也是用独一无二的路径来表示。

#include <sys/un.h>

structsockaddr_un {

sun_familysun_family;

charsun_path[108]; //注意,最后一位不需要存储'\0'

};

使用方法:

// 选择一个存在的路径,通常使用/tmp。

const char pth_unix[] /* pathname */
= "/tmp/my_sock";
// 创建一个无名的Socket,这个时候该socket显然无法跨进程通信。
sck_unix = socket(AF_UNIX,SOCK_STREAM,0);
if ( sck_unix == -1 )
return -1; //错误处理代码。

unlink(pth_unix); //保险起见,先删除文件。

//初始化并设置adr_unix。
memset(&adr_unix,0, sizeof adr_unix);
dr_unix.sun_family = AF_UNIX;
strncpy(adr_unix.sun_path,pth_unix,
sizeof adr_unix.sun_path-1)
[sizeof adr_unix.sun_path-1] = 0;

//将路径与前面创建的无名Socek进行绑定。
len_unix = SUN_LEN(&adr_unix);
z = bind(sck_unix,
(struct sockaddr *)&adr_unix,
len_unix);


本地域,由于使用的是Linux系统的文件路径,很显然只能跨进程通信。为了实现PC间的网络通信,

我们必须使用一种新的域,即IP 地址域(AF_INET)。我们将Socket同每台PC的IP地址进行绑定

IP地址有2个协议,IPv4和IPv6. IPv4是32位,而IPv6是128位。这里只重点介绍IPv4域。

#include <netinet/in.h>

struct sockaddr_in {
sa_family_t sin_family; /* Address Family */
uint16_t sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
unsigned char sin_zero[8]; /* Pad bytes */
};


struct in_addr {
uint32_ t s_ addr; /* Internet address */
};


注意,由于历史的原因,不同芯片存储数据的字节顺序是不一样的。以整数0x12345678为例。

Littel-Endian 0x78 0x56 0x34 0x12

Big-Endian 0x12 0x34 0x56 0x78

★网络序是Big-Endian

在实际项目中用以下宏判断:

#define IS_BigEndian(value) { int x = 0x12345678; unsigned char test = *((unsigned char*)&x); value = (test == 0x12) ? 1 : 0;}


这样便有一个网络顺序与PC本地顺序间的不一致问题。为了解决这一问题,

系统提供了相关的转换函数。h -> host 本地 n-> network 网络. s: 16bit l :32bit

unsigned long htonl(unsigned long hostlong);
unsigned short htons(unsigned short hostshort);
unsigned long ntohl(unsigned long netlong);
unsigned short ntohs(unsigned short netshort);


使用方法和上面的本地域基本一样,只是数据结构的设置有差别,数据的初始化方法如下:

struct sockaddr_in adr_inet;/* AF_INET */
int le n_inet; /* length */
const unsigned char IPno[] = {
127, 0, 0, 23 /* Local loopback */ // 127.0.0.23
};
memset(&adr_inet,0,sizeof adr_inet);

adr_inet.sin_family = AF_INET;

adr_inet.sin_port = htons(9000); // port = 9000

memcpy(&adr_inet.sin_addr.s_addr,IPno,4);


接下来,书中还提到了其他几种地址域。

X.25 Address:

#include <linux/x25.h>

struct sockaddr_x25 {
sa_family_t sx25_family; /* Must be AF_X25 */
x25_address sx25_addr; /* X.121 Address */
};

typedef struct {
char x25_addr[16];
} x25_address;


使用:

struct sockaddr_x25 adr_x25;/* AF_X25 */

const char x25_host[] /* X.121 addr */
= "79400900";

adr_x25.sx25_family = AF_X25;
strcpy(adr_x25.sx25_addr.x25_addr,x25_host);

小技巧:

cat /proc/net/x25 查看系统当前X.25 Socket连接信息。


AF_INET6— IPv6 下一代IP地址

struct sockaddr_in6 {
sa_family_t sin6_family;
uint16_t sin6_port; /* port # */
uint32_t sin6_flowinfo; /* flow info */
struct in6_addr sin6_addr; /* IPv6 address */
};


struct in6_addr {
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];

} in6_u;

};
• AF_AX25— Amateur Radio X.25 protocol
• AF_APPLETALK— Linux AppleTalk protocol implementation

具体数据结构请百度或参考书本。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics