linux平台基于文件锁实现用户数据锁(基于文件锁判断用户是否处于登录状态)

2 篇文章 0 订阅
1 篇文章 0 订阅

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

执行结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值