关于c:Linux网络开发必学教程3深入浅出-IP-地址

46次阅读

共计 2964 个字符,预计需要花费 8 分钟才能阅读完成。

问题:网络编程接口中一些参数的意义是什么?

sock = socket(PF_INET, SOCK_STREAM, 0);

socket 参数详解

int socket(int domain, int type, int protocal);

参数 意义
domain 套接字中应用的协定族信息
type 套接字数据传输类型信息
prorocol 设施间通信应用的协定信息

socket() 中的 domain 参数(协定族)

  • PF_INET → IPv4 互联网协议族
  • PF_INET6 → IPv6 互联网协议族
  • PF_LOCAL → 本地通信的协定族
  • PF_PACKET → 底层数据收发协定
  • PF_IPX → Novell 专用协定(互联网分组替换协定)
留神:不同协定中的地址表现形式可能不同,网络编程时地址类型必须和协定类型匹配

socket() 中的 type 和 protocol 参数

  • type : 用于指定协定类型

    • SOCK_STREAM : 流式数据(TCP)
    • SOCK_UGRAM : 报文式数据(UDP)
  • protocol:用于指定协定族合乎类型的具体协定

    • domain 和 type 简直能够惟一确定一种协定,因而,这个参数通常为 0
    • 即:0 代表 domain 和 type 指定后的默认协定

对于端口号和 IP 地址

  • 端口号是一个 2 字节数据(无符号)
  • 0 – 1024 作为特定端口被预约义(调配给特定应用程序)
  • IP 地址是一个 4 字节无符号地址族(可分为 5 类地址)

深刻解析 IP 地址

IP 地址分为 网络标识 主机标识 两局部

  • 网络标识:标识网络主机(设施)所在的网络
  • 主机标识:标识网络主机(设施)的具体地址

问题:一个 IP 地址就 4 个字节,那么如何辨别网络标识和主机标识呢?

  • IP 地址 子网掩码 配合应用辨别 网络标识 和 主机标识
  • 子网掩码的表现形式也是一个 4 字节的整型数(无符号)
  • 子网掩码用于从 IP 地址中提取 网络标识(& 操作)

深刻了解子网掩码

设:子网掩码为 M.N.P.Q,则子网可用 IP 地址数量 n = (256 - M) * (256 - N) * (256 - P) * (256 - Q)

例:IP 地址 211.99.34.33,掩码 255.255.2555.248,因而:211.99.34.33 所在子网有 8 个 IP 地址
所在子网地址:211.99.34.32 
播送地址:211.99.34.39
6 个可调配地址:211.99.34.33 ... 211.99.34.38

注:子网地址即为网络标识

ip 地址 211.99.34.33,掩码 255.255.225.248
可知 211.99.34.33 所在子网有 8 个 IP 地址,且 8 = 2^3(二的三次方),所以 Y = 32 - 3 = 29
可示意为 211.99.34.33 / 29【简写模式】

注:29 为 32 位子网掩码的高位

算一算

IP 地址 192.168.3.44,掩码 255.255.255.0

问:子网地址是什么?播送地址是什么?可用地址有多少?简洁表示法是什么?答:子网地址:192.168.3.44
    播送地址:192.168.3.255
    可用地址:254 [256 - 0(子网地址) - 255(播送地址)]
    简洁示意:192.168.3.44 / 24

非凡的地址

  • 0.0.0.0 / 0 – 保留,罕用于代表“缺省网络”
  • 127.0.0.0 / 8 – 回环地址,罕用于本地软件会送测试
  • 255.255.255.255 / 32 – 播送地址

网络编程中的地址类型

int sock = 0;
struct sockaddr_in addr = {0};

sock = socket(PF_INET, SOCK_STREAM, 0);  // Protocol Family,协定族

if (sock == -1) {pritnf("socket error\n");
    return;
}

addr.sin_family = AF_INET;  // Address Family,地址族
addr.sin_addr.s_addr = inet_addr("192.168.3.241");
addr.sin_addr.port = htons(8899);

if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {printf("connect error\n");
    return -1;
}

问:(struct sockaddr*)&addr 的强制类型转换不会出问题吗?

地址数据类型解析

  • struct sockaddr 可了解为顶层地址类型父类,其与子类的内存布局雷同
  • connect() 依据 addr.sin_family 来判断是哪一种地址类型并进行相应解析

IP 地址相干函数

#include <arpa/inet.h>

函数原型 性能形容
in_addr_t inet_addr(const char* strptr); 将 IP 字符串转换为合乎网络字节序的整数
int inet_aton(const char *cp, struct_addr *inp); 将 IP 字符串转换为合乎网络字节序的整数,胜利返回 1,失败返回 0
char *inet_ntoa(struct in_addr in) 将合乎网络字节序的整数地址转换为字符串模式

编程试验:地址函数试验

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>

int main()
{unsigned int addr = inet_addr("1.2.3.4");
    struct in_addr addr1 = {0x09080706};
    struct in_addr addr2 = {0x05040302};
    char *s1 = inet_ntoa(addr1);
    char *s1_s = strcpy(malloc(32), s1);
    char *s2 = inet_ntoa(addr2);
    char *s2_s = strcpy(malloc(32), s2);

    printf("addr = %x\n", addr);

    printf("addr1 = %x\n", addr1.s_addr);
    printf("addr2 = %x\n", addr2.s_addr);

    printf("s1 = %s\n", s1);
    printf("s2 = %s\n", s2);               // 留神这里!!printf("s1 == s2 : %d\n", s1 == s2);   // 留神这里!!printf("s1_s = %s\n", s1_s);
    printf("s2_s = %s\n", s2_s);
    printf("s1_s == s2_s : %d\n", s1_s == s2_s);

    if (inet_aton("D.T.Software", &addr1)) {  // 留神这里!!printf("addr1 = %x\n", addr1.s_addr);
    }
    
    free(s1_s);
    free(s2_s);

    return 0;
}

输入

addr = 4030201
addr1 = 9080706
addr2 = 5040302
s1 = 2.3.4.5
s2 = 2.3.4.5   // 留神,转换后果被笼罩!!s1 == s2 : 1   // 两次为同一个地址!!s1_s = 6.7.8.9
s2_s = 2.3.4.5
s1_s == s2_s : 0

遗留的问题:如何加强服务端能力,同时反对多个客户端?什么是多播?什么是播送?

正文完
 0