防止程序二次启动

本文探讨了防止程序重复启动的方法,包括跨平台通用方法和特定于Linux及Windows平台的技术方案,并提出了一种新颖的端口绑定策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在编写应用程序的过程中,通常会遇到这样的情况,因为某些原因,程序被系统多次或者反复调用,导致程序耗尽系统内存或者出现不可预知的错误,最终影响到程序原本的设计需求,这显然不是我们所希望看到的结果,但是如果在程序内部加上必要的判断,不管系统是否多次调用,都能防止同一时刻多个同样的程序同时运行。    

网络上防止程序二次启动的方法大同小异,最常见的便是程序启动时先检测指定文件是否存在,如果不存在则创建一个文件,退出时删除该文件,否则认为该程序已启动,直接退出。但是这样做有一个潜在的问题,万一程序在退出前崩溃了,指定文件还未来得及删除,则程序将无法再次启动。另外一个问题是,有些特定文件系统是只读属性的,压根就无法创建文件,所以这一方案也不可行。

上面那种办法虽然存在一定限制以及潜在的缺陷,但至少是支持大多数平台的,对于跨平台的程序而言比较有优势。如果程序只运行在特定平台,我们也可以使用各平台特有的办法实现。

Linux平台下,我们可以调用popen函数执行ps命令,结合awk、grep跟wc命令统计当前进程中与当前程序名字相同的进程数量,即执行“ps x | awk ‘{print $5}’ | grep “当前程序名” | wc -l”,看得到的结果是否大于1,倘若大于1则说明在当前程序启动以前已经启动过同样的程序了,当前程序作退出处理。这种方法的存在的隐患也很大,必须确保没有同名或名字相似的其他程序存在,也不允许该程序有多种命名方式,否则判断结果将出现误差。

#include <sys/types.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <string.h>  
  
int main(int argc, char *argv[])  
{  
    int i = 0;  
    FILE *stream;  
    char recvBuf[256] = {0};  
    char cmdBuf[256] = {0};  
  
    sprintf(cmdBuf, "ps x | awk '{print $5}' | grep %s | wc -l", argv[0]);  
    stream = popen(cmdBuf, "r");  
    fread(recvBuf, sizeof(char), sizeof(recvBuf)-1, stream);  
    pclose(stream);  
  
    if (atoi(recvBuf) > 1)  
    {  
        printf("The number of programs: %s\n", recvBuf);  
        printf("The program %s already exist, so exit!\n", argv[0]);  
        exit(1);  
    }  
  
    //sleep for test  
    while(1) sleep(10);  
  
    return 0;  
}  
Windows平台下,大多程序都用CreateMutex方式来限制多开。使用API函数CreateMutex来创建命名互斥对象来实现程序互斥是一个比较通用的方法。对于界面程序,我们可以在IninInstance()函数加入互斥对象,对于后台或者控制台程序,我们可以在main()开始的部分加入互斥对象。

#include <Windows.h>  
  
int main(int argc, char* argv[])  
{  
    HANDLE hMutex = ::CreateMutex(NULL, FALSE, “MYCOMPANY MYAPP.EXE”);  
    if( (GetLastError() == ERROR_ALREADY_EXISTS) ||  
    (GetLastError() == ERROR_ACCESS_DENIED) )  
    {  
        CloseHanle( hMutex );  
        printf(“程序已经运行!系统不允许重复运行!\n”);  
        return FALSE;  
    }  
  
    // main code here  
  
    return 0;  
}  
   
以上是网上广为传播的两类最普遍的解决程序多重启动的方法,都在不同程度上存在一定的局限跟隐患。本人想到了一种几乎兼容所有平台且方便使用的方法,那就是在程序启动以后,开始真正的任务之前,先尝试绑定一个系统端口,如果绑定成功,则继续执行其他主要任务,否则端口被其他程序绑定,说明已经有一个同样的程序正在执行,当前程序作退出处理。这样做的坏处是浪费了一个端口,不过这对于大多数业务来说是值得的。需要注意的是,端口默认无法复用,不能人为地设置端口复用,而且该端口应该尽可能取得生僻,以确保不会恰巧被其他程序所占用。
以Linux平台下C语言实现为例,其他平台代码大同小异:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <errno.h>  
  
int main(void)  
{  
    int fd;  
    struct sockaddr_in addr;  
  
    fd = socket(PF_INET, SOCK_STREAM, 0);  
    if (fd < 0)  
    {  
        perror("socket");  
        return -1;  
    }  
  
    memset(&addr, 0, sizeof(addr));  
    addr.sin_family = PF_INET;  
    addr.sin_port = htons(1987);  
    addr.sin_addr.s_addr = INADDR_ANY;  
  
    if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0)  
    {  
        perror("bind");  
        printf("The program already exist, so exit!\n");  
        close(fd);  
        exit(1);  
    }  
    else  
    {  
        while (1) sleep(10);  
    }  
  
    return 0;  
}   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值