-端口号是一个2字节16位的整数;
TCP(Transmission Control Protocol 传输控制协议)

TCP如何决定有效载荷和报头如何分离?
先读取前20个字节,提取出其中4位首部长度,然后让首部长度✖4,就是报头大小,就可以将报头和有效载荷分离出来。
TCP如何决定将自己的有效载荷交付给上层的那个协议?
目的端口号就可以决定将有效载荷交给谁
tcp建立连接就是三次握手

这就是三次握手。
三次握手属于通信细节!!上层用户不需要关心,双方OS(TCP)自动完成。

什么是可靠性?什么是真正的可靠性?
一般而言,我们认为只有我发的消息收到了回应,才算我发的消息可靠的被对方收到。
一般而言,发送的数据都要有响应,这是保证可靠性的底层策略,这就是确认应答机制。

TCP将每个字节的数据都进行了编号. 即为序列号(保证可靠性)

每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发。
为什么TCP要用两套序号机制——确认序号和序号?
因为TCP是全双工的。可能同时双方都在进行通信。

如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发
但是, 主机A未收到B发来的确认应答, 也可能是因为ACK丢失了

因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉. 这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.
UDP(User Datagram Protocol 用户数据报协议)

UDP传输的过程类似于寄信
UDP如何保证自己的报头和有效载荷分离?
*****UDP是定长报头(8字节)
UDP如何让决定自己的有效载荷交付给上层的那个协议?
*****因为有目的端口号
什么叫做报头?
UDP是属于内核协议栈(C语言),用C语言是如何标识报头呢?
传输层是如何通过端口号找到对应的服务器的进程
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,
socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
套接字不仅支持跨网络的进程间通信,还支持本地的进程间通信(域间套接字)。在进行跨网络通信时我们需要传递的端口号和IP地址,而本地通信则不需要,因此套接字提供了sockaddr_in结构体和sockaddr_un结构体,其中sockaddr_in结构体是用于跨网络通信的,而sockaddr_un结构体是用于本地通信的。
为了让套接字的网络通信和本地通信能够使用同一套函数接口,于是就出现了sockeaddr结构体,该结构体与sockaddr_in和sockaddr_un的结构都不相同,但这三个结构体头部的16个比特位都是一样的,这个字段叫做协议家族。

端口号(Port)标识了一个主机上进行通信的不同的应用程序;

在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看);


一个进程是否可以bind多个端口号
可以的
一个端口号是否可以被多个进程bind
这是不行的,因为一个端口号只能标识唯一一个进程