軟件多用戶管理,同一中端不允許重複登錄同一賬號。linux平臺基於flock實現該功能。首先,用戶登錄時,創建屬於該用戶的鎖文件並上鎖。當要重複登錄同一個賬號時,首先檢查該用戶的鎖文件是否存在,如果存在並且鎖文件處於鎖定狀態,那麼就判定用戶處於登錄狀態。廢話不多說,直接上測試代碼。
main.cpp(編譯命令g++ main.cpp -o test -lstdc++fs)
#include <experimental/filesystem>
#include <string>
#include <string.h>
#include <sys/fcntl.h>
#include <unistd.h>
using namespace std;
namespace filesystem = std::experimental::filesystem;
// 用戶數據鎖類
class UserDataLock
{
public:
UserDataLock(const string& lockFilename);
~UserDataLock();
private:
filesystem::path m_lockFilePath;// 用戶數據鎖文件路徑
struct lockFileDeleter
{
void operator()(FILE* fileHandle) const
{
if (fileHandle)
{
fclose(fileHandle);
}
}
};
std::unique_ptr<FILE, lockFileDeleter> m_lockFileHandle;// 用戶數據鎖文件句柄
};
UserDataLock::UserDataLock(const string& lockFilename)
: m_lockFilePath(lockFilename)
{
if (filesystem::exists(m_lockFilePath))
{
throw std::runtime_error("a lock file exists");// 鎖文件存在
}
m_lockFileHandle.reset(fopen(m_lockFilePath.string().c_str(), "wb"));
if (!m_lockFileHandle)
{
throw std::runtime_error("create lock file failed");// 創建鎖文件失敗
}
const char* content = "File Lock";
fwrite(content, strlen(content), 1, m_lockFileHandle.get());
fflush(m_lockFileHandle.get());// 向鎖文件寫入"File Lock"
// 嘗試鎖住整個文件,給文件上鎖
struct flock lock = {};
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = getpid();
if (fcntl(fileno(m_lockFileHandle.get()), F_SETLK, &lock) == -1) {//上鎖失敗
throw std::runtime_error("lock lock file failed");
}
}
UserDataLock::~UserDataLock()
{
try
{
// 釋放鎖
struct flock lock = {};
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = getpid();
fcntl(fileno(m_lockFileHandle.get()), F_SETLK, &lock);
m_lockFileHandle.reset();
filesystem::remove(m_lockFilePath);
}
catch (const filesystem::filesystem_error&)
{
}
}
//獲取用戶數據鎖
std::unique_ptr<UserDataLock> AcquireUserDataLock(const string& strlockFilename)
{
filesystem::path lockFilename = strlockFilename;
try
{
if (filesystem::exists(lockFilename))
{
int fd = open(lockFilename.string().c_str(), O_RDWR);
if (fd == -1) {
throw std::runtime_error("can not open lock file");
}
// 嘗試鎖住整個文件,linux平臺刪除已打開文件不會拋出異常,先嚐試給文件上鎖
struct flock lock = {};
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = getpid();
if (fcntl(fd, F_SETLK, &lock) == -1) {//上鎖失敗
close(fd);
throw std::runtime_error("a lock file exists");
}
// 釋放鎖
lock.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &lock) == -1) {
close(fd);
throw std::runtime_error("lock file release lock fail");
}
close(fd);
}
auto pLock = std::unique_ptr<UserDataLock>(new UserDataLock(lockFilename.string()));
return pLock;
}
catch (const filesystem::filesystem_error& e)
{
return nullptr;
}
catch (const std::runtime_error& e)
{
return nullptr;
}
}
int main()
{
std::string lockfilepath = "/tmp/a.lock";
UserDataLock userlock(lockfilepath);//創建一個用戶鎖,此時處於登錄狀態
auto pUserDataLock = AcquireUserDataLock(lockfilepath);
if(pUserDataLock == nullptr)//獲取用戶數據鎖失敗,說明此時處於登錄狀態
{
printf("用戶數據鎖存在\n");
}
return 0;
}
執行結果如下: