【牛客网C++服务器项目学习】Day16-主程序的编写

项目学习地址:【牛客网C++服务器项目学习】

day16

  1. Linux的信号机制及其使用方式

信号是什么?信号是Linux中一种古老的消息通知机制。其主要的作用是告知进程有一个事件结束了。是一种在软件层面对中断的模拟。

信号的产生,可分为硬件产生和软件产生。硬件信号不是我们关注的重点,有Ctrl+c触发SIGINT信号,实现终止进程的功能;软件上的产生可以通过kill函数/命令、alarm闹钟函数、abort函数(功能不清楚)

重点应该是在【信号注册】上。

signal函数

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

signal函数中,有两个形参,分别代表需要处理的信号编号值和处理信号函数的指针。它主要是用于前32种非实时信号的处理,不支持信号的传递信息。但是由于使用简单,易于理解,因此在许多场合被程序员使用。

函数返回值:成功返回先前的信号处理函数指针,出错则返回SIG_ERR(-1)

sigaction函数

  1. 项目开发的规范组织方式
项目开发之【文件夹】命名规范


// 代码相关
src 		- 源代码
__test__ 	- 测试文件
lib			- 库文件
core		- 核心文件
demo		- 示例
// 文档、资源相关
docs		- 文档
images		- 图片
misc		- 杂项,miscellaneous的缩写

// 其他
bin			- 命令脚本
  1. EPOLL的两种模式——ET和LT模式

所谓的ET边缘触发模式和LT水平触发模式,并没有那么神秘,其主要的内容如下:

    • 边缘触发模式ET:使用该模式时,当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你。
      • 所以,在使用ET模式的时候,为了保证数据都能被读取,一般要搭配【while】循环去读取数据。同时,为了不让读取函数在没有数据可以读时,阻塞住当前进程/线程,一般要将read/write函数设置为非阻塞模式,也即O_NONBLOCK
      • 为什么在ET模式具有缺点的情况下,还在强调ET模式的读写,这是因为ET模式一般情况下会比LT模式效率更高。这是因为ET模式避免了多次调用epollwit函数,可以避免epoll上的资源消耗,从而提高了执行效率。
    • 水平触发模式LT:使用该模式时,当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,会继续通知你去处理未完成的读写事件。
  1. setsockopt函数
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

做【端口复用】的。这个函数可以让相同地址的主机使用同一个端口。如果服务器因为断电意外退出,此时服务器一端在与客户端的TCP连接中会处于【FIN_WAIT_2】状态,此时立马再次启动服务器的话,【bind】函数也许会失败。所以我们使用这个函数,让sockfd对应的服务端程序能够重复使用这个端口号。

  1. epoll_ctl函数的参数宏EPOLLRDHUP,EPOLLONESHOT

EPOLLRDHUP (since Linux 2.6.17)

​ Stream socket peer closed connection, or shut down writing half of connection. (This flag is especially

​ useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.)

这是在Linux2.6.17之后新加入的一个特性。在之前的版本中,epoll监听的socket对端如果调用close主动关闭连接,epoll在这条连接上会检测到一个EPOLLIN事件,并交给上层程序去执行读。但是读一个关闭了写入端的socket通信来说,调用read函数会返回一个错误号。一般情况下我们是通过if( read(fd, readbuff, sizeof(readbuff) < 0)来判断read函数调用是否会发生错误

为了进一步提高程序的效率,我们可以在底层就将对端关闭连接这种情况处理了,所以自Linux2.6.17之后新加入了一个EPOLLRDHUP 宏,通过将epoll事件设置为event.events = EPOLLIN | EPOLLRDHUP便能在底层进行处理

EPOLLONESHOT:设置EPOLLONESHOT可以保证一个socket只能被一个线程占用,避免了多个线程收到了一个socket在前后时间发来的不同数据,造成数据混乱,程序运行出错的情况。EPOLLONESHOT的作用是对加入到epollfd中的socket,该socket日后接收到数据后,只会响应一次,无论日后有多少数据再次发来,在epoll_wait中都不再对这个socket作出响应,也就避免了其他线程会获取到这个socket上的数据。

  1. extern关键字

在【牛客网-高老师】的视频中我们可以看到,对epoll的几个包装函数,采用了在main.cpp中通过extern关键字进行声明,在http_conn.cpp中进行定义的操作。extern的功能就是声明一个变量或者函数,声明之后在其他源文件中进行定义,只要在主程序中包含了相应的源文件,就不怕编译器在编译的时候找不到。

为什么要这么做?我猜测是【高老师】懒得重新写一个头文件,一种偷懒的方式。

你可能感兴趣的:(服务器项目学习,服务器,c++,linux,网络,后端)