《TCP/IP网络编程》第3章 笔记&代码&注释

IP(网络协议Internet Protocol):为了收发网络数据而给计算机分配的值。

端口号:为了区分程序中创建的套接字而分配给套接字的序号。

网络地址

  • IPv4 4字节地址族(目前主要使用)
  • IPv6 16字节地址族(为了应对IP地址耗尽而提出的标准,但现在仍未普及)

IPv4

IPv4标准的4字节地址分为网络地址主机(计算机)地址,且分为A,B,C,D,E类型,E类为已预约地址一般不会使用。

  1字节 1字节 1字节 1字节 首字节范围
A类 网络ID 主机ID 主机ID 主机ID 0~127:1.0.0.1—126.155.255.254
B类 网络ID 网络ID 网络ID 主机ID 128~191:128.0.0.1—191.255.255.254
C类 网络ID 网络ID 网络ID 主机ID 192~223:192.0.0.1—223.255.255.254
D类 网络ID 网络ID 网络ID 网络ID

(D类不分网络和主机地址,前四位固定为1110)

224.0.0.1—239.255.255.254

端口号(port)

端口号用于区分套接字:当数据传输到主机上时,但计算机并不知道数据用于哪一个程序(如何分配套接字)。

端口号由16为组成,可分配端口号为0~65535,但0~1023位知名端口号,一般不使用。

TCP与UDP不会共用端口号:TCP使用了2333端口,UDP仍可使用2333端口,但其他TCP套接字就不可以使用2333端口。

数据传输

浏览IP地址的网络地址 → 将数据传到该网络地址的路由器 → 路由器接收数据后,根据主机地址寻找目标计算机 → 计算机收到数据后,根据端口号将数据进行分配

地址信息的表示

SOCKADDR_IN servAddr;//windows
struct sockaddr_in serv_addr;//Linux
......
bind(ServerSock,(SOCKADDR*)&servAddr,sizeof(servAddr));//windows
bind(serv_sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//Linux

在使用bind()填写地址信息可以看到,servAddr是SOCKADDR_IN数据类型,在SOCKADDR_IN内,他保存了:

//Linux
struct sockaddr_in {
    short            sin_family;       // 2 bytes e.g. AF_INET, AF_INET6
    unsigned short   sin_port;    // 2 bytes e.g. htons(3490)
    struct in_addr   sin_addr;     // 4 bytes see struct in_addr, below
    char             sin_zero[8];     // 8 bytes zero this if you want to use
};

sockaddr用其余14个字节来表示sa_data,而sockaddr_in把14个字节拆分成sin_port, sin_addr和sin_zero.

sockaddr和sockaddr_in包含的数据都是一样的,但他们在使用上有区别:程序员不应操作sockaddr,sockaddr是给操作系统用的,因此我们会在向bind()传参时,对SOCKADDR_IN(sockaddr_in)进行强制类型转换。

网络字节序

  • 大端序 高位字节存放到低位地址
  • 小端序 高位字节存放到高位地址

当数据传输并进行解析后,因为计算机布偶听的字节序会导致不同的情况:

00000000 00000000 00000000 00000001(大端序)

00000001 00000000 00000000 00000000 (小端序)

字节序转换

  • unsigned short htons(unsigned short);
  • unsigned short ntohs(unsigned short);
  • unsigned short htonl(unsigned long);
  • unsigned short ntohl(unsigned long);

从函数名称理解,如:htonl→ 将long整型数据主机字节序(host)转换为网络字节序

为了保证数据的准确传输与解析,必须保证收发机器都为相同的大端序(或将数据进行转换处理)

htons(),htonl()函数(windows)

这两个函数在Linux上并无区别:

unsigned short host_port= 0x1234;
unsigned short net_port;
unsigned long host_addr=0x12345678;
unsigned long net_addr;
//.....
net_port=htons(host_port);//net_port=0x3412
net_addr=htonl(host_addr);//net_addr=0x78563412;

inet_addr()函数(wiodows)

const char* addr="127.212.124.78";
unsigned long conv_addr=inet_addr(addr);//0x4e7cd47f

函数将IP地址转换为32位整数型,且可以检测无效的IP地址。

inet_ntoa()函数(wiodows)

struct sockaddr_in addr
char* strPtr;

addr.sin_addr.s_addr=htonl(0x1020304);
strPtr = inet_ntoa(addr.sin_addr);//1.2.3.4

将一个32位网络字节序的二进制IP地址转换成相应的点分十进制的IP地址(返回点分十进制的字符串在静态内存中的指针)。

代码:

https://github.com/ChristmasError/TCP-IP-Network-programming/tree/master/%E7%AC%AC%E4%B8%89%E7%AB%A0%20%E5%9F%BA%E4%BA%8Ewindows%E7%9A%84%E5%AE%9E%E7%8E%B0

网络地址初始化

//windows
#define ser_port 8888
SOCKADDR_IN servAddr;
char *ser_ip="211.217.168.13"
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;//地址族 IPv4
servAddr.sin_addr.s_addr = htonl(ser_ip);//基于字符串的IP地址初始化
servAddr.sin_port = htons(ser_port);//基于整形数据的端口号初始化

以上代码是windows内常见的网络地址初始化方法。

INADDR_ANY

//....
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//....

在对ip地址初始化,我们可以使用INADDR_ANY,采用这种方式,会自动获取运行服务器端的计算机的IP地址而不必自己输入,优先考虑这种方式(除非客户端中带有一部分服务器端功能)。

在这里, 127.0.0.1是回送地址(loopback address),指计算机自身的IP地址,第一章中,服务器端和客户端在同一机器上运行,因此都为127.0.0.1。

猜你喜欢

转载自blog.csdn.net/qq_43265890/article/details/84751553