Linux网络编程基础

第5章 Linux网络编程基础API

5.1 socket地址API

5.1.1 主机字节序和网络字节序
  • 大端字节序(网络字节序):指一个整数的高位字节(23-31bit)存储在内存的低地址处,低位字节(0-7bit)存储在内存的低地址处
  • 小端字节序(主机字节序):整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的低地址处

主机字节序与网络字节序之间的转换:发送端总是把要发送的数据转换成大端字节序数据后再发送,而接收端知道对方传送过来的数据总是采用大端字节序,所以接收端可以根据自身采用的字节序决定是否对接收到的数据进行转换

5.1.2 通用socket地址

socket网络编程接口中表示socket地址的是结构体sockaddr
在这里插入图片描述

  • sa_family 地址族类型的变量
    地址族类型常与协议族类型对应

  • sa_data 存放socket地址值
    不同的协议族的地址值具有不同的含义和长度

14字节的sa_data根本无法完全容纳多数协议族的地址值,因此Linux定义了新的通用的socket地址结构体sockaddr_storage

在这里插入图片描述
这个结构体不仅提供了足够大的空间用于存放地址值,而且是内存对齐的,这是_ss_align成员的作用

5.1.3 专用socket地址

Linux为各个协议族提供了专门的socket地址结构体

  • Unix本地域协议族使用如下专用socket地址结构体

在这里插入图片描述

  • TCP/IP协议族使用sockaddr_in和sockaddr_in6两个专用socket地址结构体,它们分别用于IPv4和IPv6

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

所有专用socket地址类型的变量在实际使用时都需要转化为通用socket地址类型sockaddr(强制转换),因为所有的socket编程接口使用的地址参数类型都是sockaddr。

5.1.4 IP地址转换函数

编程中需要把用点分十进制表示的IPv4地址和用十六进制表示的IPv6地址转换成整数方能使用,而记录日志时则相反。
在这里插入图片描述

5.2 创建socket

Linux中,所有东西都是文件,socket也是一个可读,可写,可控制,可关闭的文件描述符。
创建socket:
在这里插入图片描述
参数:

  • domain 告诉系统使用哪个底层协议族
    对TCP/IP协议族而言,该参数设为PF_INET或PF_INET6。

  • type 指定服务类型
    服务类型主要有SOCK_STREAM服务(传输层使用TCP协议)和SOCK_UGRAM服务(传输层使用UDP协议)

  • protocol参数是指在前两个参数构成的协议集合下,再选择一个具体的协议,这个值通常都是唯一的,一般设置为0,表示使用默认协议

5.3 命名socket

将一个socket与socket地址绑定称为给socket命名。在服务器程序中,通常要命名socket,因为只有命名之后客户端才能知道如何连接它,客户端则通常不需要命名socket,而是采用匿名方式,即使用操作系统自动分配的socket地址,命名socket调用bind
在这里插入图片描述
bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数指出该socket地址的长度。

5.4监听socket

socket被命名之后,还不能马上接受客户连接,使用如下系统调用来创建一个监听队列以存放待处理的客户连接
在这里插入图片描述
参数:

  • sockfd参数指定被监听的socket
  • backlog参数提示内核监听队列的最大长度

5.5 接受连接

从listen监听队列中接受一个连接
在这里插入图片描述
参数:

  • sockfd 执行过listen系统调用的监听socket
  • addr 获取被接受连接的远端socket地址
  • addrlen socket地址的长度

5.6 发起连接

服务器通过listen调用来被动接受连接,那么客户端需要通过如下系统调用来主动与服务器建立连接
在这里插入图片描述
参数:

  • sockfd 由socket系统调用返回一个socket
  • serv_addr 服务器监听的socket地址
  • addrlen 指定这个地址的长度

5.7 关闭连接

关闭一个连接实际上就是关闭该连接对应的socket,这可以通过关闭普通文件描述符的系统调用来完成
在这里插入图片描述
fd参数是待关闭的socket,不过close系统调用并非总是立即关闭一个连接,而是将fd的引用计数减1,只有当fd的引用计数为0时,才真正关闭连接,多进程程序中,一次fork系统调用默认将使父进程中打开的socket的引用计数加1,因此我们必须在父进程和子进程中都对该socket执行close调用才能将连接关闭。
如果要立即终止连接,而不是将socket的引用计数减1,可以使用shutdown系统调用,相对于close来说,它是专门为网络编程设计的。
在这里插入图片描述
参数:

  • sockfd 待关闭的socket
  • howto 决定了shutdown的行为

shutdown能够分别关闭socket上的读或写,或者都关闭
close在关闭连接时只能将socket上的读和写同时关闭

5.8 数据读写

5.8.1 TCP数据读写

对文件的读写操作read和write同样适用于socket,但socket编程接口提供了几个专门用于socket数据读写的系统调用。它们增加了对数据读写的控制
用于TCP流数据读写的系统调用是:
在这里插入图片描述
在这里插入图片描述

5.8.2 UDP数据读写

在这里插入图片描述

5.8.3 通用数据读写函数

socket编程接口还提供了一对通用的数据读写调用,不仅能用于TCP流数据,也能用于UDP数据报
在这里插入图片描述
在这里插入图片描述

5.10 地址信息函数

在这里插入图片描述

5.12 网络信息API

socket地址的两个要素,即IP地址和端口号,都是用数值表示的,我们用主机名来访问一台机器,而避免直接使用其IP地址,同样我们用服务名称来代替端口号,比如下面两条telnet命令具有完全相同的作用
在这里插入图片描述
telnet客户端程序是通过调用某些网络信息API来实现主机名到IP地址的转换,以及服务名称到端口号的转换的。

5.12.1 gethostbyname和gethostbyaddr
  • gethostbyname函数根据主机名称获取主机的完整信息
  • gethostbyaddr函数根据IP地址获取主机的完整信息

在这里插入图片描述

5.12.2 getservbyname和getservbyport
  • getservbyname函数根据名称获取某个服务的完整信息
  • getservbyport函数根据端口号获取某个服务的完整信息

在这里插入图片描述

5.12.3 getaddrinfo

getaddrinfo函数既能通过主机名获得IP地址(内部使用的是gethostbyname函数),也能通过服务名获得端口号(内部使用的是getservbyname函数)

5.12.4 getnameinfo

getnameinfo函数能通过socket地址同时获得以字符串表示的主机名(内部使用的是gethostbyaddr函数)和服务名(内部使用的是getservbyport函数)

第6章 高级I/O函数

6.1 pipe函数

pipe函数可用于创建一个管道,以实现进程间通信
在这里插入图片描述

  • pipe函数的参数是一个包含两个int型整数的数组指针,该函数成功时将一对打开的文件描述符填入其参数指向的数组。
  • 通过pipe函数创建的两个文件描述符fd[0]和fd[1],分别构成管道的两端,往fd[1]写入的数据可以从fd[0]读出,并且fd[0]只能用于从管道读出数据,fd[1]则只能用于往管道写入数据,而不能反过来用。如果要实现双向的数据传输,就应该使用两个管道。
  • 管道内部传输的数据是字节流,管道本身拥有一个容量限制,它规定应用程序如果不将数据从管道读走的话,该管道最多能被写入多少字节的数据,管道容量的大小默认是65536字节
  • socketpair函数能够方便地创建双向管道

在这里插入图片描述

6.2 dup函数和dup2函数

通过复制文件描述符的dup或dup2函数来实现把标准输入重定向到一个文件,或者把标准输出重定向到一个网络连接
在这里插入图片描述
dup函数创建一个新的文件描述符,该新文件描述符与原文件描述符file_descriptor指向相同的文件、管道或者网络连接,并且dup返回的文件描述符总是取系统当前可用的最小整数值。dup2和dup类似,不过它将返回第一个不小于file_descriptor_two的整数值。

6.3 readv函数和writev函数

  • readv函数 分散读:将数据从文件描述符读到分散的内存块中
  • writev函数 集中写:将多块分散的内存数据一并写入文件描述符

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

6.4 sendfile函数

sendfile函数在两个文件描述符之间直接传递数据,完全在内核中操作,从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,这被称为零拷贝。
在这里插入图片描述
在这里插入图片描述

6.5 mmap函数和munmap函数

  • mmap函数用于申请一段内存空间,可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中。
  • munmap函数则释放由mmap创建的这段内存空间

在这里插入图片描述

6.6 splice函数

splice函数用于在两个文件描述符之间移动数据,也就是零拷贝操作
在这里插入图片描述

6.7 fcntl函数

提供了对文件描述符的各种控制操作
在这里插入图片描述

第7章 Linux服务器程序规范

7.1 日志

7.1.1 Linux系统日志

Linux提供一个守护进程来处理系统日志文件——syslogd,现在的Linux系统上使用的都是它的升级版——rsyslogd
在这里插入图片描述

7.2 用户信息

7.2.1 UID、EUID、GID和EGID

用户信息对于服务器程序的安全性来说是很重要的,比如大部分服务器就必须以root身份启动,但不能以root身份运行。

  • UID——真实用户ID
  • EUID——有效用户ID
  • GID——真实组ID
  • EGID——有效组ID

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

第8章 高性能服务器框架

8.1 服务器模型

8.1.1 C/S模型

在这里插入图片描述
C/S模型非常适合资源相对集中的场合,实现简单,但是缺点是服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应。

8.1.2 P2P模型

P2P模型比C/S模型更符合网络通信的实际情况,它摒弃了以服务器为中心的格局,使每台机器在消耗服务的同时也给别人提供服务,缺点是当用户之间传输的请求过多时,网络的负载将加重。
在这里插入图片描述
实际使用的P2P模型通常带有一个专门的发现服务器,可以提供查找服务,使每个客户都能尽快地找到自己需要的资源。

8.2 服务器编程框架

服务器程序种类繁多,但是其基本框架都一样,不同之处在于逻辑处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • I/O处理单元:服务器管理客户连接的模块,它要完成等待并接受新的客户连接,接收客户数据,将服务器响应数据返回给客户端。
  • 逻辑单元:通常是一个进程或者线程,它分析并处理客户数据,然后将结果传递给I/O处理单元或者直接发送给客户端
  • 网络存储单元:可以是数据库、缓存和文件,甚至是一台独立的服务器,但它不是必须的,比如ssh,telnet等登录服务就不需要这个单元
  • 请求队列:各单元之间的通信方式的抽象
    在这里插入图片描述

8.3 I/O模型

阻塞和非阻塞的概念能够应用于所有的文件描述符,而不仅仅是socket,称阻塞的文件描述符为阻塞I/O,称非阻塞的文件描述符为非阻塞I/O。
在这里插入图片描述
在这里插入图片描述

8.4 两种高效的事件处理模式

服务器程序通常需要处理三类事件:I/O事件、信号及定时事件
两种高效的事件处理模式:

8.4.1 Reactor模式:

在这里插入图片描述

8.4.2 Proactor模式:

在这里插入图片描述

8.5 两种高效的并发模式

8.5.1 半同步/半异步模式

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

8.5.2 领导者/追随者模式

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

8.7 提高服务器性能的其他建议

8.7.1 池

概念:
池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源分配。
在这里插入图片描述
分类:根据不同的资源类型,池可分为多种,常见的有

  • 内存池:通常用于socket的接收缓存和发送缓存
  • 进程池,线程池:当我们需要一个工作进程或工作线程来处理新到来的客户请求时,可以直接从进程池或线程池中取得一个执行实体,而无需动态调用函数来创建进程和线程
  • 连接池:通常用于服务器或服务器机群的内部永久连接
8.7.2 数据复制

在这里插入图片描述

8.7.3 上下文切换和锁

线程间的切换将占用大量的CPU时间,服务器真正用于处理业务逻辑的CPU时间的比重就显得不足了,因此为每个客户连接都创建一个工作线程的服务器模型是不可取的。
多线程服务器的一个优点是可以同时运行在不同的CPU上,当线程的数量不大于CPU的数目时,上下文的切换就不是问题了。
在这里插入图片描述

第9章 I/O复用

I/O复用使得程序能同时监听多个文件描述符

9.1 select 系统调用

用途:在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件

9.2 poll系统调用

用途:在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者

9.3 epoll系列系统调用

第10章 信号

信号是由用户、系统或进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常

10.1 Linux信号概述

10.1.1 发送信号

在这里插入图片描述

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值