Starting a Service

博客介绍了启动服务的方法,通过打开已安装数据库的句柄,在调用StartService函数时指定该句柄来启动服务。启动后,程序利用QueryServiceStatusEx函数返回的SERVICE_STATUS_PROCESS结构成员跟踪服务进度,该函数需服务控制管理器数据库的句柄。

Starting a Service

To start a service, the following example opens a handle to an installed database and then specifies the handle in a call to the StartService function. It can be used to start either a service or a driver service, but this example assumes that a service is being started. After starting the service, the program uses the members of the SERVICE_STATUS_PROCESS structure returned by the QueryServiceStatusEx function to track the progress of the service.

The function requires a handle to a service control manager database. For more information, see Opening an SCManager Database.

#include <windows.h>
#include <stdio.h>

BOOL StartSampleService(SC_HANDLE schSCManager) 
{ 
    SC_HANDLE schService;
    SERVICE_STATUS_PROCESS ssStatus; 
    DWORD dwOldCheckPoint; 
    DWORD dwStartTickCount;
    DWORD dwWaitTime;
    DWORD dwBytesNeeded;
 
    schService = OpenService( 
        schSCManager,          // SCM database 
        "Sample_Srv",          // service name
        SERVICE_ALL_ACCESS); 
 
    if (schService == NULL) 
    { 
        return 0; 
    }
 
    if (!StartService(
            schService,  // handle to service 
            0,           // number of arguments 
            NULL) )      // no arguments 
    {
        return 0; 
    }
    else 
    {
        printf("Service start pending./n"); 
    }
 
    // Check the status until the service is no longer start pending. 
 
    if (!QueryServiceStatusEx( 
            schService,             // handle to service 
            SC_STATUS_PROCESS_INFO, // info level
            &ssStatus,              // address of structure
            sizeof(SERVICE_STATUS_PROCESS), // size of structure
            &dwBytesNeeded ) )              // if buffer too small
    {
        return 0; 
    }
 
    // Save the tick count and initial checkpoint.

    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = ssStatus.dwCheckPoint;

    while (ssStatus.dwCurrentState == SERVICE_START_PENDING) 
    { 
        // Do not wait longer than the wait hint. A good interval is 
        // one tenth the wait hint, but no less than 1 second and no 
        // more than 10 seconds. 
 
        dwWaitTime = ssStatus.dwWaitHint / 10;

        if( dwWaitTime < 1000 )
            dwWaitTime = 1000;
        else if ( dwWaitTime > 10000 )
            dwWaitTime = 10000;

        Sleep( dwWaitTime );

        // Check the status again. 
 
    if (!QueryServiceStatusEx( 
            schService,             // handle to service 
            SC_STATUS_PROCESS_INFO, // info level
            &ssStatus,              // address of structure
            sizeof(SERVICE_STATUS_PROCESS), // size of structure
            &dwBytesNeeded ) )              // if buffer too small
            break; 
 
        if ( ssStatus.dwCheckPoint > dwOldCheckPoint )
        {
            // The service is making progress.

            dwStartTickCount = GetTickCount();
            dwOldCheckPoint = ssStatus.dwCheckPoint;
        }
        else
        {
            if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
            {
                // No progress made within the wait hint
                break;
            }
        }
    } 

    CloseServiceHandle(schService); 

    if (ssStatus.dwCurrentState == SERVICE_RUNNING) 
    {
        printf("StartService SUCCESS./n"); 
        return 1;
    }
    else 
    { 
        printf("/nService not started. /n");
        printf("  Current State: %d/n", ssStatus.dwCurrentState); 
        printf("  Exit Code: %d/n", ssStatus.dwWin32ExitCode); 
        printf("  Service Specific Exit Code: %d/n", 
            ssStatus.dwServiceSpecificExitCode); 
        printf("  Check Point: %d/n", ssStatus.dwCheckPoint); 
        printf("  Wait Hint: %d/n", ssStatus.dwWaitHint); 
        return 0;
    } 
}
以下是整合 **自动恢复服务** 的完整脚本,包含文件传输、MD5校验、服务状态监控及自动重启功能,适用于生产环境部署: --- ### **完整脚本(含恢复服务)** ```bash #!/bin/bash # ===== 配置参数 ===== USER_NAME="nvidia" USER_PASSWD="your_password_here" # 建议从环境变量读取 USER_IP="10.100.51.119" DISK_MOUNT="/opt/production" HIDE_MOUNT=".os_recovery" IMG_FILE="/path/to/local/recovery.img" REMOTE_TARGET="${DISK_MOUNT}/${HIDE_MOUNT}/" SERVICE_NAME="recovery_service" # 远程需存在的服务名 MAX_RETRIES=3 # 最大重试次数 RETRY_DELAY=10 # 重试间隔(秒) # ===== 检查本地文件 ===== [ -f "$IMG_FILE" ] || { echo "Error: Local image file missing" >&2; exit 1; } # ===== 计算本地MD5 ===== LOCAL_MD5=$(md5sum "$IMG_FILE" | awk '{print $1}') || exit 1 echo "Local MD5: $LOCAL_MD5" # ===== 传输文件(带重试机制) ===== echo "Starting rsync transfer..." for ((i=1; i<=$MAX_RETRIES; i++)); do sshpass -p "$USER_PASSWD" rsync -avzP --progress "$IMG_FILE" "${USER_NAME}@${USER_IP}:${REMOTE_TARGET}" && break [ $i -eq $MAX_RETRIES ] && { echo "Error: rsync failed after $MAX_RETRIES attempts" >&2; exit 1; } echo "Retry $i/$MAX_RETRIES in $RETRY_DELAY seconds..." sleep $RETRY_DELAY done # ===== 验证远程文件 ===== REMOTE_FILE="${REMOTE_TARGET}$(basename "$IMG_FILE")" for ((i=1; i<=$MAX_RETRIES; i++)); do REMOTE_MD5=$(sshpass -p "$USER_PASSWD" ssh "${USER_NAME}@${USER_IP}" \ "md5sum \"$REMOTE_FILE\" 2>/dev/null" | awk '{print $1}') && break [ $i -eq $MAX_RETRIES ] && { echo "Error: Failed to verify remote MD5" >&2; exit 1; } sleep $RETRY_DELAY done # ===== MD5校验 ===== [ "$LOCAL_MD5" = "$REMOTE_MD5" ] || { echo "Error: MD5 checksum mismatch!" >&2 echo "Local: $LOCAL_MD5" echo "Remote: $REMOTE_MD5" exit 1 } echo "MD5 verification: SUCCESS" # ===== 远程服务恢复逻辑 ===== echo "Executing recovery service..." RECOVERY_CMD=$(cat <<EOF # 检查服务状态 if systemctl is-active --quiet "$SERVICE_NAME"; then echo "Service is running, attempting restart..." systemctl restart "$SERVICE_NAME" || { echo "Error: Failed to restart service" >&2 exit 1 } else echo "Service is stopped, starting..." systemctl start "$SERVICE_NAME" || { echo "Error: Failed to start service" >&2 exit 1 } fi # 验证服务状态 if systemctl is-active --quiet "$SERVICE_NAME"; then echo "Recovery service status: ACTIVE" else echo "Error: Service is not running after recovery" >&2 exit 1 fi EOF ) # ===== 执行远程命令(带重试) ===== for ((i=1; i<=$MAX_RETRIES; i++)); do sshpass -p "$USER_PASSWD" ssh "${USER_NAME}@${USER_IP}" "$RECOVERY_CMD" && break [ $i -eq $MAX_RETRIES ] && { echo "Error: Recovery service failed after $MAX_RETRIES attempts" >&2; exit 1; } sleep $RETRY_DELAY done echo "Recovery process completed successfully!" ``` --- ### **核心功能说明** 1. **传输可靠性**: - 添加 `MAX_RETRIES` 和 `RETRY_DELAY` 实现传输失败自动重试 - 每次重试间隔可配置(默认10秒) 2. **服务恢复机制**: - 自动检测服务状态(`systemctl is-active`) - 根据状态执行 `start` 或 `restart` - 最终验证服务是否真正运行 3. **安全增强**: - 所有远程命令通过 `sshpass` 非交互执行 - 关键步骤添加严格错误检查 --- ### **远程服务配置要求** 1. **服务文件示例**(`/etc/systemd/system/recovery_service.service`): ```ini [Unit] Description=Recovery Image Service After=network.target [Service] Type=simple User=nvidia WorkingDirectory=/opt/production/.os_recovery ExecStart=/usr/bin/python3 /opt/production/.os_recovery/recovery_daemon.py Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` 2. **服务依赖**: - 确保远程主机已安装: ```bash sudo apt install systemd # Debian/Ubuntu sudo systemctl daemon-reload sudo systemctl enable recovery_service ``` --- ### **高级优化方案** #### 1. 使用 `systemd` 路径触发(推荐) ```ini # 在服务文件中添加 Path 单元 [Unit] Description=Recovery Image Monitor [Path] PathModified=/opt/production/.os_recovery/recovery.img Unit=recovery_service.service [Install] WantedBy=multi-user.target ``` #### 2. 添加邮件报警 ```bash # 在脚本失败时发送邮件 send_alert() { echo "$1" | mail -s "Recovery Service Alert" admin@example.com } # 使用示例 trap 'send_alert "Script failed at line $LINENO"' ERR ``` #### 3. 日志集中管理 ```bash # 远程日志配置 ssh user@host "sudo tee /etc/rsyslog.d/recovery.conf <<EOF /var/log/recovery.log { daily rotate 7 compress missingok } EOF" ``` --- ### **常见问题解决** #### 问题1:服务启动失败 - **检查步骤**: ```bash # 查看服务日志 journalctl -u recovery_service -f # 检查依赖项 ldd /path/to/recovery_binary ``` #### 问题2:SSH 连接不稳定 - **优化方案**: ```bash # 在 ~/.ssh/config 中添加 Host 10.100.51.119 ServerAliveInterval 60 ConnectTimeout 10 ``` #### 问题3:文件权限问题 - **修复命令**: ```bash ssh user@host "sudo chown -R nvidia:nvidia /opt/production/.os_recovery && \ sudo chmod -R 755 /opt/production/.os_recovery" ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值