第十三章学习笔记

@

一、学习笔记

1.TCP/IP 协议

TCP/IP (Comer 1988, 2001; RFC1180 1991 )是互联网的基础。TCP 代表传输控制协议。IP 代表互联网协议。目前有两个版本的IP,即 IPv4 和 IPv6。IPv4 使用32位地址,IPv6 则 使用128位地址。本节围绕 IPv4 进行讨论,它仍然是目前使用最多的IP版本。TCP/IP 的组织结构分为几个层级,通常称为TCP/IP 堆栈,如图所示为TCP/IP的各个层级以及每一层级的代表性组件及其功能。
在这里插入图片描述
顶层是使用 TCP/IP 的应用程序。用于登录到远程主机的 ssh、用于交换电子邮件的 mail、用于 Web 页面的 http 等应用程序需要可靠的数据传输。通常,这类应用程序在传输层使用 TCP。另一方面,有些应用程序,例如用于查询其他主机的ping命令,则不需要可靠性。这类应用程序可以在传输层使用 UDP 来提高效率(RFC 768 1980; Comer 1988)。传 输层负责以包的形式向 IP 主机发送/接收来自 IP 主机的应用程序数据。进程与主机之间的传输层或其上方的数据传输只是逻辑传输。实际数据传输发生在互联网(IP) 和链路层,这些层将数据包分成数据帧,以便在物理网络之间传输。

2.IP 主机和 IP 地址

主机是支持TCP/IP协议的计算机或设备。每个主机由一个32位的 IP地址来标识。为 了方便起见,32位的 IP地址号通常用点记法表示,例如:134.121.64.1,其中各个字节用点 号分开。主机也可以用主机名来表示,如 dnsl.eec.wsu.edu。实际上,应用程序通常使用主机名而不是 IP 地址。在这个意义上说,主机名就等同于IP地址,因为给定其中一个,我们可以通过 DNS (域名系统)(RFC 134 1987; RFC 1035 1987 )服务器找到另一个,它将IP地址转换为主机名,反之亦然。
  IP地址分为两部分,即NetworkID字段和HostID字段。根据划分,1P地址分为 A~E 类。例如,一个B类 IP 地址被划分为一个16位 NetworklD,其中前2位是10,然后是一个16位的 HostID 字段。发往IP地址的数据包首先被发送到具有相同 networkID 的路由器。路由器将通过 HostID 将数据包转发到网络中的特定主机。每个主机都有一个本地主机名 localhost,默认 IP 地址为127.0.0.1。本地主机的链路层是一个回送虚拟设备,它将每个数据包路由回同一个 localhost0 这个特性可以让我们在同一台计算机上运行 TCP/IP 应用程序,而不需要实际连接到互联网。

3.IP 协议

IP 协议用于在 IP 主机之间发送/接收数据包。IP 尽最大努力运行。IP 主机只向接收主机发送数据包,但它不能保证数据包会被发送到它们的目的地,也不能保证按顺序发送。这意味着 IP 并非可靠的协议。必要时,必须在 IP 层的上面实现可靠性。

4.IP 数据包格式

IP 数据包由 IP 头、发送方 IP 地址和接收方 IP 地址以及数据组成。每个 IP 数据包的大小最大为64KB。IP 头包含有关数据包的更多信息,例如数据包的总长度、数据包使用 TCP 还是 UDP、生存时间(TTL)计数、错误检测的校验和等。
在这里插入图片描述

5.路由器

IP 主机之间可能相距很远。通常不可能从一个主机直接向另一个主机发送数据包。路 由器是接收和转发数据包的特殊 IP 主机。如果有的话,一个 IP 数据包可能会经过许多路由器,或者跳跃到达某个目的地。图13.4显示了 TCP/IP 网络的拓扑结构。
每个 IP 包在 IP 报头中都有一个8位生存时间(TTL)计数,其最大值为255。在每个路由器上,TTL 会减小1。如果 TTL 减小到0,而包仍然没有到达目的地,则会直接丢弃它。这可以防止任何数据包在 IP 网络中无限循环。

6.UDP

UDP(用户数据报协议)(RFC 768 1980; Comer 1988)在 IP 上运行,用于发送/接收数据报。与 IP 类似,UDP 不能保证可靠性,但是快速高效。它可用于可靠性不重要的情况。 例如,用户可以使用ping命令探测目标主机,如ping 主机名或 ping IP 地址
  ping 是一个向目标主机发送带时间戳 UDP 包的应用程序。接收到一个 pinging 数据包后,目标主机将带有时间戳的 UDP 包回送给发送者,让发送者可以计算和显示往返时间。如果目标主机不存在或宕机,当 TTL 减小为0时,路由器将会丢弃 pinging UDP 数据包。 在这种情况下,用户会发现目标主机没有任何响应。用户可以尝试再次 ping,或者断定目标主机宕机。在这种情况下,最好使用 UDP,因为不要求可靠性。

7.TCP

TCP(传输控制协议)是一种面向连接的协议,用于发送/接收数据流。TCP 也可在 IP 上运行,但它保证了可靠的数据传输。通常,UDP 类似于发送邮件的 USPS,而 TCP 类似于电话连接。

8.端口编号

在各主机上,多个应用程序(进程)可同时使用 TCP/UDP。每个应用程序由三个组成
部分唯一标识
应用程序 = (主机IP,协议,端口号)
其中,协议是 TCP 或 UDP,端口号是分配给应用程序的唯一无符号短整数。要想使用 UDP 或 TCP,应用程序(进程)必须先选择或获取一个端口号。前1024个端口号已被预留。其他端口号可供一般使用。应用程序可以选择一个可用端口号,也可以让操作系统内核分配端口号。

9.网络和主机字节序

计算机可以使用大端字节序,也可以使用小端字节序。在互联网上,数据始终按网络 序排列,这是大端。在小端机器上,例如基于Intel x86的 PC,htons()、htonl()、ntohs()、 ntohl()等库函数,可在主机序和网络序之间转换数据。例如,PC中的端口号1234按主机字节序(小端)是无符号短整数。必须先通过 htons(1234)把它转换成网络序,才能使用。相反,从互联网收到的端口号必须先通过 ntohs(port)转换为主机序。

10.TCP/IP 网络中的数据流

TCP/IP 层的数据格式
在这里插入图片描述

二、苏格拉底挑战

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、实践过程及截图

实践代码:

include <stdio.h>

include <stdlib.h>

include <string.h>

include <sys/socket.h>

include <netinet/ip.h>

include <arpa/inet.h>

include <unistd.h>

include <netdb.h>

define MAX 256

define SERVER_HOST "localhost"

define SERVER_PORT 1234

struct sockaddr_in server_addr;
int sock, r;

int client_init() {
printf("======= client init ==\n");
printf("1 : create a TCP socket\n");
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
printf("socket call failed\n");
exit(1);
}
printf("2 : fill server_addr with server's IP and PORT#\n");
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // localhost
server_addr.sin_port = htons(SERVER_PORT); // server port number
printf("3 : connecting to server ....\n");
r = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (r < 0) {
printf("connect failed\n");
exit(3);
}
printf("4 : connected OK to\n");
printf("-------------------------------------------------\n");
printf("Server hostname=%s PORT=%d\n", SERVER_HOST, SERVER_PORT);
printf("-------------------------------------------------\n");
printf("
= init done ==========\n");
}

int main() {
int n;
char line[MAX], ans[MAX];
client_init();
printf("***processing loop *********\n");
while (1) {
printf("input a line 😊;
bzero(line, MAX);
fgets(line, MAX, stdin);
line[strlen(line) - 1] = 0;
if (line[0] == 0)
exit(0);
n = write(sock, line, MAX);
printf("client:wrote n=%d bytes;line=%s\n", n, line);
n = read(sock, ans, MAX);
printf("client:read n=%d bytes;line=%s\n", n, ans);
}
}

include <stdio.h>

include <stdlib.h>

include <string.h>

include <sys/socket.h>

include <netinet/ip.h>

include <arpa/inet.h>

include <unistd.h>

include <netdb.h>

define MAX 256

define SERVER_HOST "localhost"

define SERVER_IP "81.70.18.119"

define SERVER_PORT 1234

struct sockaddr_in server_addr, client_addr;
struct in_addr client_addr_tranform;
int mysock, csock;
int r, len, n;

int server_init() {
printf("================== server init ====\n");
printf("1 : create a TCP STREAM socket\n");
mysock = socket(AF_INET, SOCK_STREAM, 0);
if (mysock < 0) {
printf("socket call failed\n");
exit(1);
}
printf("2 : fill server_addr with host IP and PORT# info\n");
server_addr.sin_family = AF_INET; // for TCP/IP
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // This HOST IP
server_addr.sin_port = htons(SERVER_PORT); // port number 1234
printf("3 : bind socket to server address\n");
r = bind(mysock, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (r < 0) {
printf("bind failed\n");
exit(3);
}
printf(" hostname = %s port = %d\n", SERVER_HOST, SERVER_PORT);
printf("4 : server is listening ....\n");
listen(mysock, 5); // queue length = 5
printf("
= init done =======================\n");
}

int main() {
char line[MAX];
server_init();
client_addr_tranform.s_addr = client_addr.sin_addr.s_addr;
while (1) {
printf("server: accepting new connection ....\n");
len = sizeof(client_addr);
csock = accept(mysock, (struct sockaddr*)&client_addr, &len);
if (csock < 0) {
printf("server: accept error\n");
exit(1);
}
printf("server: accepted a client connection from\n");
printf("-----------------------------------------\n");
printf("Clinet: IP=%s port=%d\n", inet_ntoa(client_addr_tranform), ntohs(client_addr.sin_port));
printf("-----------------------------------------\n");
while (1) {
n = read(csock, line, MAX);
if (n == 0) {
printf("server: client died, server loops\n");
close(csock);
break;
}
printf("server: read n=%d bytes; line=%s\n", n, line);
n = write(csock, line, MAX);
printf("server:wrote n=%d bytes; ECHO=%s\n", n, line);
printf("server:ready for next request\n");
}
}
}

实践截图:
在这里插入图片描述
在这里插入图片描述

posted @ 2023-12-17 21:08  20211112周子凯  阅读(2)  评论(0编辑  收藏  举报