Linux高性能服务器编程阅读笔记

TCP/IP协议族

TCP协议详解

TCP服务的特点

  • 面向连接、字节流
  • 可靠传输
    使用TCP协议通信的双方必须先建立连接,然后才能开始数据的读写。然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP连接是全双工的。即双方的数据读写可以通过一个连接进行。完成数据交换之后,通信双方都必须断开连接以释放系统资源。

Linux网络基础API

数据读写

TCP数据读写
#include<sys/types.h>
#include<sys/socket.h>
ssize_t recv(int sockfd,void *buf,size_t len,int flags);
ssize_t send(int sockfd,const void *buf,size_t len,int flags);

recv 读取sockfg上面的数据,buf和len参数分别制定读缓冲区的位置和大小。flags通常设置为0即可。recv成功时返回实际读取到的数据的长度,它可能小于长度len,因此可能需要多次调用recv才能读取到完整的数据。recv可能返回0,这意味着通信对方已经关闭了。recv出错时返回-1并设置errno。
send往sockfd上写入数据,buf和len参数分别指定写缓冲区的位置和大小。send成功时返回实际写入的数据的长度,失败则返回-1 并设置errno。

高级I/O函数

pipe函数

pipe函数可用于创建一个管道。以实现进程间通信。成功返回0,失败返回-1。

#include<unistd.h>
int pipe(int fd[2]);

通过pipe函数创建的这两个文件描述符fd[0]和fd[1]分别构成管道的两端。往fd[1]写入的数据可以从fd[0]读出。并且,fd[0]只能从管道读出数据,fd[1]只能往管道写入数据。而不能反过来使用。如果要实现双向的数据传输,就应该使用两个管道。默认情况下,这一对文件描述符都是阻塞的。此时如果使用read来读取一个空的管道。那么read将被阻塞。直到管道内有数据可读。如果使用write来向一个满的管道写入数据。则write亦将被阻塞。直到管道有足够多的空闲空间可用。
管道本身拥有一个容量限制。它规定如果应用程序不将数据从管道读走的话.该管道最多能够被写入多少字节的数据.可以通过fcntl函数来修改管道容量

#include<sys/types.h>
#include<sys/socket.h>
int socketpair(int domain,int type,int protocol,int fd[2]):

socketpair中的domain只能使用UNIX本地域协议族AF_UNIX,因为仅仅只能在本地使用这个双向管道。此时的fd是可读也可以是写的

dup和dup2函数

dup和dup2函数可以把标准输入重定向到一个文件或者把标准输出定向到一个网络连接。

#include<unistd.h>
int dup(int fd);
int dup2(int fd1,int fd2):

dup函数创建一个新的文件描述符。该新文件描述符和原有描述符fd指向相同的文件、管道或者网络连接。并且dup返回的文件描述符总是取系统当前可用的最小整数值。dup2和dup类似,不过它将返回第一个不小于fd2的整数值。两者在调用失败的时候返回-1 并设置errno。
注:通过dup和dup2创建的文件描述符并不继承原文件描述符的属性。例如close-on-exec和non-blocking等。

Linux服务器程序规范

服务器编程框架

单个服务器程序
I/O处理单元:处理客户连接,读写网络数据
逻辑单元:业务进程或线程
网络存储单元:本地数据库,文件或缓存
请求队列:各单元之间的通信方式
服务器集群
I/O处理单元:作为接入服务器,实现负载均衡
逻辑单元:逻辑服务器
网络存储单元:数据库服务器
请求队列:各服务器之间的永久TCP连接

I/O处理单元

服务器管理客户连接的模块。

职责

等待并接受新的客户连接,接受客户数据,将服务器响应返回给客户端。但是,数据的收发不一定在I/O处理单元中执行。也可能在逻辑单元中执行,具体在何处执行取决于事件处理模式。对于一个服务器集群来说,I/O处理单元是一个专门的接入服务器,它实现负载均衡,从所有的逻辑服务器中选取负荷最小的一台来为新客户服务。

逻辑单元

一个逻辑单元通常是一个进程或者线程。它分析并处理客户数据,然后将结果传递给I/O处理单元或者直接发送给客户端(具体使用哪种方式取决于事件处理模式)。对于服务器机群而言,一个逻辑单元本身就是一台逻辑服务器。服务器通常拥有多个逻辑单元。以实现对多个客户任务的并行处理。

网络存储单元

可以是数据库、缓存和文件。甚至是一台独立的服务器,但它并不是必须的。比如ssh,telent等登陆服务就不需要这个单元。

请求队列

是各单元之间的通信方式的抽象。I/O处理单元接收到客户请求时,需要以某种方式来通知一个逻辑单元来处理该请求。同样,多个逻辑单元同时访问一个存储单元时,也需要采用某种机制来协调处理竞态条件。请求队列通常被实现为池的一部分。对于服务机群而言,请求队列是个各台服务器之间预先建立的、静态的、永久的TCP连接

I/O模型

socket在创建的时候默认是阻塞的。可以通过给socket系统调用的第二个参数传递SOCK_NONBLOCK标志,或者通过fcntl系统调用的F_SETFL命令将其设置为非阻塞的。
阻塞I/O
阻塞的文件描述符。针对此类I/O执行的系统调用可能因为无法立即完成而被操作系统挂起。直到等待的事件发生为止。socket的基础API中,可能被阻塞的系统调用有:

  • accept
  • send
  • recv
  • connect
    非阻塞I/O
    非阻塞的文件描述符。针对此类I/O执行的系统调用总是立即返回。而不管事件是否已经发生。如果事件没有立即发生,系统调用也会返回。
    总结
    很显然,只有在事件已经发生的情况下操作非阻塞I/O(读、写等)才能提高程序的效率。因此非阻塞I/O通常需要和其他I/O机制一起使用。例如I/O复用和SIGIO信号。
I/O复用

应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。Linux上常用的I/O复用函数是 select、poll和epoll_wait。
注意:I/O复用函数本身是阻塞的,它们能提高程序效率的原因在于它们具有监听多个I/O事件的能力。
I/O事件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一路初心向前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值