Run [03.03.2020] con una sola instancia de proceso de realización del socket de Unix abstracto

En primer lugar, el problema de fondo

Muchas veces, tenemos que garantizar que el proceso es sólo una instancia en ejecución .

Hay varias maneras:

http://stackoverflow.com/questions/2964391/preventing-multiple-process-instances-on-linux

http://stackoverflow.com/questions/5339200/how-to-create-a-single-instance-application-in-c-or-c

https://github.com/qtproject/qt-solutions/tree/master/qtsingleapplication/src

enfoque más convencional es añadir una bandada bloqueo de archivos de documentos, como por ejemplo para el rebaño archivo pid (LOCK_EX | LOCK_NB)

Sin embargo, este método algunos inconvenientes:

  1. Si el archivo es mv o RM, se pasa por alto.
  2. Si un fallo en el disco como un disco completo, sin acceso de escritura en el directorio, se producirá un error.

二, espacio de nombres abstracto socket Unix

http://linux.die.net/man/7/unix

socket Unix Hay tres tipos:

  1. Basado en archivos
  2. socketpair creado anónima
  3. El espacio de nombres abstracto, específica de Linux

Bajo Linux, toma AF_UNIX soporta un especial
espacio de nombres abstracto socket Unix.

En comparación con el archivo de socket Unix basado en el sistema, espacio de nombres abstracto socket UNIX ordinaria:

  1. No hay ningún archivo de disco
  2. Después del proceso colgó borrado automáticamente, no hay archivos residuales
  3. Los archivos sin tener que preocuparse por los conflictos con el sistema de archivos, no se preocupan por la ruta absoluta en el sistema de archivos, si hay un problema

Lsof mirada al interior de los resultados, hay un fichero Tal algunos artículos similares @test_abstract_ns

El código también es muy simple, espacio de nombres abstracto UNIX zócalo antes de bind, sockaddr_un.sun_path [0] se puede configurar para 0x0.

En tercer lugar, el código

Por lo tanto I abstractos UNIX implementos herramienta socket SysSem una clase (un semáforo en todo el sistema),
para:

  1. De manera que sólo una instancia de un programa se inicia.
  2. Deje x y proceso para esperar a que el proceso de ejecución de la operación después de yyy, xxx para realizar la operación.

características:

  1. Multi-proceso / hilo de concurrencia de fallos.
  2. Cuando el proceso se lleva a cabo matanza libera automáticamente, el sistema operativo, no deja residuos.
  3. Ningún archivo de disco, ningún archivo se elimina accidentalmente una variedad de situaciones.
  4. No tome puerto TCP / UDP.
  5. Simple, menos de 60 líneas de código.

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include <algorithm>
#include <string>

//
// a semaphore with system scope.
//
// 1. no race conditions between Post() / GetValue() , better than flock().
// 2. when a running process be killed, automatically release all.
// 3. no file on disk, no accidently delete .
// 4. no tcp/udp socket, no confliction, no port consumption.
//
class SysSem {
public:
    SysSem() : _fd(-1) { memset(&_addr, 0, sizeof(_addr)); }
    ~SysSem();

    void Init(std::string id);

    bool Post();
    bool GetValue();

    const char* GetID() const;

private:
    struct sockaddr_un _addr;
    int _fd;
};

void SysSem::Init(std::string id) {
    _addr.sun_family = AF_UNIX;
    const size_t len = std::min(id.size(), sizeof(_addr.sun_path) - 2);  // 2 = start null and end null byte
    // abstract namespace socket address , _addr.sun_path[0] is a null byte ('\0')
    memcpy(_addr.sun_path + 1, id.c_str(), len);
    // memcpy(_addr.sun_path + 0, id.c_str(), len);
}

const char* SysSem::GetID() const { return &_addr.sun_path[1]; }

SysSem::~SysSem() {
    if (_fd >= 0) {
        ::close(_fd);
        _fd = -1;
    }
}

bool SysSem::Post() {
    _fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
    if (_fd < 0) {
        return false;
    }

    if ((0 != ::bind(_fd, (struct sockaddr*)&_addr, sizeof(_addr))) || (0 != listen(_fd, 65536))) {
        return false;
    }
    return true;
}

bool SysSem::GetValue() {
    const int clientFD = ::socket(AF_UNIX, SOCK_STREAM, 0);
    if (clientFD < 0) {
        return false;
    }
    const bool ret = (0 == ::connect(clientFD, (struct sockaddr*)&_addr, sizeof(_addr)));
    ::close(clientFD);
    return ret;
}

#include <assert.h>
#include <stdio.h>

int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: %s abstract-path post/get\n", argv[0]);
        exit(1);
    }

    SysSem inst;
    inst.Init(argv[1]);

    if (0 == strcasecmp(argv[2], "post")) {
        assert(inst.Post());
        SysSem check;
        check.Init(argv[1]);
        assert(check.GetValue());
        printf("ok, i am the only one under %s. running ...\n", inst.GetID());
        pause();

    } else if (0 == strcasecmp(argv[2], "get")) {
        assert(inst.GetValue());
        printf("a process is running under %s. \n", inst.GetID());
    } else {
        printf("unknown cmd \n");
    }

    return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/windydays/p/12536033.html
Recomendado
Clasificación