网络

网络其实就是跨主机的“进程间”通信
协议分层

  • 分层的意义:网络协议比较复杂,如果不拆分就会很复杂
  • 分层的好处:拆分成多个模块相当于降低了整个系统的耦合程度,根据实际需要,随时可以替换其中的某一层协议
    OSI七层模型:
    认识网络(一)_第1张图片
    认识网络(一)_第2张图片
    TCP/IP五层(或四层)模型
    认识网络(一)_第3张图片
    由图可见网络层和传输层都是由操作系统内核来实现的,我们所开发的程序就是调用这些内核提供的传输层系统调用(socket api)来完成应用层的程序。每一层都包含了不同的协议。
    网络中的常见设备和协议的关系:
  • 对于一台主机, 它的操作系统内核实现了从传输层到物理层的内容;
  • 对于一台路由器, 它实现了从网络层到物理层;
  • 对于一台交换机, 它实现了从数据链路层到物理层;
  • 对于集线器, 它只实现了物理层;
    上下层协议之间交互数据的时候两步:封装和分用(就相当于是包装快递和拆快递)
    认识TCP和UDP协议
    TCP:
  • 传输层协议
  • 有连接(打电话,必须双方同意通信)
  • 可靠传输(知道数据是否发送成功,本质上靠对方的反馈)
  • 面向字节流(发送数据和接收数据可以随意控制,非常灵活,水管的例子)
    UDP:
  • 传输层协议
  • 无连接(发qq,不需要双方同意通信)
  • 不可靠传输(不知道数据是否发送成功)
  • 面向数据报(一次发多少数据一次就要接多少,否则会造成数据的损失,对读写要求严格,读写一致)
    网络字节序(大端序),统一转化为大端序再发送到网络上,主机字节序(不确定,和机器相关)
    相关函数:
    h->主机 n->网络
    认识网络(一)_第4张图片

SOCKET

服务端和客户端
主动发送数据的是客户端,被动接受的是服务端,一个进程是客户端和服务器端都不是固定的
端口号:端口号(port)是传输层协议的内容.端口号是一个2字节16位的整数;端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;一个端口号只能被一个进程占用.
socket函数系列

  • socket函数(客户端+服务器)的返回值本质上是一个文件描述符,但不是和磁盘上的文件对应,而是和网卡这样的设备对应,对应的文件类型是socket类型(TCP/UDP)
  • bind(通常是服务器使用,客户端也可以但是很少用,客户端不bind操作系统将会随机分配端口号,服务器是不能随机【导致产生随机变化客户端端口号,使服务器无法连接】) 作用是把socket文件和端口号关联在一起(绑定端口号),一个进程可以关联到多个端口号,因为bind将端口号和文件描述符关联,而一个进程可以创建多个socket文件描述符,反之一个端口号只能找到一个进程(TCP/UDP)
    理解bind第二个参数 const struct sockaddr address
    这是一个结构体,它的结构如下:
    认识网络(一)_第5张图片
    struct sockaddr_in 这个结构体是struct sockaddr的一种特殊形式,IPv4是用这种结构表示的,其中有16位地址类型、16位端口号和32位IP地址,IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容,而我们通常是通过设置struct sockaddr_in 这个结构体并且在使用时强制转化为(sockaddr
    )这样做虽然麻烦,但是提高了程序的通用性。

           

  • listen(服务器使用)进入监听状态,随时等待客户端发送的请求->相当于手机开机信号良好(TCP)
    int listen(int s, int backlog);
    这个函数的第二个参数表示已经完成连接正等待应用程序接收的套接字队列的长度,描述+组织 -> 所谓的连接指的是五元组(源IP,源端口,目的IP,目的端口,协议),这个队列就是维护这些连接状态,而这个队列是和socket相关的,每个调用listen的socket就有一个这样的队列。
  • accept(服务器使用)接受链接->相当于电话来了按下接通键(TCP)
    int accept(int s, struct sockaddr * addr, socklen_t * addrlen);
    从连接队列中取一个连接到用户代码中,如果队列中没有连接会阻塞
    它的返回值也是一个socket文件描述符,后续和客户端的交流都是借助这个返回值
    它的后两个参数是出参,返回客户端的的地址和IP,如果不关心可以传NULL
  • connet(客户端使用)发起连接请求->相当于给别人拨电话(TCP)
  • 发送/接受
    read/write:只针对TCP,因为read/write是面向字节流的
    recv/send(只针对TCP,比read/write功能更加丰富)
    recv():recv()的返回值表示读取成功的字节数,如果读取失败返回-1,如果对端关闭socket返回结果为0
    recvfrom/sendto(针对UDP)