第 13 章 网络与分布式系统基础

第 13 章 网络与分布式系统基础

《计算机系统:系统架构与操作系统的高度集成》

Umakishore Ramachandran & William D. Leahy Jr. 著


13.1 计算机网络概述

复制代码
计算机网络(Computer Network):
  将多台计算机通过通信链路连接起来,实现资源共享和信息交换的系统

网络的基本概念:
  节点(Node):计算机、路由器、交换机
  链路(Link):连接节点的通信信道(有线/无线)
  协议(Protocol):通信规则的集合

网络分类(按覆盖范围):
  PAN(个人区域网):蓝牙、NFC,覆盖范围 < 10m
  LAN(局域网):以太网、Wi-Fi,覆盖范围 < 1km
  MAN(城域网):覆盖一个城市
  WAN(广域网):覆盖国家或全球
  Internet:全球最大的 WAN

网络拓扑:
  总线型:所有节点连接到同一总线(早期以太网)
  星型:所有节点连接到中心交换机(现代以太网)
  环型:节点形成环形(令牌环)
  网状型:节点之间有多条路径(Internet)

网络性能指标:
  带宽(Bandwidth):每秒传输的最大数据量(bps)
  延迟(Latency):数据从源到目的地的时间(ms)
  吞吐量(Throughput):实际传输速率(通常 < 带宽)
  丢包率(Packet Loss Rate):丢失的数据包比例
  抖动(Jitter):延迟的变化量(对实时应用重要)

13.2 网络协议栈

13.2.1 OSI 参考模型

复制代码
OSI 七层模型(从上到下):

7. 应用层(Application Layer):
   为应用程序提供网络服务
   协议:HTTP, HTTPS, FTP, SMTP, DNS, SSH
   数据单位:消息(Message)

6. 表示层(Presentation Layer):
   数据格式转换、加密/解密、压缩
   协议:SSL/TLS(现在通常归入应用层)
   数据单位:消息

5. 会话层(Session Layer):
   建立、管理、终止会话
   协议:RPC, NetBIOS
   数据单位:消息

4. 传输层(Transport Layer):
   端到端的可靠传输
   协议:TCP(可靠), UDP(不可靠)
   数据单位:段(Segment)/ 数据报(Datagram)

3. 网络层(Network Layer):
   路由和寻址(IP地址)
   协议:IP, ICMP, ARP, OSPF, BGP
   数据单位:数据包(Packet)

2. 数据链路层(Data Link Layer):
   帧传输,错误检测
   协议:以太网, Wi-Fi (802.11), PPP
   数据单位:帧(Frame)

1. 物理层(Physical Layer):
   比特传输(电信号、光信号、无线电波)
   标准:RJ45, 光纤, 802.11
   数据单位:比特(Bit)

数据封装过程(发送方,从上到下):
  应用数据
  → 加传输层头(TCP/UDP头)→ 段
  → 加网络层头(IP头)→ 数据包
  → 加数据链路层头尾(以太网帧头+FCS)→ 帧
  → 转换为比特流传输

数据解封装过程(接收方,从下到上):
  比特流
  → 去掉帧头尾 → 数据包
  → 去掉IP头 → 段
  → 去掉TCP/UDP头 → 应用数据

13.2.2 TCP/IP 协议族

复制代码
TCP/IP 四层模型:

4. 应用层:HTTP, FTP, SMTP, DNS, SSH...
3. 传输层:TCP, UDP
2. 网络层:IP, ICMP, ARP
1. 网络接口层:以太网, Wi-Fi...

IP 地址:
  IPv4:32位,点分十进制(192.168.1.1)
  IPv6:128位,冒号十六进制(2001:db8::1)
  
  IPv4 地址类别:
  A类:1.0.0.0 ~ 126.255.255.255(大型网络)
  B类:128.0.0.0 ~ 191.255.255.255(中型网络)
  C类:192.0.0.0 ~ 223.255.255.255(小型网络)
  
  私有地址(不可路由到Internet):
  10.0.0.0/8
  172.16.0.0/12
  192.168.0.0/16

子网掩码:
  192.168.1.100/24
  网络地址:192.168.1.0
  广播地址:192.168.1.255
  主机范围:192.168.1.1 ~ 192.168.1.254

TCP vs UDP:
  特性          | TCP              | UDP
  -------------|------------------|------------------
  连接          | 面向连接(三次握手)| 无连接
  可靠性        | 可靠(确认+重传) | 不可靠
  顺序          | 保证顺序          | 不保证顺序
  流量控制      | 是               | 否
  拥塞控制      | 是               | 否
  速度          | 较慢             | 较快
  开销          | 大(20字节头)   | 小(8字节头)
  适用场景      | 文件传输、HTTP   | 视频流、DNS、游戏

TCP 三次握手:
  客户端 → SYN(seq=x)→ 服务器
  客户端 ← SYN+ACK(seq=y, ack=x+1)← 服务器
  客户端 → ACK(ack=y+1)→ 服务器
  连接建立!

TCP 四次挥手:
  客户端 → FIN → 服务器
  客户端 ← ACK ← 服务器
  客户端 ← FIN ← 服务器
  客户端 → ACK → 服务器
  连接关闭!

13.3 套接字编程基础

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

/* ===== TCP 服务器 ===== */
void *handle_client(void *arg) {
    int client_fd = *(int *)arg;
    free(arg);

    char buf[1024];
    int n;

    /* 接收数据 */
    while ((n = recv(client_fd, buf, sizeof(buf)-1, 0)) > 0) {
        buf[n] = '\0';
        printf("[服务器] 收到: %s", buf);

        /* 回显数据 */
        send(client_fd, buf, n, 0);
    }

    printf("[服务器] 客户端断开连接\n");
    close(client_fd);
    return NULL;
}

void tcp_server(int port) {
    /* 1. 创建套接字 */
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) { perror("socket"); return; }

    /* 设置地址重用(避免 TIME_WAIT 状态导致绑定失败)*/
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    /* 2. 绑定地址 */
    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
        .sin_addr.s_addr = INADDR_ANY  /* 监听所有网络接口 */
    };

    if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind"); close(server_fd); return;
    }

    /* 3. 监听 */
    if (listen(server_fd, 5) < 0) {  /* 5 = 等待队列长度 */
        perror("listen"); close(server_fd); return;
    }

    printf("[服务器] 监听端口 %d...\n", port);

    /* 4. 接受连接 */
    while (1) {
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);

        int *client_fd = malloc(sizeof(int));
        *client_fd = accept(server_fd,
                            (struct sockaddr *)&client_addr,
                            &client_len);

        if (*client_fd < 0) { perror("accept"); free(client_fd); continue; }

        printf("[服务器] 新连接: %s:%d\n",
               inet_ntoa(client_addr.sin_addr),
               ntohs(client_addr.sin_port));

        /* 为每个客户端创建线程 */
        pthread_t tid;
        pthread_create(&tid, NULL, handle_client, client_fd);
        pthread_detach(tid);
    }

    close(server_fd);
}

/* ===== TCP 客户端 ===== */
void tcp_client(const char *server_ip, int port) {
    /* 1. 创建套接字 */
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) { perror("socket"); return; }

    /* 2. 连接服务器 */
    struct sockaddr_in server_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port)
    };
    inet_pton(AF_INET, server_ip, &server_addr.sin_addr);

    if (connect(sock, (struct sockaddr *)&server_addr,
                sizeof(server_addr)) < 0) {
        perror("connect"); close(sock); return;
    }

    printf("[客户端] 连接到 %s:%d\n", server_ip, port);

    /* 3. 发送和接收数据 */
    const char *messages[] = {
        "Hello, Server!\n",
        "How are you?\n",
        "Goodbye!\n"
    };

    char buf[1024];
    for (int i = 0; i < 3; i++) {
        /* 发送 */
        send(sock, messages[i], strlen(messages[i]), 0);
        printf("[客户端] 发送: %s", messages[i]);

        /* 接收回显 */
        int n = recv(sock, buf, sizeof(buf)-1, 0);
        if (n > 0) {
            buf[n] = '\0';
            printf("[客户端] 收到回显: %s", buf);
        }
    }

    /* 4. 关闭连接 */
    close(sock);
    printf("[客户端] 连接关闭\n");
}

/* ===== UDP 示例 ===== */
void udp_server(int port) {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
        .sin_addr.s_addr = INADDR_ANY
    };
    bind(sock, (struct sockaddr *)&addr, sizeof(addr));

    printf("[UDP服务器] 监听端口 %d...\n", port);

    char buf[1024];
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);

    /* 接收数据报 */
    int n = recvfrom(sock, buf, sizeof(buf)-1, 0,
                     (struct sockaddr *)&client_addr, &client_len);
    buf[n] = '\0';
    printf("[UDP服务器] 收到来自 %s:%d 的数据: %s\n",
           inet_ntoa(client_addr.sin_addr),
           ntohs(client_addr.sin_port), buf);

    /* 回复 */
    const char *reply = "UDP Reply!";
    sendto(sock, reply, strlen(reply), 0,
           (struct sockaddr *)&client_addr, client_len);

    close(sock);
}

void udp_client(const char *server_ip, int port) {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    struct sockaddr_in server_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port)
    };
    inet_pton(AF_INET, server_ip, &server_addr.sin_addr);

    /* 发送数据报(无需建立连接)*/
    const char *msg = "Hello UDP!";
    sendto(sock, msg, strlen(msg), 0,
           (struct sockaddr *)&server_addr, sizeof(server_addr));
    printf("[UDP客户端] 发送: %s\n", msg);

    /* 接收回复 */
    char buf[1024];
    int n = recvfrom(sock, buf, sizeof(buf)-1, 0, NULL, NULL);
    buf[n] = '\0';
    printf("[UDP客户端] 收到: %s\n", buf);

    close(sock);
}

/* ===== 简单 HTTP 服务器 ===== */
void simple_http_server(int port) {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
        .sin_addr.s_addr = INADDR_ANY
    };
    bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
    listen(server_fd, 5);

    printf("[HTTP服务器] 监听端口 %d...\n", port);
    printf("  访问: http://localhost:%d/\n", port);

    int client_fd = accept(server_fd, NULL, NULL);

    /* 读取 HTTP 请求 */
    char request[4096];
    int n = recv(client_fd, request, sizeof(request)-1, 0);
    request[n] = '\0';
    printf("[HTTP服务器] 收到请求:\n%s\n", request);

    /* 发送 HTTP 响应 */
    const char *body = "<html><body><h1>Hello, World!</h1>"
                       "<p>Simple HTTP Server</p></body></html>";
    char response[1024];
    snprintf(response, sizeof(response),
             "HTTP/1.1 200 OK\r\n"
             "Content-Type: text/html\r\n"
             "Content-Length: %zu\r\n"
             "Connection: close\r\n"
             "\r\n"
             "%s",
             strlen(body), body);

    send(client_fd, response, strlen(response), 0);
    printf("[HTTP服务器] 发送响应\n");

    close(client_fd);
    close(server_fd);
}

int main() {
    printf("=== 套接字编程演示 ===\n\n");

    /* 演示 TCP 通信(使用 fork 模拟客户端和服务器)*/
    printf("TCP 通信演示:\n");

    int port = 8888;
    pid_t pid = fork();

    if (pid == 0) {
        /* 子进程:客户端 */
        sleep(1);  /* 等待服务器启动 */
        tcp_client("127.0.0.1", port);
        exit(0);
    } else {
        /* 父进程:服务器(只处理一个连接)*/
        int server_fd = socket(AF_INET, SOCK_STREAM, 0);
        int opt = 1;
        setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        struct sockaddr_in addr = {
            .sin_family = AF_INET,
            .sin_port = htons(port),
            .sin_addr.s_addr = INADDR_ANY
        };
        bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
        listen(server_fd, 1);

        printf("[服务器] 监听端口 %d...\n", port);

        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int client_fd = accept(server_fd,
                               (struct sockaddr *)&client_addr,
                               &client_len);

        printf("[服务器] 客户端连接: %s:%d\n",
               inet_ntoa(client_addr.sin_addr),
               ntohs(client_addr.sin_port));

        char buf[1024];
        int n;
        while ((n = recv(client_fd, buf, sizeof(buf)-1, 0)) > 0) {
            buf[n] = '\0';
            printf("[服务器] 收到: %s", buf);
            send(client_fd, buf, n, 0);
        }

        close(client_fd);
        close(server_fd);

        int status;
        wait(&status);
    }

    return 0;
}

13.4 分布式系统概念

13.4.1 分布式系统的特征

复制代码
分布式系统(Distributed System):
  多台计算机通过网络协作,对用户呈现为单一系统

分布式系统的特征:
  并发性(Concurrency):
    多个节点同时执行
    需要协调并发访问共享资源
  
  缺乏全局时钟(No Global Clock):
    各节点时钟不同步
    难以确定事件的全局顺序
    解决:逻辑时钟(Lamport 时钟)、向量时钟
  
  故障独立性(Independent Failures):
    部分节点故障不影响整体
    需要容错机制
  
  异构性(Heterogeneity):
    不同硬件、操作系统、编程语言
    需要统一的通信协议

分布式系统的挑战:
  网络延迟和不可靠性
  节点故障
  数据一致性
  安全性
  可扩展性

CAP 定理(Brewer 定理):
  分布式系统不能同时满足以下三个特性:
  C(Consistency):一致性------所有节点看到相同的数据
  A(Availability):可用性------每个请求都能得到响应
  P(Partition Tolerance):分区容错------网络分区时仍能工作
  
  实际系统必须在 CA、CP、AP 中选择:
  CA:传统关系数据库(MySQL,不支持分区)
  CP:ZooKeeper、HBase(一致性优先)
  AP:Cassandra、DynamoDB(可用性优先)

13.4.2 远程过程调用(RPC)

c 复制代码
/* RPC(Remote Procedure Call)概念演示 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/* RPC 消息格式 */
typedef struct {
    int request_id;     /* 请求ID */
    char function[32];  /* 函数名 */
    int arg1;           /* 参数1 */
    int arg2;           /* 参数2 */
} RPCRequest;

typedef struct {
    int request_id;     /* 对应的请求ID */
    int result;         /* 返回值 */
    int error;          /* 错误码(0=成功)*/
} RPCResponse;

/* RPC 服务器端:实现远程函数 */
int rpc_add(int a, int b) { return a + b; }
int rpc_multiply(int a, int b) { return a * b; }
int rpc_subtract(int a, int b) { return a - b; }

void rpc_server(int port) {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
        .sin_addr.s_addr = INADDR_ANY
    };
    bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
    listen(server_fd, 5);

    printf("[RPC服务器] 监听端口 %d\n", port);

    int client_fd = accept(server_fd, NULL, NULL);

    RPCRequest req;
    RPCResponse resp;

    while (recv(client_fd, &req, sizeof(req), 0) > 0) {
        printf("[RPC服务器] 收到请求: ID=%d, 函数=%s(%d,%d)\n",
               req.request_id, req.function, req.arg1, req.arg2);

        resp.request_id = req.request_id;
        resp.error = 0;

        /* 根据函数名调用对应函数 */
        if (strcmp(req.function, "add") == 0) {
            resp.result = rpc_add(req.arg1, req.arg2);
        } else if (strcmp(req.function, "multiply") == 0) {
            resp.result = rpc_multiply(req.arg1, req.arg2);
        } else if (strcmp(req.function, "subtract") == 0) {
            resp.result = rpc_subtract(req.arg1, req.arg2);
        } else {
            resp.error = -1;
            resp.result = 0;
        }

        printf("[RPC服务器] 返回结果: %d\n", resp.result);
        send(client_fd, &resp, sizeof(resp), 0);
    }

    close(client_fd);
    close(server_fd);
}

/* RPC 客户端:调用远程函数(看起来像本地调用)*/
int rpc_sock = -1;
int rpc_request_id = 0;

/* 客户端存根(Stub):将本地调用转换为网络请求 */
int remote_add(int a, int b) {
    RPCRequest req = {
        .request_id = ++rpc_request_id,
        .arg1 = a,
        .arg2 = b
    };
    strncpy(req.function, "add", sizeof(req.function));

    send(rpc_sock, &req, sizeof(req), 0);

    RPCResponse resp;
    recv(rpc_sock, &resp, sizeof(resp), 0);

    if (resp.error != 0) {
        printf("RPC错误: %d\n", resp.error);
        return -1;
    }
    return resp.result;
}

int remote_multiply(int a, int b) {
    RPCRequest req = {
        .request_id = ++rpc_request_id,
        .arg1 = a,
        .arg2 = b
    };
    strncpy(req.function, "multiply", sizeof(req.function));

    send(rpc_sock, &req, sizeof(req), 0);

    RPCResponse resp;
    recv(rpc_sock, &resp, sizeof(resp), 0);
    return resp.result;
}

void rpc_client(const char *server_ip, int port) {
    rpc_sock = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in server_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port)
    };
    inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
    connect(rpc_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));

    printf("[RPC客户端] 连接到服务器\n");

    /* 调用远程函数(看起来像本地调用!)*/
    int result1 = remote_add(3, 5);
    printf("[RPC客户端] remote_add(3, 5) = %d\n", result1);

    int result2 = remote_multiply(4, 7);
    printf("[RPC客户端] remote_multiply(4, 7) = %d\n", result2);

    int result3 = remote_add(result1, result2);
    printf("[RPC客户端] remote_add(%d, %d) = %d\n", result1, result2, result3);

    close(rpc_sock);
}

int main() {
    printf("=== RPC 演示 ===\n\n");

    int port = 9999;
    pid_t pid = fork();

    if (pid == 0) {
        sleep(1);
        rpc_client("127.0.0.1", port);
        exit(0);
    } else {
        rpc_server(port);
        wait(NULL);
    }

    return 0;
}

13.4.3 分布式文件系统

复制代码
分布式文件系统(Distributed File System):
  将文件存储在多台服务器上,对用户呈现为统一的文件系统

NFS(Network File System):
  Sun Microsystems 开发(1984)
  Unix/Linux 系统广泛使用
  
  工作原理:
  客户端挂载远程目录
  文件操作通过 RPC 发送到服务器
  服务器执行操作并返回结果
  
  挂载示例:
  mount -t nfs 192.168.1.100:/shared /mnt/nfs
  
  特点:
  透明性:用户感觉不到文件在远程
  无状态:服务器不保存客户端状态(简化故障恢复)
  缓存:客户端缓存文件数据(提高性能)

HDFS(Hadoop Distributed File System):
  为大数据处理设计
  
  架构:
  NameNode:存储文件系统元数据(目录结构、文件块位置)
  DataNode:存储实际数据块(默认128MB/块)
  
  特点:
  高容错:每个数据块默认3个副本
  高吞吐量:优化顺序读写(不适合随机访问)
  大文件:适合存储GB~TB级别的大文件
  
  写入流程:
  1. 客户端向 NameNode 请求写入
  2. NameNode 分配 DataNode 列表
  3. 客户端将数据写入第一个 DataNode
  4. 第一个 DataNode 将数据复制到第二个
  5. 第二个复制到第三个
  6. 写入完成,通知 NameNode

GFS(Google File System):
  Google 内部使用(2003年论文)
  HDFS 的设计参考
  
  设计假设:
  节点故障是常态(使用廉价商用服务器)
  文件通常很大(GB级别)
  大多数写操作是追加(Append),而非随机写
  高吞吐量比低延迟更重要

13.5 网络操作系统

复制代码
网络操作系统(Network Operating System):
  提供网络服务的操作系统

主要功能:
  文件共享(NFS, SMB/CIFS)
  打印机共享
  用户认证(LDAP, Active Directory)
  网络管理

现代网络服务:
  DNS(Domain Name System):
    将域名转换为IP地址
    例:www.google.com → 142.250.80.36
    
    查询过程:
    1. 客户端查询本地缓存
    2. 查询本地 DNS 服务器
    3. 本地 DNS 查询根 DNS 服务器
    4. 根 DNS 返回顶级域(.com)DNS 服务器地址
    5. 查询顶级域 DNS 服务器
    6. 返回权威 DNS 服务器地址
    7. 查询权威 DNS 服务器
    8. 返回 IP 地址
  
  DHCP(Dynamic Host Configuration Protocol):
    自动分配 IP 地址
    客户端广播 DHCP Discover
    服务器回复 DHCP Offer(提供IP地址)
    客户端发送 DHCP Request(接受IP地址)
    服务器发送 DHCP ACK(确认)
  
  HTTP/HTTPS:
    Web 通信协议
    HTTP/1.1:持久连接,管道化
    HTTP/2:多路复用,头部压缩,服务器推送
    HTTP/3:基于 QUIC(UDP),减少延迟
c 复制代码
/* DNS 查询演示 */
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>

void dns_lookup_demo() {
    printf("=== DNS 查询演示 ===\n\n");

    const char *hostnames[] = {
        "www.google.com",
        "www.baidu.com",
        "localhost"
    };

    for (int i = 0; i < 3; i++) {
        printf("查询 %s:\n", hostnames[i]);

        struct hostent *he = gethostbyname(hostnames[i]);
        if (!he) {
            printf("  查询失败\n");
            continue;
        }

        printf("  官方名称: %s\n", he->h_name);

        /* 打印所有 IP 地址 */
        for (int j = 0; he->h_addr_list[j]; j++) {
            char ip[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, he->h_addr_list[j], ip, sizeof(ip));
            printf("  IP地址[%d]: %s\n", j, ip);
        }

        /* 打印别名 */
        for (int j = 0; he->h_aliases[j]; j++) {
            printf("  别名[%d]: %s\n", j, he->h_aliases[j]);
        }
        printf("\n");
    }
}

/* 反向 DNS 查询(IP → 域名)*/
void reverse_dns_demo() {
    printf("=== 反向 DNS 查询 ===\n\n");

    const char *ips[] = {"8.8.8.8", "1.1.1.1", "127.0.0.1"};

    for (int i = 0; i < 3; i++) {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        inet_pton(AF_INET, ips[i], &addr.sin_addr);

        char hostname[256];
        int ret = getnameinfo((struct sockaddr *)&addr, sizeof(addr),
                              hostname, sizeof(hostname),
                              NULL, 0, 0);

        if (ret == 0) {
            printf("%s → %s\n", ips[i], hostname);
        } else {
            printf("%s → 查询失败\n", ips[i]);
        }
    }
}

int main() {
    dns_lookup_demo();
    reverse_dns_demo();
    return 0;
}

本章小结

知识点 核心内容 重要程度
网络概述 节点/链路/协议,LAN/WAN,性能指标 ⭐⭐⭐⭐
OSI七层模型 各层功能、协议、数据单位 ⭐⭐⭐⭐⭐
TCP/IP四层 应用/传输/网络/网络接口 ⭐⭐⭐⭐⭐
IP地址 IPv4/IPv6,子网掩码,私有地址 ⭐⭐⭐⭐⭐
TCP vs UDP 可靠vs不可靠,适用场景 ⭐⭐⭐⭐⭐
TCP三次握手 SYN→SYN+ACK→ACK ⭐⭐⭐⭐⭐
套接字编程 socket/bind/listen/accept/connect/send/recv ⭐⭐⭐⭐⭐
分布式系统特征 并发/无全局时钟/故障独立/异构 ⭐⭐⭐⭐
CAP定理 一致性/可用性/分区容错,三选二 ⭐⭐⭐⭐⭐
RPC 远程调用看起来像本地调用,存根机制 ⭐⭐⭐⭐⭐
NFS/HDFS 分布式文件系统,透明性,容错 ⭐⭐⭐⭐
DNS 域名→IP,递归查询,缓存 ⭐⭐⭐⭐

思考题

  1. TCP 为什么需要三次握手而不是两次?
  2. CAP 定理说不能同时满足三个特性,为什么?
  3. RPC 的"透明性"是什么意思?它有什么局限性?
  4. HDFS 为什么将每个数据块默认存储3个副本?
  5. DNS 查询为什么使用 UDP 而不是 TCP?

参考文献:Umakishore Ramachandran & William D. Leahy Jr.,《计算机系统:系统架构与操作系统的高度集成》

相关推荐
山东穆柯传感器1 小时前
安全触边损坏如何维修及更换配件
网络·安全
huainingning1 小时前
华三ACL单向TCP互通组网-通过Established状态回包实现
运维·网络·tcp/ip
Johnstons2 小时前
游戏网络测试怎么做?从延迟到丢包,一套完整的游戏弱网测试方案
网络·游戏·php
Rocket-Luo2 小时前
谈谈企业中的网络安全
网络·安全·web安全
byte_conn2 小时前
船舶机舱监控频频瘫痪?CAN转光纤与中继器重塑海事通信底座
网络
技术不好的崎鸣同学3 小时前
[BJDCTF2020]The mystery of ip 思路及解法
网络·安全·web安全
normanhere4 小时前
浪潮云国产化超融合规划和部署案例
服务器·网络
AFinalStone6 小时前
Android 7系统网络(一)全景图与调用链路概览
android·网络·frameworks
yxl874646466 小时前
PCTG-1015型Profinet转Ethernet/IP协议转换器
服务器·网络·物联网·网络协议·自动化·信息与通信