---
###### tags: `linux2022`
---
# CS:APP 第 11 章
contributed by < `eric88525` >
[鳥哥網路介紹,建議先看](https://linux.vbird.org/linux_server/centos6/0110network_basic.php)
[video: network programming: Part 1
](https://scs.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=54178cf8-d57e-4984-b46c-b66db645431a)
# 1. Overview
+ 大部分的網路架構都是 client-server 架構

+ network 是透過有限或是無線相連的系統
+ SAN (system area network)
+ LAN (local area network)
+ WAN (wide area network )
+ **i**nternet vs **I**nternet
+ 小寫的 i 代表互相連接的網路
+ Golbal IP Internet 是最有名的 internet
# 2. Network
+ [Hub(集線器)、Bridge(橋接器)、Switch(交換器)與Router(路由器)](https://giboss.pixnet.net/blog/post/26798642)
+ [鳥哥 linux 私藏 / 共不共享很重要,集線器還是交換器? ](https://linux.vbird.org/linux_server/centos6/0110network_basic.php)
+ 最大的差異在於集線器 hub 封包都是可見的,交換器是會單獨傳送
+ [router switch hub](https://tung168.pixnet.net/blog/post/330937279-%E7%B6%B2%E8%B7%AF%E8%A8%AD%E5%82%99hub%E3%80%81switch%E5%92%8Crouter%E7%9A%84%E5%B7%AE%E7%95%B0)
## lowest level: Ethernet Segment
+ 用於房間或是一層樓
+ each ethernet adapter has 48-bit address(MAC address)
+ host 間傳遞 bit 資料的單位為 **frames**
+ hub 很懶惰,every host sees every bit
```graphviz
graph{
node[shape=box]
host1--hub
host2--hub [label=" port"]
}
```
## Bridged Ethernet Segment
+ 一堆的 ethernet 可以連成 LAN
+ bridge 知道要把資料傳給哪個 host
+ 用於學校或公司

# 3. internets (lower case)
透過 router 來連接多個 LAN (這些 LAN 未必相同架構)

## internet protocol
+ 提供了 naming scheme (命名規則),如 host address
+ 每個 host 都有他專屬的 address 來識別
+ 定義了傳遞機制,基本單位為 packet
+ packet 含有 **header**(packet 資訊) 和 **payload**(資料)
在此架構下的傳遞情況
+ PH: internet packet header
+ FH: LAN frame header

# 4. Global IP Internet
+ 最有名的 internet
+ base on TCP/IP
+ IP (Internet Protocol): provieds **basic naming scheme** and unrealiable delivery capability of packets from **host-to-host**
+ UDP (Unreliable datagram protocol): **process-to-process** 但不穩定
+ TCP (transmission control protocol): 透過 IP 來進行可靠的 **process-to-process** 傳輸
## hardware and software organization of an internet application

+ 站在程式的角度
+ Hosts 映射到 32-bit **IP address**
+ The set of **IP addresses** is mapped to set of identifiers called internet **domain names**
+ 不同 host 的 process 可透過 **connection** 來溝通
## IPv4 and IPv6
+ 32 bit-ipv4 不夠用了,因此有 128 bit ipv6 替代
+ IP address 被存在 IP address struct,格式為 **network byte order**
```c
/* Internet address structure */
struct in_addr {
uint32_t s_addr; /*network byte order (big-endian)*/
}
```
Network byte-order conversion functions
l: 32bits
s: 16bit
h: host
n: network
```c
htonl // convert uint32_t from [host] to [network] byte order
htons // convert uint16_t from [host] to [network] byte order
ntohl // convert uint32_t from [network] to [host] byte order
ntohs // convert uint16_t from [network] to [host] byte order
```
Function of converting between **binary IP address** and **dotted decimal strings**
"n": network, "p" presentation
```c
inet_pton: dotteed deciaml string -> IP address in network byte order
inet_ntop: IP address in network byte order -> dotteed deciaml string
```
## internet domain name
> Q: 要如何將 domain name 對應到 ip 呢?
> A: Internet 會維護 IP address <-> domain name 的對應,這些儲存在 **huge worldwide distributed database** called **DNS**

查詢 DNS 可透過 `nslookup` 來查找
```c
$ nslookup www.google.com
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
Name: www.google.com
Address: 74.125.200.105
Name: www.google.com
Address: 74.125.200.106
Name: www.google.com
Address: 74.125.200.104
Name: www.google.com
Address: 74.125.200.99
Name: www.google.com
Address: 74.125.200.147
Name: www.google.com
Address: 74.125.200.103
Name: www.google.com
Address: 2404:6800:4012:2::2004
```
## Internet connections
client 和 server 可透過 `connections` 互相傳輸 bytes stream , `connection` 的特性
+ point-to-point
+ Full-duplex: 雙向的
+ Reliable: 資料順序不會變動
A **socket** is an endpoint of a connection
+ Socket address = **IPaddress:port**
A **port** is a 16-bit interger that identifies a process
* Ephemeral(臨時) port: 當 client 連線時自動決定
* Well-know port: 提供特殊服務,對應表放在 `/etc/services`
* 7/ echo
* 22/ ssh
* 25/ smtp


# 5. socket
+ 對於 kernel, sokcet 是連線的終點
+ 對於 application 來說他就是一個 file descriptor 可以 read/write,在 linux 中萬物皆檔案

如果使用 **Internet-specific** socket,最後要轉形成 (struct sockaddr \*)。
當初會這樣設計是希望能有個 interface 能兼容所有種類的 socket address structure。(from book p902)
:+1: The _in suffix is short for internet, not input.
```c
/* Generic socket address structure (for connect, bind, and accept) */
struct sockaddr{
unsigned short sa_family; /* Protocol family */
char sa_data[14]; /* Address data */
};
/* Internet-style socket address structure */
struct sockaddr_in {
unsigned short sin_family; /* Address family (always AF_INET)*/
unsigned short sin_port; /* Port number in network byte order */
struct in_addr sin_addr; /* IP address in network byre order */
unsigned char sin_zero[8]; /* Pad to sizeof (struct sockaddr)*/
};
```

# 6. 程式介紹
## socket
用於 client 和 server 建立 socket。
```c
/* socket - create an endpoint for communication
* @domain: protocol
* @type: communication semantic
* @protocol: The protocol specifies a particular protocol to be used with the socket.
* */
int socket(int domain, int type, int protocol);
/* example */
int clientfd = socket(AD_INET, SOCK_STREAM, 0)
```
## connect
用於 client ,建立和 server 的連線,成功的話 sockfd 就能進行 read / write,
```c
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
```
## bind
+ 用於 server 端
+ The bind function tells the kernel to associate the server’s socket address in my_addr with the socket descriptor sockfd.
```c
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
```
## listen
+ 相較於 client 是主動連線, server 是等待連線。
+ 此函式將 sockfd 從 **active socket** 轉成具有接受連線能力的 **listening socket**
+ backlog 為提示 kernel 預計會有多少個連線,要先準備好
```c
#include <sys/socket.h>
/* Returns: 0 if OK, −1 on error */
int listen(int sockfd, int backlog);
```
## open_listenfd
結合了 `socket`, `bind`, `listen` 的 function
```c
#include "csapp.h"
/* Returns: descriptor if OK, −1 on Unix error */
int open_listenfd(int port);
```
## open_clientfd
把 socket 和 connect 包在一起的實做
```c
#include "csapp.h"
/* Returns: descriptor if OK, −1 on Unix error, −2 on DNS error */
int open_clientfd(char *hostname, int port);
```
```c
/*
* open_clientfd - open connection to server at <hostname, port>
* and return a socket descriptor ready for reading and writing.
* Returns -1 and sets errno on Unix error.
* Returns -2 and sets h_errno on DNS (gethostbyname) error.
*/
typedef struct sockaddr SA;
int open_clientfd(char *hostname, int port)
{
int clientfd;
struct hostent *hp;
struct sockaddr_in serveraddr;
if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1; /* check errno for cause of error */
/* Fill in the server's IP address and port */
if ((hp = gethostbyname(hostname)) == NULL)
return -2; /* check h_errno for cause of error */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *) hp->h_addr_list[0],
(char *) &serveraddr.sin_addr.s_addr,
hp->h_length);
serveraddr.sin_port = htons(port);
/* Establish a connection with the server */
if (connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr)) < 0)
return -1;
return clientfd;
}
```
## accept
Servers wait for connection requests from clients by calling the accept function
```c
#include <sys/socket.h>
/* accept - accept a connection on a socket */
int accept(int sockfd, struct sockaddr *restrict addr,
socklen_t *restrict addrlen);
```

## Example code
client 端
```c
/*
* echoclient.c - An echo client
*/
/* $begin echoclientmain */
#include "csapp.h"
int main(int argc, char **argv)
{
int clientfd;
char *host, *port, buf[MAXLINE];
rio_t rio;
if (argc != 3) {
fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
exit(0);
}
host = argv[1];
port = argv[2];
clientfd = Open_clientfd(host, port);
Rio_readinitb(&rio, clientfd);
while (Fgets(buf, MAXLINE, stdin) != NULL) {
Rio_writen(clientfd, buf, strlen(buf));
Rio_readlineb(&rio, buf, MAXLINE);
Fputs(buf, stdout);
}
Close(clientfd); //line:netp:echoclient:close
exit(0);
}
/* $end echoclientmain */
```
Server 端
```c
/*
* echoserveri.c - An iterative echo server
*/
#include "csapp.h"
/*
* echo - read and echo text lines until client closes connection
*/
void echo(int connfd)
{
size_t n;
char buf[MAXLINE];
rio_t rio;
Rio_readinitb(&rio, connfd);
while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { //line:netp:echo:eof
printf("server received %d bytes\n", (int)n);
Rio_writen(connfd, buf, n);
}
}
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t clientlen;
struct sockaddr_storage clientaddr; /* Enough space for any address */ //line:netp:echoserveri:sockaddrstorage
char client_hostname[MAXLINE], client_port[MAXLINE];
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(0);
}
listenfd = Open_listenfd(argv[1]);
while (1) {
clientlen = sizeof(struct sockaddr_storage);
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
Getnameinfo((SA *) &clientaddr, clientlen, client_hostname, MAXLINE,
client_port, MAXLINE, 0);
printf("Connected to (%s, %s)\n", client_hostname, client_port);
echo(connfd);
Close(connfd);
}
exit(0);
}
```
## getaddrinfo
> Given node and service, which identify an Internet host and a
service, getaddrinfo() returns one or more addrinfo structures,
each of which contains an Internet address that can be specified
in a call to bind(2) or connect(2).
```c
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
/* Given node and service, which identify an Internet host and a service,
* getaddrinfo() returns one or more addrinfo structures, each of which
* contains an Internet address that can be specified in a call to
* bind(2) or connect(2). */
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
```
Struct of addrinfo returned by getaddrinfo
```c
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
```
前面提到 `nslookup` 可以找 domain 對應許多ip, getaddrinfo 回傳的 linked list 長這樣

`getnameinfo` 則是相反,將 socket address 轉成對應的 host 和 service
```c
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
char *restrict host, socklen_t hostlen,
char *restrict serv, socklen_t servlen, int flags);
```
# Web Servers
+ web client 和 server 使用 text-based application-level protocol **HTTP(Hypertext transfer protocol)** 溝通。
```graphviz
digraph{
node [shape=box]
label="HTTP protocol"
client->server [label="request"]
server->client [label = "content"]
rankdir="LR"
}
```
## web content
+ content is a sequence of bytes with an associated MIME (Multipurpose Internet Mail Extensions) type
+ content 分為 static 和 dynamic content,差別在於有沒有需要處理資料