格式化IPv4套接口地址
在Linux下使用最多的地址族为AF_INET。这为一个套接口指定一个IPv4套接口地址,从而使得这个套接口可以通过TCP/IP网络与其他的主机进行通信。定义了sockaddr_in结构的包含头文件是由下面的C语句来进行定义的:
#include <netinet/in.h>
下面的例子是一个用于网络地址的sockaddr_in结构。另外显示了一个in_addr结构,因为sockaddr_in结构会在他的定义中使用这个结构。
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 */
};
其成员描述如下:
sin_family成员出现在与通用套接口定义中的sa_family相同的存储位置。sin_family会被初始化为AF_INET。
sin_port成员为这个套接口地址定义了TCP/IP的端口号。这个值必须为网络字节顺序。
sin_addr成员定义为in_addr结构,用于以网络字节顺序存放IP地址。如果我们检测in_addr,我们就会发现他由32位无符号整数组成。
最后,结构的剩余部分由8个字节的成员sin_zero[8]填充为16个字节。
这个地址结构的物理布局如下图所示:
从上图中我们可以看出,sin_port成员使用两个字节,而sin_addr使用4个字节。这两个成员都在其上放置了一个标志用来表明这些值必须为网络字节顺序。
理解网络字节顺序
不同的CPU体系结构对于多个字节的数据,16位,32位或者更多,会有不同的安排方式。最基本的两个字节顺序为:
大端
小端
其他的组合也是可以的,但是我们在这里并不考虑这些情况。下面这个图显示了这两种不同的字节顺序:
上个图所演示的为十进制的数4660,以十六进制表示则为0x1234.这个数值需要用两个字节来表示。从这个图我们可以看到或者我们可以首先放置最重的字节(大端),或者是我们可以首先放置最不重要的字节(小端)。这种选择是非常模糊的,而这最终涉及到CPU的设计。
我们也许已经知道,Intel CPU使用小端字节顺序。其他的CPU,例如Motorola 68000系列使用大端字节顺序。在这里我们要考虑的最重要的事情就是这两种类型的CPU都存在,而且他们要连接到同一个网络。
如果一个Motorola的CPU向网络中写入一个16位的数字,并且为一个Intel CPU接收时会发生什么呢?这些字节将会为Intel CPU进行反序解释,从而这个值看起来就是十六进制的0x3412。
为网络存在的协议,大端字节顺序将在网络上使用。只要通过网络传输的所有消息遵循这个序列,所有软件就可以顺利通信。
这就将我们带回了AF_INET地址族。TCP/IP端口号(sin_port)以及IP地址(sin_addr)必须是网络字节顺序。BSD套接口地址要求作为程序员的我们在格式化地址必须考虑到这一点。
执行端转换
有一些函数提供用来帮助我们简化端转换。需要考虑两个方向的端转换:
主机顺序到网络顺序
网络顺序到主机顺序
主机顺序是指我们的CPU所使用的字节顺序。对于Intel CPU来说是指小端字节顺序。网络字节顺序,正如我们已经了解到的,为大端字节顺序。
同时也有两类转换函数:
短整数(16位)转换
长整数(32位)转换
下面所提供的是转换函数的概要:
#include <netinet/in.h>
unsigned long htonl(unsigned long hostlong);
unsigned short htons(unsigned short hostshort);
unsigned long ntohl(unsigned long netlong);
unsigned short ntohs(unsigned short netshort);
这些函数的使用是很简单的。例如,要将一个短整数转换为网络顺序,我们可以使用下面的代码:
short host_ short = 0x1234;
short netw_short;
netw_short = htons(host_short);
netw_short值将接收转换为网络字节后的合适值。将一个网络字节顺序转换为一个主机顺序也是一样简单的:
host_short = ntohs(netw_short);
初始化一个宽网地址
现 在我们已准备好来创建一个网络地址了。在这里演示的这个例子需要这个地址必须为宽的。这经常是当我们连接到一个远程服务时完成的。这个原因是因为我们的主 机也许会有两个或是多个网卡,每一个网卡有一个不同的IP地址。而且,Linux同时也允许每一个网卡有多个IP地址。当我们指定一个宽的IP地址,我们 允许系统选择到远程服务的路由。内核会在连接建立时确定我们的最终本地套接口地址。
有时我们希望内核为我们赋一个本地端口号,这是通过将sin_port指定为0来做到的。下面的代码演示了如何使用一个宽IP地址与一个宽端口号来初始化一个AF_INET地址。
1: struct sockaddr_in adr_inet;
2: int adr_len;
3:
4: memset(&adr_inet,0,sizeof adr_inet);
5:
6: adr_inet.sin_family = AF_INET;
7: adr_inet.sin_port = ntohs(0);
8: adr_inet.sin_addr.s_addr = ntohl(INADDR_ANY);
9: adr_len = sizeof adr_inet;
描述如上:
1 使用sockaddr_in结构来定义一个adr_inet变量。
2 通过调用memset函数将adr_inet结构清0。
3 通过将AF_INET赋给adr_inet.sin_family来建立地址族。
4 在第7行指定一个宽端口号。注意ntohs函数的使用。值0指明一个宽端口号。
5 在第8行赋一个宽IP地址。注意执行端转换的ntohl函数的使用。
6 地址的尺寸简单的由adr_inet结构的尺寸来计算。
另一个常用的IP地址为127.0.0.1。这是指loopback设备。回环设备允许我们在同一个主机上与另一个进程进行通信。第8行的代码可以用下面的代码为进行替换:
adr_inet.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
这会通过回环设备来定位我们的主机。
初始化一个指定的网络地址
在前一个部分我们处理了一个简单的AF_INET地址的例子。当我们要在地址中建立一个指定的IP地址事情就会变得更为复杂。下面是一个程序示例:
/*
* af_inet.c
* Establishing a specific AF_INET
* Socket Address
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
/*
* This function reports the error and
* exits back to the shell:
*/
static void bail(const char *on_what)
{
perror(on_what);
exit(1);
}
int main(int argc,char **argv,char **envp)
{
int z; /* Status return code */
int sck_inet; /* Socket */
struct sockaddr_in adr_inet; /* AF_INET */
int len_inet; /* length */
const unsigned char IPno[] = {
127,0,0,23 /* Local loopback */
};
/* Create an IPv4 Internet Socket */
sck_inet = socket(AF_INET,SOCK_STREAM,0);
if(sck_inet == -1)
bail("socket()");
/*Create an AF_INET address */
memset(&adr_inet,0,sizeof adr_inet);
adr_inet.sin_family = AF_INET;
adr_inet.sin_port = htons(9000);
memcpy(&adr_inet.sin_addr.s_addr,IPno,4);
len_inet = sizeof adr_inet;
/* Now bind the address to the socket */
z = bind(sck_inet,(struct sockaddr *)&adr_inet,len_inet);
if(z == -1)
bail("bind()");
/* Display all of our bound sockets */
system("netstat -pa --tcp 2>/dev/null | "
"sed -n '1,/^Proto/P;/af_inet/P'");
close(sck_inet);
return 0;
}
在这个程序所用的步骤是我们前面的例子程序相同。然而43到48行还需要一些解释:
1 在第30行使用sockaddr_in结构来定一个名为adr_inet的变量名。另外,在第31行将套接口地址的长度定义为一个整数len_inet。
2 在第32行与第33行定义了一个无符号字符数组IPno[4]。在这里指定了一个IP地址:127.0.0.23。
3 在第43行将adr_inet结构清0。
4 在第45行建立了AF_INET地址族。
5 在这个例子中在第46行选择TCP/IP的9000端口建立连接。在这里我们要注意在第46行htons函数的用法。
6 在第47行将字符数组IPno[4]拷贝到adr_inet.sin_addr.s_addr的位置。因为这些字节是按照网络字节顺序来定义的,所以不需要端转换函数。
7 计算地址结构的大小。
在这里我们可以看出网络地址一个确定的长度。如果我们回顾一下上一个例子,我们就可以很容易的看出来。然而,我们要记得AF_LOCAL的地址长度是变化的。对于AF_INET的地址,我们只需简单的提供sockaddr_in结构的大小。在C语言中为:
sizeof(struct sockaddr_in)
指定一个X.25地址
套接口接口允许程序员使用在Linux下可用的其他的协议。我们要处理的代码之间的一个主要区别就是套接口是如何编址的。我们已经知道如何初始化一个AF_INET或是AF_LOCAL地址。X.25地址的创建也是类似的。
用来定义X.25协议地址的结构为sockaddr_x25结构。下面的包含语句定义了这个结构:
#include <linux/x25.h>
X.25套接口地址结构如下:
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;
我们可以注意到有一个sx25_family成员出现在与通用套接口结构相同的前两个字节处。对于这个地址而言,必须为AF_X25。
一个X.25网络地址是由一系列的十进制数组成的。下面的af_x25.c程序用来演示如何创建一个X.25地址。
/*af_x25.c
*
* x.25 Socket Address Example:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/x25.h>
/*
* This function reports the error and exits back to the shell:
*/
static void bail(const char *on_what)
{
perror(on_what);
exit(1);
}
int main(int argc,char **argv,char **envp)
{
int z; /* Status return code */
int sck_x25; /* Socket */
struct sockaddr_x25 adr_x25; /* AF_X25 */
int len_x25; /* length */
const char x25_host[] /* X.121 addr */
= "79400900";
/* create an AF_X25 socket */
sck_x25 = socket(AF_X25,SOCK_SEQPACKET,0);
if(sck_x25 == -1)
bail("Socket()");
/* Form an AF_X25 Address */
adr_x25.sx25_family = AF_X25;
strcpy(adr_x25.sx25_addr.x25_addr,x25_host);
len_x25 = sizeof adr_x25;
/* Bind the address to the socket */
z = bind(sck_x25,(struct sockaddr *)&adr_x25,len_x25);
if(z == -1)
bail("bind()");
puts("X.25 SOCKETS :");
system("cat /proc/net/x25");
return 0;
}
创建地址的代码包含如下的基本步骤:
1 在第29行使用sockaddr_x25结构来定义adr_x25变量。在第30行定义一个int类型的长度变量len_x25。
2 在第31行与第32行定义了一个固定的x25_host[],作为要建立了X.25地址。
3 在第41行将地址簇指定为AF_X25。
4 在第42行将主机地址号拷贝到地址结构中,并且指定了一个结束符。
5 sockaddr_x25结构的长度是在当前Linux实现下使用的正确长度。
注 意,这个程序并没有使用netstat命令。这时因为此时netstat命令并不会报告AF_X25套接口。相反,在这个例子中我们使用cat命令来将 /proc/net/x25的内容拷贝到标准输出。然而为了这个例子能够成功,我们必须将proc文件系统的支持编译进入我们的内核。
程序的运行结果如下:
$ ./af_x25
X.25 SOCKETS :
dest_addr src_addr dev lci st vs vr va t t2 t21 t22 t23 Snd-Q Rcv-Q inode
* 79400900 ??? 000 0 0 0 0 0 3 200 180 180 0 0 104172
$
分享到:
相关推荐
Linux Socket学习(十四).txt可能讨论了套接字选项和控制消息,如setsockopt()和getsockopt(),它们允许程序员调整Socket的行为。而Linux Socket学习(十一).txt可能会讲解错误处理和异常情况,例如连接超时、中断...
《实战Linux Socket编程》是...总之,《实战Linux Socket编程》的配套源代码是一个宝贵的资源,它使学习者能够动手实践,从而更好地掌握网络编程的核心概念和技术,对于提升Linux系统下的网络编程能力具有重要意义。
在IT行业中,Linux Socket是进行网络通信的重要工具,尤其对于系统和网络程序员来说,理解和掌握Linux Socket编程至关重要。本示例代码提供了客户端(client)和服务器端(server)的实现,帮助初学者深入理解如何在...
在IT领域,Linux Socket编程是网络通信的核心技术之一,它为开发者提供了在Linux操作系统上实现进程间通信(IPC)和网络通信的接口。本实战指南将深入探讨这一主题,帮助你掌握如何在Linux环境中构建高效的网络应用...
在Linux操作系统中,Socket是一种进程间通信机制,它允许不同进程或者不同计算机之间的通信。本教程将深入探讨Linux下的socket编程,包括服务器和客户端的实现。我们主要关注以下几个知识点: 1. **Socket基本概念*...
本篇文章将根据给定文件“linux socket学习.pdf”的内容进行展开,重点讨论 socket 的定义、如何创建 socket 以及 socket 与其他常见 I/O 操作的区别。 #### 二、理解 Socket ##### 2.1 定义 Socket Socket 可以...
本压缩包“linuxsocket.zip”包含了基于TCP/IP协议的socket通信测试代码,是学习Linux应用编程的一个实用资源。这里我们将深入探讨Linux TCP/IP socket编程的相关知识点。 1. **TCP/IP协议栈**:TCP/IP协议栈是...
通过本书的学习,读者可以掌握如何在Linux环境中使用Socket进行网络通信,构建高性能、稳定的网络应用。下面将根据提供的压缩包文件名“实战 Linux Socket编程代码”来解析其中可能包含的知识点。 1. **Socket基础...
Linux Socket编程是网络编程的重要组成部分,它为开发者提供...通过这个实战教程,开发者将学习如何在Linux环境中创建和管理Socket,实现网络通信功能,这对于开发服务器应用、网络工具或分布式系统是至关重要的技能。
在Linux操作系统中,Socket接口是应用程序与网络协议交互的主要接口,它允许程序通过网络发送和接收数据。在本文中,我们将深入探讨“Linux Socket网络驱动深度分析”这一主题,特别是当应用尝试创建一个用于捕获...
Linux Socket是Linux操作系统中用于进程间通信(IPC)的一种接口,它允许程序通过网络协议进行数据传输。在本文中,我们将深入探讨Linux ...通过IBM技术论坛的文章,你可以更深入地了解和学习Linux Socket的各种细节。
### Linux Socket Programming (Linux 套接字编程) #### 知识点概览: 1. **Socket编程基础** ...通过以上知识点的学习,读者可以深入了解Linux环境下的Socket编程,并能够掌握如何设计和实现网络通信程序。
Linux Socket实战编程是深入理解网络通信机制的...总的来说,这份资源对于想要深入理解和精通Linux Socket编程的IT从业者来说是一份宝贵的资料,通过学习和实践,可以显著提升网络编程能力,为职业发展打下坚实基础。
Gay撰写,为读者提供了丰富的实例和深入的理论知识,是学习Linux Socket编程的绝佳资源。 **二、基本Socket概念** ### 1. Socket简介 在Linux环境下,Socket是一种进程间通信(IPC)的方式,它提供了一种在两个...
在IT行业中,网络通信是至关重要的部分,而Linux Socket编程是实现这一目标的关键技术。Socket是一种接口,允许应用程序通过网络发送和接收数据。本篇将深入探讨标题为"Linux Socket两则示例"的资源,其中包括`echo_...
10. **学习资源**:学习Socket编程,可以参考《UNIX Network Programming》等经典书籍,同时网上有许多关于Linux Socket编程的教程和示例代码可供学习。 总之,"Linux下的socket聊天室程序"是一个很好的实践项目,...
《Linux Socket编程示例》...以上仅为《Linux Socket编程示例》部分章节的知识点总结,实际书中还包含了更多深入的技术细节和实战案例,对于希望掌握Linux环境下网络编程技术的学习者而言,是一本不可多得的参考书籍。
本资源“实战Linux Socket编程”旨在帮助你深入理解并掌握这一关键技能,尤其对于那些希望在嵌入式领域有所建树的开发者来说,它是不可或缺的学习资料。 在Linux系统中,Socket编程主要涉及以下几大知识点: 1. **...
在Linux操作系统中,Socket是一种进程间通信(IPC)机制,广泛用于网络编程,它提供了标准接口,使得应用程序能够发送和接收数据。本篇将详细解析Linux Socket客户端和服务器的源代码,帮助理解其工作原理。 一、...