国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C/C++輕量級(jí)并發(fā)TCP服務(wù)器框架Zinx-游戲服務(wù)器開發(fā)002:框架學(xué)習(xí)-按照三層結(jié)構(gòu)模式重構(gòu)測(cè)試代碼+Tcp數(shù)據(jù)適配+時(shí)間輪定時(shí)器

這篇具有很好參考價(jià)值的文章主要介紹了C/C++輕量級(jí)并發(fā)TCP服務(wù)器框架Zinx-游戲服務(wù)器開發(fā)002:框架學(xué)習(xí)-按照三層結(jié)構(gòu)模式重構(gòu)測(cè)試代碼+Tcp數(shù)據(jù)適配+時(shí)間輪定時(shí)器。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1 Zinx框架總覽

cpp zinx框架,Zinx-Tcp輕量級(jí)并發(fā)服務(wù)器框架-MMO游戲服務(wù)器開發(fā),服務(wù)器,游戲,重構(gòu)

2 三層模式的分析

cpp zinx框架,Zinx-Tcp輕量級(jí)并發(fā)服務(wù)器框架-MMO游戲服務(wù)器開發(fā),服務(wù)器,游戲,重構(gòu)

3 三層重構(gòu)原有的功能 - 頭文件

三層結(jié)構(gòu)重構(gòu)原有功能

  1. 自定義消息類,繼承UserData,添加一個(gè)成員變量szUserData
  2. 定義多個(gè)Role類繼承Irole,重寫ProcMsg函數(shù),進(jìn)行不同處理
  3. 定義protocol類,繼承Iprotocol,重寫四個(gè)函數(shù),兩個(gè)函數(shù)時(shí)原始
    數(shù)據(jù)和用戶數(shù)據(jù)之間的轉(zhuǎn)換;另兩個(gè)用來找消息處理對(duì)象和消息發(fā)
    送對(duì)象。
  4. 定義channel類,繼承Ichannel,在getnextinputstage函數(shù)中返回協(xié)
    議對(duì)象

3.1 通道層Stdin和Stdout類

通道類,派生自基礎(chǔ)處理者類,提供基于系統(tǒng)調(diào)用的數(shù)據(jù)收發(fā)功能
一般地,用戶應(yīng)該根據(jù)處理的文件(信息源)不同而創(chuàng)建通道類的子類或選用合適的實(shí)用類(已經(jīng)提供的通道類子類)來完成系統(tǒng)級(jí)文件IO
cpp zinx框架,Zinx-Tcp輕量級(jí)并發(fā)服務(wù)器框架-MMO游戲服務(wù)器開發(fā),服務(wù)器,游戲,重構(gòu)

class StdInChannel :
	public Ichannel
{
public:
	StdInChannel();
	virtual ~StdInChannel();

	// 通過 Ichannel 繼承
	virtual bool Init() override;
	virtual bool ReadFd(std::string& _input) override;
	virtual bool WriteFd(std::string& _output) override;
	virtual void Fini() override;
	virtual int GetFd() override;
	virtual std::string GetChannelInfo() override;
	virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};

class StdOutChannel :public Ichannel
{
	// 通過 Ichannel 繼承
	virtual bool Init() override;
	virtual bool ReadFd(std::string& _input) override;
	virtual bool WriteFd(std::string& _output) override;
	virtual void Fini() override;
	virtual int GetFd() override;
	virtual std::string GetChannelInfo() override;
	virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};

3.1.2 StdInChannel

bool StdInChannel::ReadFd(std::string& _input)
{
	cin >> _input;
	return true;
}

bool StdInChannel::WriteFd(std::string& _output)
{
	return false;
}

int StdInChannel::GetFd()
{
	return 0;
}

std::string StdInChannel::GetChannelInfo()
{
	return "stdin";
}

AZinxHandler* StdInChannel::GetInputNextStage(BytesMsg& _oInput)
{
	/*返回協(xié)議對(duì)象*/
	return CmdCheck::GetInstance();
}

3.1.2 StdOutChannel

bool StdOutChannel::ReadFd(std::string& _input)
{
	return false;
}

bool StdOutChannel::WriteFd(std::string& _output)
{
	cout << _output << endl;
	return true;
}

int StdOutChannel::GetFd()
{
	return 1;
}

std::string StdOutChannel::GetChannelInfo()
{
	return "stdout";
}

AZinxHandler* StdOutChannel::GetInputNextStage(BytesMsg& _oInput)
{
	return nullptr;
}

3.2 協(xié)議層CmdCheck和CmdMsg類

3.2.1 CmdCheck單例模式

  1. 原始數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù)相互函數(shù),開發(fā)者重寫該函數(shù),實(shí)現(xiàn)協(xié)議
  2. 獲取處理角色對(duì)象函數(shù),開發(fā)者應(yīng)該重寫該函數(shù),用來指定當(dāng)前產(chǎn)生的用戶數(shù)據(jù)消
  3. 獲取發(fā)送通道函數(shù),開發(fā)者應(yīng)該重寫該函數(shù),用來指定當(dāng)前字節(jié)流應(yīng)該由哪個(gè)通道對(duì)象發(fā)出
class CmdCheck :
	public Iprotocol
{
	CmdCheck();
	virtual ~CmdCheck();
	static CmdCheck *poSingle;
public:
	// 通過 Iprotocol 繼承
	/*原始數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù)相互函數(shù),開發(fā)者重寫該函數(shù),實(shí)現(xiàn)協(xié)議*/
	virtual UserData * raw2request(std::string _szInput) override;
	virtual std::string * response2raw(UserData & _oUserData) override;
	/*獲取處理角色對(duì)象函數(shù),開發(fā)者應(yīng)該重寫該函數(shù),用來指定當(dāng)前產(chǎn)生的用戶數(shù)據(jù)消息應(yīng)該傳遞給哪個(gè)角色處理*/
	virtual Irole * GetMsgProcessor(UserDataMsg & _oUserDataMsg) override;
    /*獲取發(fā)送通道函數(shù),開發(fā)者應(yīng)該重寫該函數(shù),用來指定當(dāng)前字節(jié)流應(yīng)該由哪個(gè)通道對(duì)象發(fā)出*/
	virtual Ichannel * GetMsgSender(BytesMsg & _oBytes) override;
	static CmdCheck *GetInstance() {
		return poSingle;
	}
	std::string szOutChannel;
};
3.2.1.1 單例模式

構(gòu)造全局唯一的協(xié)議對(duì)象

#include "CmdCheck.h"
#include "CmdMsg.h"
#include "EchoRole.h"
using namespace std;

CmdCheck *CmdCheck::poSingle = new CmdCheck();

3.2.1.2 * 命令識(shí)別類向業(yè)務(wù)層不同類別做分發(fā)

通過是不是命令來進(jìn)行區(qū)分:if (isCmd)

Irole * CmdCheck::GetMsgProcessor(UserDataMsg & _oUserDataMsg)
{
	szOutChannel = _oUserDataMsg.szInfo;
	if ("stdin" == szOutChannel)
	{
		szOutChannel = "stdout";
	}
	/*根據(jù)命令不同,交給不同的處理role對(duì)象*/
	auto rolelist = ZinxKernel::Zinx_GetAllRole();

	auto pCmdMsg = dynamic_cast<CmdMsg *>(_oUserDataMsg.poUserData);

	/*讀取當(dāng)前消息是否是命令*/
	bool isCmd = pCmdMsg->isCmd;

	Irole *pRetRole = NULL;

	for (Irole *prole : rolelist)
	{
		if (isCmd)
		{
			auto pOutCtrl = dynamic_cast<OutputCtrl *>(prole);
			if (NULL != pOutCtrl)
			{
				pRetRole = pOutCtrl;
				break;
			}
		}
		else
		{
			auto pDate = dynamic_cast<DatePreRole *>(prole);
			if (NULL != pDate)
			{
				pRetRole = pDate;
				break;
			}
		}
	}
	
	return pRetRole;
}

3.2.2 CmdMsg自定義用戶信息類,繼承UserData

class CmdMsg :
	public UserData
{
public:
	/*成員變量表示要回顯的字符串*/
	std::string szUserData;
	/*開啟輸出標(biāo)志*/
	bool isOpen = true;
	/*該消息是命令*/
	bool isCmd = false;
	/*要加前綴*/
	bool needDatePre = false;
	
	CmdMsg();
	virtual ~CmdMsg();
};

3.3 業(yè)務(wù)層:回顯類, 輸出通道控制類, 日期前綴管理類

3.3.1 回顯對(duì)象EchoRole

主要有init, procmsg,fini三個(gè)函數(shù)

#pragma once
#include <zinx.h>

class EchoRole :
	public Irole
{
public:
	EchoRole();
	virtual ~EchoRole();

	// 通過 Irole 繼承
	virtual bool Init() override;
	virtual UserData * ProcMsg(UserData & _poUserData) override;
	virtual void Fini() override;
};
  • 容易出錯(cuò)的點(diǎn):參數(shù)一必須是一個(gè)堆對(duì)象
UserData * EchoRole::ProcMsg(UserData & _poUserData)
{
	/*寫出去*/
	GET_REF2DATA(CmdMsg, input, _poUserData);
	CmdMsg *pout = new CmdMsg(input);
	ZinxKernel::Zinx_SendOut(*pout, *(CmdCheck::GetInstance()));
	return nullptr;
}

3.3.2 控制輸入輸出

  1. 寫一個(gè)關(guān)閉輸出的角色類,摘除輸出通道或添加輸出通道
  2. 在CmdMsg用戶數(shù)據(jù)類中添加開關(guān)標(biāo)志,是否是命令標(biāo)志
  3. 在協(xié)議類中,根據(jù)輸入字符串,設(shè)置開關(guān)標(biāo)志和是否是命令的標(biāo)志
  4. 在協(xié)議類分發(fā)消息時(shí),判斷是否是命令,是命令則發(fā)給關(guān)閉輸出角 色類,否則發(fā)給回顯角色類
class OutputCtrl :public Irole {
	// 通過 Irole 繼承
	virtual bool Init() override;
	virtual UserData * ProcMsg(UserData & _poUserData) override;
	virtual void Fini() override;
	Ichannel *pOut = NULL;
};

3.3.3 日期管理類

class DatePreRole :public Irole {
	// 通過 Irole 繼承
	virtual bool Init() override;
	virtual UserData * ProcMsg(UserData & _poUserData) override;
	virtual void Fini() override;
	bool needAdd = false;
};

4 Tcp數(shù)據(jù)適配

4.1 工廠類 - 框架頭文件分析

  • 產(chǎn)生tcp數(shù)據(jù)套接字通道類的抽象工廠類。
    • 開發(fā)者需要重寫CreateTcpDataChannel函數(shù),來返回一個(gè)tcp通道對(duì)象。
    • 般地,開發(fā)者應(yīng)該同時(shí)創(chuàng)建一對(duì)tcp通道類和工廠類
class IZinxTcpConnFact {
public:
	virtual ZinxTcpData *CreateTcpDataChannel(int _fd) = 0;
};
  • tcp監(jiān)聽通道類,這是一個(gè)實(shí)體類(不建議繼承該類)。
    • 開發(fā)者可以直接創(chuàng)建tcp監(jiān)聽通道對(duì)象,
    • 一般地,開發(fā)者應(yīng)該在該類的構(gòu)造函數(shù)中,指定一個(gè)tcp套接字通道類的工廠類,當(dāng)有連接到來后,該工廠類的成員方法會(huì)被調(diào)用
class ZinxTCPListen :
	public Ichannel
{
private:
	unsigned short m_usPort = 0;
	int m_fd = -1;
	IZinxTcpConnFact *m_ConnFac = NULL;
	
public:
	ZinxTCPListen(unsigned short _usPort, IZinxTcpConnFact *_pConnFac) :m_usPort(_usPort), m_ConnFac(_pConnFac){}
	virtual ~ZinxTCPListen();

	virtual bool Init() override;
	virtual bool ReadFd(std::string & _input) override;
	virtual bool WriteFd(std::string & _output) override;
	virtual void Fini() override;
	virtual int GetFd() override;
	virtual std::string GetChannelInfo() override;
	virtual AZinxHandler * GetInputNextStage(BytesMsg & _oInput);
};

4.2 tcp通道實(shí)現(xiàn)

cpp zinx框架,Zinx-Tcp輕量級(jí)并發(fā)服務(wù)器框架-MMO游戲服務(wù)器開發(fā),服務(wù)器,游戲,重構(gòu)

4.2.1 Tcp套接字通道通信類

  • tcp數(shù)據(jù)套接字通道類,繼承通道類,該類也是一個(gè)抽象類,需要開發(fā)者繼承該類,重寫GetInputNextStage函數(shù)以指定讀取到的字節(jié)流的處理方式
// h
class myTcpData :public ZinxTcpData {
public:
	myTcpData(int _fd) :ZinxTcpData(_fd) {}
	// 通過 ZinxTcpData 繼承
	virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};
  • Q: Ichannel對(duì)象讀取到的數(shù)據(jù)給誰了?
    • 給該對(duì)象調(diào)用GetInputNextStage函數(shù)返回的對(duì)象
AZinxHandler* myTcpData::GetInputNextStage(BytesMsg& _oInput)
{
	/*返回協(xié)議對(duì)象*/
	return CmdCheck::GetInstance();
}
  • Q: Iprotocol對(duì)象轉(zhuǎn)換出的用戶請(qǐng)求給誰了?
    • 給該對(duì)象調(diào)用GetMsgProcessor函數(shù)返回的對(duì)象

4.2.2 tcp數(shù)據(jù)套接字通道類的工廠類

  • 產(chǎn)生tcp數(shù)據(jù)套接字通道類的抽象工廠類,開發(fā)者需要重寫CreateTcpDataChannel函數(shù),來返回一個(gè)tcp通道對(duì)象
    一般地,開發(fā)者應(yīng)該同時(shí)創(chuàng)建一對(duì)tcp通道類和工廠類
// h
class myFact :public IZinxTcpConnFact {
	// 通過 IZinxTcpConnFact 繼承
	virtual ZinxTcpData* CreateTcpDataChannel(int _fd) override;
};
ZinxTcpData* myFact::CreateTcpDataChannel(int _fd)
{
	return new myTcpData(_fd);
}

5 時(shí)間輪定時(shí)器

5.1 timerfd產(chǎn)生超時(shí)事件

timerfd_create()返回定時(shí)器文件描述符
timerfd_settime()設(shè)置定時(shí)周期,立刻開始計(jì)時(shí)
read,讀取當(dāng)當(dāng)前定時(shí)器超時(shí)的次數(shù),沒超時(shí)會(huì)阻塞.
一般地,會(huì)將定時(shí)器文件描述符結(jié)合IO多路復(fù)用使用

5.1.1 測(cè)試代碼

#include<sys/timerfd.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	int iTimerfd = timerfd_create(CLOCK_MONOTONIC, 0);
	struct itimerspec period
	{{5, 0},{5, 0}
	};
	timerfd_settime(iTimerfd,0, &period,NULL);
	__uint64_t count = 0;
	while(1) {
		read(iTimerfd, &count, sizeof(count));
		puts("time out");
	}
}

cpp zinx框架,Zinx-Tcp輕量級(jí)并發(fā)服務(wù)器框架-MMO游戲服務(wù)器開發(fā),服務(wù)器,游戲,重構(gòu)

5.2 時(shí)間輪設(shè)置

單例模式文章來源地址http://www.zghlxwxcb.cn/news/detail-833955.html

AZinxHandler * ZinxTimerChannel::GetInputNextStage(BytesMsg & _oInput)
{
	return &TimerOutMng::GetInstance();
}

TimerOutMng TimerOutMng::single;

5.2.1 時(shí)間輪的定義

// h
class TimerOutProc {
public:
	virtual void Proc() = 0;
	virtual int GetTimeSec() = 0;
	/*所剩圈數(shù)*/
	int iCount = -1;
};

  • vector存儲(chǔ)輪的齒
  • 每個(gè)齒里用list存每個(gè)定時(shí)任務(wù)
  • 每個(gè)定時(shí)任務(wù)需要記錄剩余圈數(shù)
  • 時(shí)間輪類中要有一個(gè)刻度,每秒進(jìn)一步
TimerOutMng::TimerOutMng()
{
	/*創(chuàng)建10個(gè)齒*/
	for (int i = 0; i < 10; i++)
	{
		list<TimerOutProc *> tmp;
		m_timer_wheel.push_back(tmp);
	}
}

5.2.2 時(shí)間輪的移動(dòng)

// h
class TimerOutMng :public AZinxHandler {
	std::vector<std::list<TimerOutProc *> > m_timer_wheel;
	int cur_index = 0;
	static TimerOutMng single;
	TimerOutMng();
public:
	/*處理超時(shí)事件,遍歷所有超時(shí)任務(wù)*/
	virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override;

	virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override;
	void AddTask(TimerOutProc *_ptask);
	void DelTask(TimerOutProc *_ptask);
	static TimerOutMng &GetInstance() {
		return single;
	}
};
  • 移動(dòng)當(dāng)前刻度
  • 遍歷當(dāng)前齒中的任務(wù)列表
  • 若圈數(shù)為0,則執(zhí)行處理函數(shù),摘除本節(jié)點(diǎn),重新添加
  • 否則,圈數(shù)–
IZinxMsg * TimerOutMng::InternelHandle(IZinxMsg & _oInput)
{
	unsigned long iTimeoutCount = 0;
	GET_REF2DATA(BytesMsg, obytes, _oInput);
	obytes.szData.copy((char *)&iTimeoutCount, sizeof(iTimeoutCount), 0);

	while (iTimeoutCount-- > 0)
	{
		/*移動(dòng)刻度*/
		cur_index++;
		cur_index %= 10;
		list<TimerOutProc *> m_cache;
		/*遍歷當(dāng)前刻度所有節(jié)點(diǎn),指向處理函數(shù)或圈數(shù)-1,*/
		for (auto itr = m_timer_wheel[cur_index].begin(); itr != m_timer_wheel[cur_index].end(); )
		{
			if ((*itr)->iCount <= 0)
			{
				/*緩存待處理的超時(shí)節(jié)點(diǎn)*/
				m_cache.push_back(*itr);
				auto ptmp = *itr;
				itr = m_timer_wheel[cur_index].erase(itr);
				AddTask(ptmp);
			}
			else
			{
				(*itr)->iCount--;
				++itr;
			}
		}

		/*統(tǒng)一待處理超時(shí)任務(wù)*/
		for (auto task : m_cache)
		{
			task->Proc();
		}
	}
	
	return nullptr;
}

5.2.3 添加和刪除任務(wù)

5.2.3.1 添加任務(wù)
  • 計(jì)算當(dāng)前任務(wù)在哪個(gè)齒上
  • 添加該任務(wù)到該齒對(duì)應(yīng)的list里
  • 計(jì)算所需圈數(shù)記錄到任務(wù)中
void TimerOutMng::AddTask(TimerOutProc * _ptask)
{
	/*計(jì)算當(dāng)前任務(wù)需要放到哪個(gè)齒上*/
	int index = (_ptask->GetTimeSec() + cur_index) % 10;
	/*把任務(wù)存到該齒上*/
	m_timer_wheel[index].push_back(_ptask);
	/*計(jì)算所需圈數(shù)*/
	_ptask->iCount = _ptask->GetTimeSec() / 10;
}
5.2.3.2 刪除任務(wù)
  • 遍歷所有齒
  • 在每個(gè)齒中遍歷所有節(jié)點(diǎn)
  • 若找到則刪除并返回
void TimerOutMng::DelTask(TimerOutProc * _ptask)
{
	/*遍歷時(shí)間輪所有齒,刪掉任務(wù)*/
	for (list<TimerOutProc *> &chi : m_timer_wheel)
	{
		for (auto task : chi)
		{
			if (task == _ptask)
			{
				chi.remove(_ptask);
				return;
			}
		}
	}
}

5.3 定時(shí)器設(shè)置

5.3.1 定時(shí)器定義

class ZinxTimerChannel :
	public Ichannel
{
	int m_TimerFd = -1;

public:
	ZinxTimerChannel();
	virtual ~ZinxTimerChannel();

	// 通過 Ichannel 繼承
	virtual bool Init() override;
	virtual bool ReadFd(std::string & _input) override;
	virtual bool WriteFd(std::string & _output) override;
	virtual void Fini() override;
	virtual int GetFd() override;
	virtual std::string GetChannelInfo() override;
	virtual AZinxHandler * GetInputNextStage(BytesMsg & _oInput) override;
};

5.3.2 定時(shí)器初始化

/*創(chuàng)建定時(shí)器文件描述符*/
bool ZinxTimerChannel::Init()
{
	bool bRet = false; //判斷成功或者失敗
	/*創(chuàng)建文件描述符*/
	int iFd = timerfd_create(CLOCK_MONOTONIC, 0);
	if (0 <= iFd)
	{
		/*設(shè)置定時(shí)周期*/
		struct itimerspec period = {
			{1,0}, {1,0}
		};
		if (0 == timerfd_settime(iFd, 0, &period, NULL))
		{
			bRet = true;
			m_TimerFd = iFd;  
		}
	}
	return bRet;
}
/*讀取超時(shí)次數(shù)*/
bool ZinxTimerChannel::ReadFd(std::string & _input)
{
	bool bRet = false;
	char buff[8] = { 0 };

	if (sizeof(buff) == read(m_TimerFd, buff, sizeof(buff)))
	{
		bRet = true;
		_input.assign(buff, sizeof(buff));
	}
	return bRet;
}

bool ZinxTimerChannel::WriteFd(std::string & _output)
{
	return false;
}

/*關(guān)閉文件描述符*/
void ZinxTimerChannel::Fini()
{
	close(m_TimerFd);
	m_TimerFd = -1;
}

/*返回當(dāng)前的定時(shí)器文件描述符*/
int ZinxTimerChannel::GetFd()
{
	return m_TimerFd;
}


std::string ZinxTimerChannel::GetChannelInfo()
{
	return "TimerFd"; // 名字隨便起的
}

5.3.3 輸出hello world

class output_hello :public AZinxHandler {
	// 通過 AZinxHandler 繼承
	virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override
	{
		auto pchannel = ZinxKernel::Zinx_GetChannel_ByInfo("stdout");
		std::string output = "hello world";
		ZinxKernel::Zinx_SendOut(output, *pchannel);
		return nullptr;
	}
	virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override
	{
		return nullptr;
	}
} *pout_hello = new output_hello();

到了這里,關(guān)于C/C++輕量級(jí)并發(fā)TCP服務(wù)器框架Zinx-游戲服務(wù)器開發(fā)002:框架學(xué)習(xí)-按照三層結(jié)構(gòu)模式重構(gòu)測(cè)試代碼+Tcp數(shù)據(jù)適配+時(shí)間輪定時(shí)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • git輕量級(jí)服務(wù)器gogs、gitea,非輕量級(jí)gitbucket

    git輕量級(jí)服務(wù)器gogs、gitea,非輕量級(jí)gitbucket

    本文來源:git輕量級(jí)服務(wù)器gogs、gitea,非輕量級(jí)gitbucket, 或 gitcode/gogs,gitea.md 結(jié)論: gogs、gitea很相似 確實(shí)輕, gitbucket基于java 不輕, 這三者都不支持組織樹(嵌套組織 nested group) 只能一層組織。 個(gè)人用,基于gogs、gitea,兩層結(jié)構(gòu)樹 簡(jiǎn)易辦法: 把用戶當(dāng)成第一層節(jié)點(diǎn)、該用戶的

    2024年02月07日
    瀏覽(140)
  • Tomcat輕量級(jí)服務(wù)器

    Tomcat輕量級(jí)服務(wù)器

    目錄 1.常見系統(tǒng)架構(gòu)? C-S架構(gòu) B-S架構(gòu) 2.B-S架構(gòu)系統(tǒng)的通信步驟 3.常見WEB服服務(wù)器軟件 4.Tomcat服務(wù)器的配置 下載安裝 環(huán)境變量配置 測(cè)試環(huán)境變量是否配置成功 測(cè)試Tomcat服務(wù)器是否配置成功? Tomcat窗口一閃而過的解決步驟 Tomcat解決亂碼 介紹: C-S架構(gòu)即Client/Server(客戶端/服務(wù)

    2023年04月14日
    瀏覽(102)
  • 輕量級(jí)音樂服務(wù)器LMS

    輕量級(jí)音樂服務(wù)器LMS

    本文軟件是網(wǎng)友 tommyvinny 推薦的,他在 UNRAID 上安裝遇到了權(quán)限問題,存在無法建立目錄的情況,但似乎在群暉上沒遇到。如果你也遇到相似的問題,可以試試命令行模式。 官方體驗(yàn)站點(diǎn):https://lms-demo.poupon.dev/ 什么是 LMS ? LMS ( Lightweight Music Server )是一款自托管的輕量級(jí)

    2024年02月08日
    瀏覽(26)
  • 三步配置輕量級(jí)服務(wù)器nginx

    三步配置輕量級(jí)服務(wù)器nginx

    一款輕量級(jí)的 Web服務(wù)器,反向代理服務(wù)器,以及電子郵件代理服務(wù)器 主要有三個(gè)優(yōu)點(diǎn): 占用內(nèi)存少,并發(fā)能力強(qiáng) Nginx為性能優(yōu)化開發(fā),能支持五千個(gè)左右的并發(fā)響應(yīng) (Tomcat只有三百到五百) Nginx支持熱部署,可以在不間斷服務(wù)情況下對(duì)軟件進(jìn)行升級(jí)(不要用關(guān)閉服務(wù)器)

    2023年04月24日
    瀏覽(24)
  • 阿里云輕量級(jí)服務(wù)器安裝docker

    阿里云輕量級(jí)服務(wù)器安裝docker

    前置知識(shí):需要有一臺(tái)阿里云服務(wù)器(或者自己電腦裝虛擬機(jī)使用centos) docker理念:\\\"一次封裝,到處運(yùn)行\(zhòng)\\",只需要一次配置好環(huán)境,換到別的機(jī)子上就可以一鍵部署好,大大簡(jiǎn)化了操作。 docker:解決了運(yùn)行環(huán)境和配置問題的軟件容器。方便做持續(xù)集成并有助于整體發(fā)布的容器

    2023年04月22日
    瀏覽(94)
  • 騰訊云輕量級(jí)服務(wù)器哪個(gè)鏡像比較好?

    騰訊云輕量級(jí)服務(wù)器哪個(gè)鏡像比較好?

    騰訊云輕量應(yīng)用服務(wù)器鏡像是什么?鏡像就是操作系統(tǒng),輕量服務(wù)器鏡像系統(tǒng)怎么選擇?如果是用來搭建網(wǎng)站騰訊云百科txybk.com建議選擇選擇寶塔Linux面板騰訊云專享版,鏡像系統(tǒng)根據(jù)實(shí)際使用來選擇,騰訊云百科來詳細(xì)說下騰訊云輕量應(yīng)用服務(wù)器鏡像的選擇方法: 輕量應(yīng)用

    2024年02月06日
    瀏覽(25)
  • 騰訊云輕量級(jí)服務(wù)器部署(新手圖文教程)

    騰訊云輕量級(jí)服務(wù)器部署(新手圖文教程)

    相信不少同學(xué)都想將自己的項(xiàng)目部署到云服務(wù)器,讓別人通過自己的域名就可以訪問到自己的項(xiàng)目,而騰訊云輕量級(jí)服務(wù)器作為一個(gè)小型的應(yīng)用,支持域名解析和可視化運(yùn)維等。比較適合新手入門,本文服務(wù)器操作系統(tǒng)為Centos7。 1.購買方式 本文主要面向新手,畢竟一般只有

    2024年02月10日
    瀏覽(33)
  • 輕量級(jí)服務(wù)器nginx:反向代理的具體配置

    輕量級(jí)服務(wù)器nginx:反向代理的具體配置

    例如:第一章 Python 機(jī)器學(xué)習(xí)入門之pandas的使用 我們?cè)趪鴥?nèi),如果要訪問谷歌,那就無法訪問,需要借助一個(gè)正向代理服務(wù)器,先將信息傳給代理服務(wù)器,代理服務(wù)器所在的位置可以訪問谷歌,這樣就可以做到代理去谷歌取到并返回?cái)?shù)據(jù),并把信息發(fā)送到自己的終端上。 如果

    2023年04月25日
    瀏覽(27)
  • 騰訊云服務(wù)器鏡像共享到另一賬號(hào)的輕量級(jí)云服務(wù)器

    騰訊云服務(wù)器鏡像共享到另一賬號(hào)的輕量級(jí)云服務(wù)器

    1.創(chuàng)建鏡像,鏡像制作完成后,點(diǎn)擊鏡像可查看 2.先共享鏡像到另一賬號(hào) 3.登錄輕量云服務(wù)器賬號(hào)鏡像板塊,復(fù)制共享鏡像為自己的鏡像 4.通過自己創(chuàng)建的鏡像共享到輕量云服務(wù)器鏡像內(nèi) 到這一步鏡像已經(jīng)成功共享到輕量云服務(wù)器了 5.接下來我們通過鏡像重裝系統(tǒng) (注意:重

    2024年02月11日
    瀏覽(22)
  • 輕量級(jí)全功能開源免費(fèi)Mailu郵件服務(wù)器部署

    輕量級(jí)全功能開源免費(fèi)Mailu郵件服務(wù)器部署

    實(shí)踐說明:基于AlmaLinux9,但適用場(chǎng)景不限于此。 文檔形成時(shí)期:2023年 因系統(tǒng)或軟件版本不同,構(gòu)建部署可能略有差異,但本文未做細(xì)分,對(duì)稍有經(jīng)驗(yàn)者應(yīng)不存在明顯障礙。 因軟件世界之復(fù)雜和個(gè)人能力之限,難免疏漏和錯(cuò)誤,歡迎指正。 占用資源少而使用成本低; 基本功

    2024年02月02日
    瀏覽(43)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包