📝 我的笔记

还没有笔记

选中页面文字后点击「高亮」按钮添加

1 网络和套接字

📜 原文
📖 逐步解释
∑ 公式拆解
💡 数值示例
⚠️ 易错点
📝 总结
🎯 存在目的
🧠 直觉心智模型
💭 直观想象

1网络和套接字

COMS W3157

Borowski 博士

2什么是协议?

协议是通信双方之间关于如何进行通信的约定。

不同的协议是针对不同的情况而构建的。

互联网上,我们通常使用 TCP/IP 以及各种协议,例如 HTTPFTPSMTPPOP 等。

3服务与协议之间的关系

服务是某一层向其上层提供的一组原语(操作)。

相比之下,协议是管理层内对等实体交换的数据包消息格式和含义的一组规则。

实体使用协议来实现其服务定义。

4OSI 参考模型

基于国际标准化组织(ISO)提出的一项建议,作为各种中使用的协议国际标准化的第一步(Day 和 Zimmermann,1983)。

它在 1995 年进行了修订(Day,1995)。

5称为 OSI(开放系统互连)

参考模型,因为它处理连接开放系统。大学

6OSI 模型的原则

OSI 模型有七层。应用于这七层所遵循的原则可以简要概括如下:

  1. 当需要不同的抽象时,应该创建一个
  2. 每个都应该执行一个明确定义的功能
  3. 每个功能应该着眼于定义国际标准化协议来选择。

7OSI 层

交换单位名称

8TCP/IP - 互联网协议套件

传输控制协议 / 互联网协议 TCP/IP 有点过于复杂,无法归类到 OSI 模型的单个中。

它是一系列在不同上工作的工具,并被许多其他应用层协议使用。

例如,HTTPDNS 依赖 TCP/IP 才能正常工作。

大多数当前的网络都使用 TCP/IP

DNS,即域名系统,是一项基本的互联网服务,它将人类可读的域名(如 google.com)转换为计算机用于定位网站和其他在线资源数字 IP 地址

9IPS 的组织

OSI 模型一样分层组织,但只有 4 而不是 7

10链路层

11互联网层

12传输层

13应用层

14OSI vs TCP/IP

| OSI | |

| :--- | :--- |

| 7 | 应用 |

| 6 | 表示 |

| 5 | 会话 |

| 4 | 传输 |

| 3 | 网络 |

| 2 | 数据链路 |

| 1 | 物理 |

| | |

TCP/IP

15来自每个层的头部

16套接字

套接字是类似于电话通信通道。它完全是关于两个端点之间的通信

17套接字

套接字套接字描述符标识

18套接字

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

| 地址族 | | 我们将在本课程中使用 AF_INET。 | |

| :--- | :--- | :--- | :--- |

| 名称 | 目的 | | 手册页 |

| AF_UNIX, AF_LOCAL | 本地通信 | | unix(7) |

| AF_INET | IPv4 互联网协议 | | ip(7) |

| AF_INET6 | IPv6 互联网协议 | | ipv6(7) |

| AF_IPX | IPX - Novell 协议 | | |

| AF_NETLINK | 内核用户界面设备 | | netlink(7) |

| AF_X25 | ITU-T X.25 / ISO-8208 协议 | | x25(7) |

| AF_AX25 | 业余无线电 AX.25 协议 | | |

| AF_ATMPVC | 原始 ATM PVC 访问 | | |

| AF_APPLETALK | AppleTalk | | ddp(7) |

| AF_PACKET | 低级别数据包接口 | | packet(7) |

| AF_ALG | 内核加密 API 接口 | | |

19示例 1:数据报套接字 - 用户数据报协议 (UDP)

20UDP

21邮政邮件

socket(AF_INET, SOCK_DGRAM, 0)

22示例 2:流套接字 - 传输控制协议 (TCP)

23TCP

24电话呼叫

socket(AF_INET, SOCK_STREAM, 0)

25套接字标识 “端点地址”

套接字标识IP 地址 + 端口号

26使用端口标识服务

27客户端-服务器通信 数据报套接字 (UDP):无连接

28客户端-服务器通信 流套接字 (TCP:连接导向)

29使用套接字的示例

本幻灯片组的其余部分演示了回显客户端回显服务器之间使用基于 TCP套接字进行通信

服务器回显客户端收到的任何字符串

30客户端-服务器通信 流套接字 (TCP:`socket()`)

哥伦比亚

31`socket()`

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

socket() 创建一个通信端点并返回一个文件描述符,该文件描述符引用该端点。成功调用返回的文件描述符将是进程中当前未打开的最低编号文件描述符

AF_INET 用于 IPv4

AF_INET6 用于 IPv6

SOCK_STREAM: 可靠字节流 (TCP)

SOCK_DGRAM: 面向消息服务 (UDP)

UNSPEC: 未指定

(AF_INETSOCK_STREAM 已经暗示 TCP,"0" 设置协议)

sockfd = socket(AF_INET, SOCK_STREAM, 0);

32C 语言中的 TCP 服务器代码

```

int serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

```

33客户端-服务器通信 流套接字 (TCP:`bind()`)

哥伦比亚

大学

34`bind()`

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

当使用 socket(2) 创建套接字时,它存在于一个命名空间地址族)中,但没有为其分配地址bind()addr 指定的地址分配给由文件描述符 sockfd 引用的套接字addrlen 指定由 addr 指向的地址结构的大小(以字节为单位)。传统上,此操作称为“为套接字命名”。

35C 语言中的 TCP 服务器代码

```

int serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = htonl(INADDR_ANY);

echoserver.sin_port = htons(atoi(argv[1]));

bind(serversock, (struct sockaddr *) &echoserver,

sizeof(echoserver));

```

36绑定套接字

```

/ Internet address /

struct in_addr {

uint32_t s_addr; / address in network byte order /

};

struct sockaddr_in {

sa_family_t sin_family; / unsigned short, address family: AF_INET /

in_port_t sin_port; / unsigned short, port in network byte order /

struct in_addr sin_addr; / internet address /

char sin_zero[8]; / Not used /

};

struct sockaddr {

sa_family_t sa_family; / unsigned short /

char sa_data[14]; / blob /

};

\begin{tabular}{|l|l|l|l|l|l|}

\hline \multirow{5}{*}{\begin{tabular}{l}

sockaddr_in \\

sockaddr

\end{tabular}} & sa_family & \multicolumn{4}{|c|}{sa_data} \\

\hline & Family & \multicolumn{4}{|c|}{Blob (14 bytes)} \\

\hline & 2 bytes & 2 bytes & 4 bytes & & 8 bytes \\

\hline & Family & Port & Internet address & & Unused \\

\hline & sin_family & sin_port & sin_addr & & sin_zero \\

\hline

\end{tabular}

\begin{tabular}{|l|}

\hline Format of struct sockaddr \\

depends on specified \\

domain. \\

To use a single bind interface \\

for all domains, we use the \\

most general format - struct \\

sockaddr. \\

A domain specific format can \\

be typecast to struct \\

sockaddr when binding.

\end{tabular}

Do "man sockaddr" to see all the specific types.

```

37字节序

为了连接到远程计算机并使用套接字,我们需要使用其地址

LINUX小端序,但 TCP/IP 使用大端序字节排序

对于小端序最低有效字节(“小端”)存储在最低内存地址处。

对于大端序最低有效字节(“小端”)存储在最高内存地址处。

大端序

小端序

38字节序

C 语言中用于确定系统字节序的简单代码。

xint 类型,所以 x=1 会根据你的架构存储如下:

小端

| 字节 | 地址 |

| :---: | :---: |

| 00000000 | 1003 |

| 00000000 | 1002 |

| 00000000 | 1001 |

| 00000001 | 1000 |

大端

| 字节 | 地址 |

| :---: | :---: |

| 00000001 | 1003 |

| 00000000 | 1002 |

| 00000000 | 1001 |

| 00000000 | 1000 |

39字节序

TCP/IP转换函数

```

#include

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

```

40客户端-服务器通信 流套接字 (TCP:`listen()`)

哥伦比亚

41`listen()`

int listen(int sockfd, int backlog);

许多客户端请求可能会到达服务器

listen() 将由 sockfd 引用的套接字标记为被动套接字,即一个将用于使用 accept() 接受传入连接请求套接字

42参数:

成功时返回 0,错误时返回 -1。

listen()非阻塞的;它立即返回。

43C 语言中的 TCP 服务器代码

```

#define MAXPENDING 5

int serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = htonl(INADDR_ANY);

echoserver.sin_port = htons(atoi(argv[1]));

bind(serversock, (struct sockaddr *) &echoserver,

sizeof(echoserver));

listen(serversock, MAXPENDING);

```

44客户端-服务器通信 流套接字 (TCP:`accept()`)

哥伦比亚

45`accept()`

```

int accept(int sockfd, struct sockaddr *addr,

socketlen_t *addrlen);

```

现在服务器所能做的就是等待

等待连接请求的到来。

它会阻塞直到请求到来,然后接受新请求

46参数:

成功时返回接受的套接字文件描述符错误时返回 -1。

47C 语言中的 TCP 服务器代码

```

#define MAXPENDING 5

int clientsock, serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoclient, echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = htonl(INADDR_ANY);

echoserver.sin_port = htons(atoi(argv[1]));

bind(serversock, (struct sockaddr *) &echoserver,

sizeof (echóserver));

listen(serversock, MAXPENDING);

clientsock = accept(serversock,

(struct sockaddr *) &echoclient,

sizeof(echoclient));

```

48客户端-服务器通信 流套接字 (TCP:`accept()`)

哥伦比亚

49`socket()`

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

socket() 创建一个通信端点并返回一个文件描述符,该文件描述符引用该端点。成功调用返回的文件描述符将是进程中当前未打开的最低编号文件描述符

AF_INET 用于 IPv4

AF_INET6 用于 IPv6

SOCK_STREAM: 可靠字节流 (TCP)

SOCK_DGRAM: 面向消息服务 (UDP)

UNSPEC: 未指定

(AF_INETSOCK_STREAM 已经暗示 TCP,"0" 设置协议)

sockfd = socket(AF_INET, SOCK_STREAM, 0);

50C 语言中的 TCP 客户端代码

```

int clientsock;

clientsock = socket(AF_INET, SOCK_STREAM, O);

```

51客户端-服务器通信 流套接字 (TCP:`accept()`)

哥伦比亚

52`connect()`

```

int connect(int sockfd, const struct sockaddr *addr,

socklen_t addrlen);

```

connect() 系统调用将由文件描述符 sockfd 引用的套接字连接到由 addr 指定的地址addr 中的地址格式由套接字 sockfd地址空间决定。

53参数:

成功时返回 0,错误时返回 -1。

注意客户端不需要调用 bind()

54C 语言中的 TCP 客户端代码

```

int clientsock;

clientsock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = inet_addr(argv[1]);

echoserver.sin_port = htons(atoi(argv[2]));

connect(clientsock, (struct sockaddr *) &echoserver,

sizeof(echoserver));

```

55客户端-服务器通信 流套接字 (TCP:`recv()`)

哥伦比亚

56`send()`

```

ssize_t send(int sockfd, const void *buf, size_t len,

int flags);

```

五个不同的系统调用用于发送数据sendsendtosendmsgwritewritev

在本课程中,我们将使用 send,它通常与连接套接字一起使用。

send()write() 之间唯一的区别在于标志的存在。当零标志参数时,send() 通常等价于 write()

57参数:

成功时返回发送字节数错误时返回 -1。

58C 语言中的 TCP 客户端代码

```

#define BUFSIZE 32

int clientsock;

clientsock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = inet_addr(argv[1]);

echoserver.sin_port = htons(atoi(argv[2]));

connect(clientsock, (struct sockaddr *)&echoserver,

sizeof(echoserver));

char buffer[BUFSIZE];

unsigned int len = strlen(argv[3]);

// Send '\0' too.

send(clientsock, argv[3], len + 1, 0);

```

59`recv()`

```

ssize_t recv(int sockfd, void *buf, size_t len,

int flags);

```

五个不同的系统调用用于接收数据recvrecvfromrecvmsgreadreadv

在本课程中,我们将使用 recv,它通常与连接套接字一起使用。

recv()read() 之间唯一的区别在于标志的存在。当零标志参数时,recv() 通常等价于 read()

60参数:

成功时返回接收字节数错误时返回 -1。

哥伦比亚大学

```

#define MAXPENDING 5

#define BUFSIZE 32

int clientsock, serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echōclient, echoserver;

memset(&echoservier, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = htonl(INADDR ANY);

echoserver.sin_port =-htons(atoi(argv[1]));

bind(serversock), (struct sockaddr *)&echoserver,

sizeof(echoserver));

listen (serversock, MAXPENDING) ;

clientsock = accept(serversock,

(struct sockaddr *) &echoclient,

sizeof(echoclient));

char buffer[BUFSIZE];

ssize_t num_recv = recv(clientsock, buffer, BUFSIZE, 0);

```

61客户端-服务器通信 流套接字 (TCP:`send()`)

哥伦比亚

62`send()`

```

ssize_t send(int sockfd, const void *buf, size_t len,

int flags);

```

五个不同的系统调用用于发送数据sendsendtosendmsgwritewritev

在本课程中,我们将使用 send,它通常与连接套接字一起使用。

send()write() 之间唯一的区别在于标志的存在。当零标志参数时,send() 通常等价于 write()

63参数:

成功时返回发送字节数错误时返回 -1。

64客户端-服务器通信 流套接字 (TCP:`recv()`)

哥伦比亚

```

#define MAXPENDING 5

#define BUFSIZE 32

int clientsock, serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echōclient, echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = htonl(INADDR ANY);

echoserver.sin_port =-htons(atoi(argv[1]));

bind(serversock, (struct sockaddr *) &echoserver,

sizeof(echoserver));

listen(serversock, MAXPENDING);

clientsock = accept(serversock,

(struct sockaddr *) &echoclient,

sizeof(echoclient));

char buffer[BUFSIZE];

ssize_t num_recv = recv(clientsock, buffer, BUFSIZE, 0);

send(clientsock, buffer, num_recv, 0);

```

```

#define BUFSIZE 32

int clientsock;

clientsock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = inet_addr(argv[1]);

echoserver.sin_port = htons(atoi(argv[2]));

connect(clientsock, (struct sockaddr *)&echoserver,

sizeof(echoserver));

char buffer[BUFSIZE];

unsigned int len = strlen(argv[3]);

// Send '\0' too.

send(sock, argv[3], len + 1, 0);

ssize_t num_recv = recv(sock, buffer, BUFSIZE, 0);

// len + 1 should equal num_recv

```

65客户端-服务器通信 流套接字 (TCP:`recv()`)

哥伦比亚

66`close()`

int close(int fd);

close() 关闭一个文件描述符,使其不再引用任何文件,并且可以重用

成功时返回 0,错误时返回 -1。

67C 语言中的 TCP 客户端代码

```

#define BUFSIZE 32

int clientsock;

clientsock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = inet_addr(argv[1]);

echoserver.sin_port = htons(atoi(argv[2]));

connect(clientsock, (struct sockaddr *)&echoserver,

sizeof(echoserver));

char buffer[BUFSIZE];

unsigned int len = strlen(argv[3]);

// Send '\0' too.

send(sock, argv[3], len + 1, 0);

ssize_t num_recv = recv(sock, buffer, BUFSIZE, 0);

// len + 1 should equal num_recv

close(clientsock) ;

```

```

#define MAXPENDING 5

#define BUFSIZE 32

int clientsock, serversock;

serversock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in echōclient, echoserver;

memset(&echoserver, 0, sizeof(echoserver));

echoserver.sin_family = AF_INET;

echoserver.sin_addr.s_addr = htonl(INADDR ANY);

echoserver.sin_port =-htons(atoi(argv[1]));

bind(serversock, (struct sockaddr *) &echoserver,

sizeof(echoserver));

listen(serversock, MAXPENDING);

clientsock = accept(serversock,

(struct sockaddr *) &echoclient,

sizeof(echoclient));

char buffer[BUFSIZE];

ssize_t num_recv = recv(clientsock, buffer, BUFSIZE, 0);

send(clientsock, buffer, num_recv, 0);

close(clientsock) ;

close(serversock);

```