Linux学习之守护进程1

一、相关概念

QQ邮箱关于三种协议的解释:SMTP/IMAP服务

1.SMTP协议

SMTP(​​Simple Mail Transfer Protocol​​,简单邮件传输协议)是一种用于发送电子邮件的互联网标准。它在TCP/IP协议族中,通常使用25端口进行通信。SMTP协议允许邮件发送者和接收者之间的邮件传输,并且可以通过中继器或网关实现不同网络之间的邮件传输。SMTP的一个重要特性是它能够跨越网络传输邮件,这被称为“SMTP邮件中继”。

2.POP3协议

POP3 (Post Office Protocol - Version 3)协议用于支持使用电子邮件客户端获取并删除在服务器上的电子邮件。

POP允许电子邮件客户端下载服务器上的邮件,但是你在电子邮件客户端上的操作(如:移动邮件、标记已读等)不会反馈到服务器上的,比如:你通过电子邮件客户端收取了QQ邮箱中的3封邮件并移动到了其他文件夹,这些移动动作是不会反馈到服务器上的,也就是说,QQ邮箱服务器上的这些邮件是没有同时被移动的。需要特别注意的是,第三方客户端通过POP收取邮件时,也是有可能同步删除服务端邮件。

3.IMAP协议

IMAP(Internet Message Access Protocol,互联网邮件访问协议)是一个应用层协议,用于从本地邮件客户端(如Microsoft Outlook、Outlook Express、Foxmail、Mozilla Thunderbird)访问远程服务器上的邮件。

在IMAP协议上,电子邮件客户端的操作都会反馈到服务器上,你对邮件进行的操作(如:移动邮件、标记已读、删除邮件等)服务器上的邮件也会做相应的动作。也就是说,IMAP 是“双向”的。

4.守护进程

守护进程是后台运行的无终端关联的系统进程,常在启动时启动,提供持续服务,如网络服务、日志记录和定时任务。其特点包括脱离终端、后台运行、持久服务、资源管理和错误处理。创建守护进程涉及重定向文件描述符、创建新会话、改变工作目录等步骤。`ps` 和 `top` 命令用于查看守护进程,前者提供进程快照,后者显示实时资源使用情况。

二、实践

1.telnet登录QQ发送邮件

打开PowerShell,输入下面命令打开telnet

telnet smtp.qq.com 587

如果无法识别telnet,打开控制面板,点击卸载程序,点击左侧的 ​​“启用或关闭 Windows 功能”

找到 ​​“Telnet 客户端”​​,勾选它,然后点击​​确定

等待安装完成,重新打开 ​​PowerShell​​ 或 ​​CMD

按照以下步骤发送邮件

telnet smtp.qq.com 587 (qq邮箱说明:http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=369)

Ehlo qq.com (打招呼)
STARTTLS (开启加密)

auth login (输入登陆命令)

//输入邮箱账号(Base64形式)(回车)
//输入邮箱授权码(Base64形式)(回车)

235 Authentication successful(提示登陆成功)
Mail from:XXXX@qq.com (注意冒号后面别有空格)
250 Ok
Rcpt to:XXX@qq.com (注意冒号后面别有空格)
250 Ok

DATA (输入此命令开始写信)

FROM:XXX@qq.com
TO:XXX@qq.com

SUBJECT:

(空一行)

内容

. (“.”结束)
quit

2.守护进程实现

(1)阿里云守护进程

首先登录QQ邮箱,点击左下方账号与安全中心,点击安全设置,点击生成授权码

在代码中需要用到你的qq邮箱地址(账号@qq.com)和授权码的base64形式,可到此处转换:https://base64.us/

进入在linux系统,输入以下命令,创建.c文件

vim smtp_daemon.c

守护进程代码如下(C语言):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define SMTP_SERVER "smtp.qq.com"
#define SMTP_PORT 465               // 使用SSL加密端口
#define EMAIL_FROM "你的qq邮箱地址"
#define EMAIL_PASS "邮箱密码或授权码" // 确认这是最新的授权码
#define EMAIL_TO "实际接收邮箱"

SSL_CTX* init_ssl() {
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
    return SSL_CTX_new(SSLv23_client_method());
}

void send_email() {
    SSL_CTX* ctx = init_ssl();
    int sockfd;
    struct hostent *server;
    struct sockaddr_in serv_addr;
    char buffer[1024];
    
    // 创建socket连接
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    server = gethostbyname(SMTP_SERVER);
    
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SMTP_PORT);
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
    
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection failed");
        return;
    }

    // SSL握手
    SSL* ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    if (SSL_connect(ssl) <= 0) {
        ERR_print_errors_fp(stderr);
        return;
    }

    // SMTP协议交互
    SSL_read(ssl, buffer, sizeof(buffer)); // 读取欢迎消息
    
    sprintf(buffer, "EHLO localhost\r\n");
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    sprintf(buffer, "AUTH LOGIN\r\n");
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    // 发送base64编码
    sprintf(buffer, "实际base64编码\r\n");
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    sprintf(buffer, "实际base64编码\r\n");
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    // 设置发件人和收件人
    sprintf(buffer, "MAIL FROM:<%s>\r\n", EMAIL_FROM);
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    sprintf(buffer, "RCPT TO:<%s>\r\n", EMAIL_TO);
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    // 发送邮件内容
    sprintf(buffer, "DATA\r\n");
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    time_t now;
    time(&now);
    sprintf(buffer, 
           "From: <%s>\r\n"
           "To: <%s>\r\n"
           "Subject: 守护进程状态\r\n"
           "\r\n"
           "守护进程正在运行中....\r\n"
           "当前时间: %s\r\n"
           ".\r\n", 
           EMAIL_FROM, EMAIL_TO, ctime(&now));
    SSL_write(ssl, buffer, strlen(buffer));
    SSL_read(ssl, buffer, sizeof(buffer));
    
    sprintf(buffer, "QUIT\r\n");
    SSL_write(ssl, buffer, strlen(buffer));
    
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
}

void daemonize() {
    pid_t pid = fork();
    if (pid < 0) exit(1);
    if (pid > 0) exit(0);
    
    setsid();
    chdir("/");
    umask(0);
    
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
}

int main() {
    daemonize();
    
    while(1) {
        send_email();
        sleep(60);
    }
    
    return 0;
}

其中邮箱地址以及授权码内容替换为你自己的

编译此文件

gcc smtp_daemon.c -o smtp_daemon -lssl -lcrypto

运行守护程序:

./smtp_daemon

运行结果如下图:

 停止命令:

pkill -f smtp_daemon
(2)树莓派守护进程 

登录树莓派,创建serial_daemon.c文件,代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <signal.h>

#define SERIAL_PORT "/dev/serial0"  // 树莓派默认串口设备
#define BAUD_RATE B115200           // 波特率115200
#define MESSAGE "守护进程正在运行中....\r\n"
#define INTERVAL 10                 // 间隔10秒

int serial_fd = -1;

// 初始化串口
int init_serial() {
    serial_fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
    if (serial_fd == -1) {
        perror("无法打开串口");
        return -1;
    }
    
    struct termios options;
    tcgetattr(serial_fd, &options);
    
    // 设置波特率
    cfsetispeed(&options, BAUD_RATE);
    cfsetospeed(&options, BAUD_RATE);
    
    // 8N1配置
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    
    // 禁用硬件流控
    options.c_cflag &= ~CRTSCTS;
    
    // 启用接收
    options.c_cflag |= CREAD | CLOCAL;
    
    // 禁用软件流控
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    
    // 原始输入模式
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    // 原始输出模式
    options.c_oflag &= ~OPOST;
    
    // 设置超时
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 10;
    
    tcsetattr(serial_fd, TCSANOW, &options);
    
    return 0;
}

// 信号处理函数
void signal_handler(int sig) {
    if (serial_fd != -1) {
        close(serial_fd);
    }
    exit(0);
}

// 守护进程化
void daemonize() {
    pid_t pid = fork();
    
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }
    
    if (pid > 0) {
        exit(EXIT_SUCCESS); // 父进程退出
    }
    
    // 子进程继续
    if (setsid() < 0) {
        exit(EXIT_FAILURE);
    }
    
    // 忽略终端I/O信号
    signal(SIGTTOU, SIG_IGN);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGTSTP, SIG_IGN);
    signal(SIGHUP, SIG_IGN);
    
    // 再次fork确保不是会话组长
    pid = fork();
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }
    
    if (pid > 0) {
        exit(EXIT_SUCCESS); // 父进程退出
    }
    
    // 设置文件权限掩码
    umask(0);
    
    // 更改工作目录
    chdir("/");
    
    // 关闭所有打开的文件描述符
    for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
        close(x);
    }
}

int main() {
    // 注册信号处理
    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);
    
    // 守护进程化
    daemonize();
    
    // 初始化串口
    if (init_serial() < 0) {
        return -1;
    }
    
    // 主循环
    while (1) {
        write(serial_fd, MESSAGE, strlen(MESSAGE));
        sleep(INTERVAL);
    }
    
    close(serial_fd);
    return 0;
}

 Ctrl+O->Enter-> Ctrl+X保存并退出

编译程序:

gcc serial_daemon.c -o serial_daemon

运行守护进程:

sudo ./serial_daemon

结果如下:

PS:串口配置波特率为115200,接受模式为文本模式,文本编码为UTF-8,不然可能会乱码

 三、总结

本次学习了如何使用telnet登录QQ发送邮件,这一步除了挺多的错,找了一些博客看其中的方法也不行,老是断连。参考文章为Email-FTP-RTSP协议实践研究_rtp邮箱-CSDN博客,还有阿里云上编写一个守护进程程序以及树莓派守护进程,都是问的deepseek,不对的话多问几次就对了。重点是我第一次发现代码可以直接在Putty上粘贴!!!!!(复制之后在Putty端右键点击就粘贴上去了),那我一个一个敲了那么多周算什么???命比苦瓜还苦。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值