目录
一.守护进程
1.1进程组与会画
1.2守护进程
二.创建守护进程
setsid函数:
三. TCP通讯流程
3.1三次握手:
3.2 数据传输的过程
3.3四次挥手
一.守护进程
1.1进程组与会画
进程组:进程组由一个进程或者多个进程组成,每个进程组有唯一的进程组ID,每个进程组有一个进程组组长(和进程组ID一样)。
会话:有一个或者多个进程组组成的集合,一个会话的几个进程组可以分为前台进程和后台进程。在任何时候必须只有一个前台进程组,
只能有一个前台,此时bash在后台运行,不能进行命令行解释。
所有会话内的进程fork创建的子进程,一般都属于当前会话。
1.2守护进程
守护进程也叫精灵进程,是一种特殊的进程,一般在后台运行,不与任何控制终端相关联,并且周期性地执行某种任务或等待处理某些发生的事件(处理一些系统级的任务)。守护进程通常在系统启动时就运行,它们以 root 用户或者其他特殊的用户运行。
特点:
- 生存周期长[不是必须]:一般是操作系统启动的时候他启动,操作系统关闭的时候他也关闭
- 守护进程和终端没有关联,也就是说他们没有控制终端,所以你控制终端退出也不会导致守护进程退出
- 守护进程是在后台运行不会占着终端,终端可以执行其它命令
二.创建守护进程
setsid函数:
#include <unistd.h>
pid_t setsid(void);
解释:
创建一个新会话,谁调用这个函数,谁就成为这个新会话进程组的组长返回值
成功返回进程ID,失败返回-1,且错误码被设置
注意:进程组组长不能调用
补充:因为进程组长不能调佣该函数,所以该进程都要fork创建子进程,让子进程创建新会话。
守护进程的一般流程:
在父进程中先 fork()——再退出父进程 。(必做)
调用 setsid()——创建新会话 。(必做)
再次 fork 退出父进程。
调用 chdir(“/”) ——将当前工作目录修改到根目录 。
调用 umask()——清除掩码。
关闭所有不使用的文件描述符。
如果有产生子进程需要处理僵尸进程
代码演示:
void daemonize()
{
int fd = 0;
// 1. 忽略SIGPIPE
signal(SIGPIPE, SIG_IGN);
// 2. 让子进程成为进程组组长
if (fork() > 0)
exit(1);
// 3. 设置自己是一个独立的会话
setsid();
// 4. 重定向0,1,2,此时fd是3,并且打开黑洞文件
if ((fd = open("/dev/null", O_RDWR)) != -1)
{
dup2(fd, STDIN_FILENO);//0
dup2(fd, STDOUT_FILENO);//1
dup2(fd, STDERR_FILENO);//2
// 5. 关闭掉不需要的fd,此时完成重定向
if(fd > STDERR_FILENO) close(fd);
}
}
int main(int argc, char *argv[])
{
if (argc != 2 && argc != 3)
{
std::cerr << "Usage:\n\t" << argv[0] << " port ip" << std::endl;
std::cerr << "example:\n\t" << argv[0] << " 8080 127.0.0.1 \n"
<< std::endl;
exit(-3);
}
std::string ip;
uint16_t port = atoi(argv[1]);
if (argc == 3)
ip = argv[2];
daemonize();//创建新会话
ServerTcp *T = new ServerTcp(port, ip);
T->init();
T->start();
return 0;
}
结果:
三. TCP通讯流程
3.1三次握手:
服务器初始化:
调用socket,创建文件描述符。
调用bind,将当前的文件描述符和IP/PORT进行绑定。
调用listen,声明当前这个文件描述符作为一个服务器的文件描述符,为后面的accept做好准备。
调用accept,并阻塞,等待客户端连接到来。
建立连接
调用socket,创建文件描述符。
调用connect,向服务器发起连接请求。
connect会发出SYN段并阻塞等待服务器应答(第一次)。
服务器收到客户端的SYN,会应答一个SYN-ACK段表示“同意建立连接”(第二次)。
客户端收到SYN-ACK后会从connect返回,同时应答一个ACK段"时间"(第三次)。
这个建立连接的过程叫三次握手
3.2 数据传输的过程
建立连接后,TCP协议提供全双工的通信服务,所谓全双工的意思是,在同一条连接中,同一时刻,通信双方可以同时写数据,相对的概念叫做半双工,同一条连接在同一时刻,只能由一方来写数据。
服务器从accept返回后立刻调用read,读socket就像读管道一样,如果没有数据到达就阻塞等待。
这时客户端调用write发送请求给服务器,服务器收到后从read返回,对客户端的请求进行处理,在此期间客户端调用read阻塞等待服务器端应答。
服务器调用write将处理的结果发回给客户端,再次调用read阻塞等待下一条请求。
客户端收到后从read返回,发送下一条请求,如此循环下去。
3.3四次挥手
服务器和客户端close的过程
断开连接的过程:
如果客户端没有更多的请求了,就调用close关闭连接,客户端会向服务器发送FIN段(第一次)。
此时服务器收到FIN后,会回应一个ACK,同时read会返回0(第二次)。
read返回之后,服务器就知道客户端关闭了连接,也调用close关闭连接,这个时候服务器会向客户端发送一个FIN(第三次)。
客户端收到FIN,再返回一个ACK给服务器(第四次)。
后面在学习网络原理时,会对这握手挥手内容进行详细的说明。