软件多用户管理,同一中端不允许重复登录同一账号。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;
}
执行结果如下: