基本概念
●IP地址是Internet中主机的标识
●Internet中的主机要与别的机器通信必须具有一个IP地址
●IP地址为32位(IPv4)或者128位(IPv6)
●表示形式:常用点分十进制,如192.168.1.109,最后都会转换为一个32位的无符号整数。
地址划分
主机号的第一个和最后一个都不能被使用,第一个作为网段号,最后一个作为广播地址。
A类:1.0.0.1~126.255.255.254
B类:128.0.0.1~191.255.255.254
C类:192.0.0.1~223.255.255.254
D类(组播地址):224.0.0.1~239.255.255.254
网段号的定义:主机位全为0,代表当前设备所处的网段号
这个需要结合子网掩码来计算,子网掩码规定了哪些是网络号,哪些是主机号
如果子网掩码位是1,那么当前为就是网络号,如果是0,那么当前位是主机号
网段号=IP&子网掩码
特殊地址(后续编程使用)
0.0.0.0:在服务器中,0.0.0.0指的是本机上的所有IPV4地址,如果一个主机有两个IP地址,192.168.1.1 和 10.1.2.1,并且该主机上的一个服务监听的地址是0.0.0.0,那么通过两个ip地址都能够访问该服务。在程序里,用宏定义表示:INADDR_ANY
127.0.0.1:回环地址/环路地址,所有发往该类地址的数据包都应该被loop back。仅作为测试使用,只能实现本机上通信。
IP地址转换
实现了人看的IP(192.168.1.155)和机器内部使用(32位的无符号的整数)的实际IP进行转换。
struct in_addr {
uint32_t s_addr;
};
//从人看的ip地址转为机器使用的32位
typedef uint32_t in_addr_t;
in_addr_t inet_addr(const char *cp);
//从机器到人
char *inet_ntoa(struct in_addr in);
例子:
给定一个IP地址,转换为机器的32位无符号整数,然后打印。
打印完后,再转回给人看的IP地址,再打印。
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
//把人看的转成机器要的,192.168.0.109
char ip[64] = "192.168.0.109";
in_addr_t ip32 = inet_addr(ip);
printf("ip = 0x%x\n", ip32); //0x6d00a8c0
//把机器的转成人看
struct in_addr in;
in.s_addr = ip32;
char *p = inet_ntoa(in);
printf("p = %s\n", p); //0x6d00a8c0
return 0;
}
端口
●为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区
●TCP端口号与UDP端口号独立
●端口号一般由IANA (Internet Assigned Numbers Authority) 管理
●端口用两个字节来表示–USHORT
●端口指定需要统一为网络字节序(大端)
众所周知端口:1-1023(1255之间为众所周知端口,2561023端口通常由UNIX系统占用)
注册端口:1024-49151(尽量用5000以上的)
动态或私有端口:49152-65535
字节序
网络中传输一字节以上的带类型的数据(比如short、int),必须使用网络字节序,即大端字节序。
小端序(little-endian) - 低序字节存储在低地址
大端序(big-endian)- 高序字节存储在低地址
面试题:写一个函数,判断当前主机的字节序?
int checkCPU()
{
union w{
short a;
char b;
}c;
c.a = 1;
return (c.b == 1);
}
主机字节序到网络字节序
uint16_t htons(uint16_t hostshort);
网络字节序到主机字节序
uint16_t ntohs(uint16_t netshort);