多台机器间的数据同步

大家好,我目前就职于一家工业制造公司,我的email是wuxfei@gmail.com,工作近3年时间了。在工作中经常会遇到这样的问题,有多台机器可以处理多种工件。若A机器在处理a种工件后,得让B机器或更多地机器知道A机器已经处理过一个a种工件。


为了能满足项目需求,并提高该功能模块的可移植性,我设计了一个类,并提供相应的一些调用接口。思路如下:每当某台机器处理了某工件后,它便以广播的形式告知其他机器,并在收到回馈数量为其他机器数量总和时,则认为其他所有机器都收到了同步消息,即可在同步列表中删除该条同步信息。

上代码:

接口:

class SYNCHRO_API CXFSynchro  
{
public:
	//nBakCount为几机备份,>=2。
	bool InitiaSynchro(int nBakCount);

	//向其他机器发送同步信息,将该条数据发往其他机器。
	int SendSynchro(string &strItem);
	
	//重写这个类,处理其他机器发送的同步信息。子类函数结尾处必须调用父类函数以便告知发送者:你已经收到了对方的同步数据。
	virtual void OnSynchro(string &strItem);

	//获取还没有收到确认信息的同步数据。返回未确认的个数.主要是为了方便在界面显示未同步的数据。
	int GetNotACK(CStringArray &strNotACKArray);
	
public:
	CXFSynchro(UINT nPort);
	virtual ~CXFSynchro();
	
private:
	void SynchroThread();
	
private:
	map<string, int> m_WaitSynchroMap;
	CRITICAL_SECTION m_cs;
	int m_nBakCount;
	bool m_bSockOK;
	bool m_bStarting;
	UINT m_Localsock;
	UINT m_SendSock;
	UINT m_nSynchroPort;
	friend void SynchroThread(LPVOID lp);
};


源码如下:

CXFSynchro::CXFSynchro(UINT nPort)
{
	InitializeCriticalSection(&m_cs);
	m_WaitSynchroMap.clear();
	m_nSynchroPort = nPort;
	m_bSockOK = true;
	m_bStarting = false;

	WSADATA wsdata;
	WSAStartup(0x0202, &wsdata);

	g_addrSynchro1.sin_family = AF_INET;
	g_addrSynchro1.sin_addr.s_addr = INADDR_BROADCAST;
	g_addrSynchro1.sin_port = htons(m_nSynchroPort);
	memcpy(&g_addrSynchro2, &g_addrSynchro1, sizeof(sockaddr_in));
	
	char opt = true;
	m_SendSock = WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
	setsockopt(m_SendSock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
	
	sockaddr_in addLocal;
	addLocal.sin_family = AF_INET;
	addLocal.sin_addr.s_addr = 0;
	addLocal.sin_port = htons(m_nSynchroPort);
	opt = true;
	m_Localsock = socket(AF_INET, SOCK_DGRAM, 0);
	setsockopt(m_Localsock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
	
	if (0 != bind(m_Localsock, (SOCKADDR*)&addLocal, sizeof(addLocal)))
	{
		m_bSockOK = false;
	}
}

CXFSynchro::~CXFSynchro()
{
	DeleteCriticalSection(&m_cs);
	g_bExitSynchro = true;
	closesocket(m_Localsock);
	closesocket(m_SendSock);
	Sleep(500);
}

int CXFSynchro::SendSynchro(string &strItem)
{	
	char szSend[1024*8];
	ZeroMemory(szSend, sizeof(szSend));
	szSend[0] = DATA_TYPE_SYN;
	strcat(szSend+1, strItem.c_str());

	EnterCriticalSection(&m_cs);
	m_WaitSynchroMap[strItem] = 0;
	int n = sendto(m_SendSock, szSend, 1+strlen(strItem.c_str()), 0, (sockaddr*)&g_addrSynchro1, sizeof(g_addrSynchro1));
	LeaveCriticalSection(&m_cs);
	return n;
}

void SynchroThread(LPVOID lp)
{
	while(!g_bExitSynchro)
	{
		((CXFSynchro*)lp)->SynchroThread();
		Sleep(300);
	}
}	

bool CXFSynchro::InitiaSynchro(int nBakCount)
{
	m_nBakCount = nBakCount;
	assert(m_nBakCount>=2);

	if (m_bSockOK && !m_bStarting)
	{
		m_bStarting = true;
		_beginthread(::SynchroThread, 0, this);
	}
	return m_bStarting;
}

void CXFSynchro::SynchroThread()
{
	char szBuff[8096];
	ZeroMemory(szBuff, sizeof(szBuff));
	int nAddrLen = sizeof(g_addrSynchro2);
	if (1>=recvfrom(m_Localsock, szBuff, sizeof(szBuff), 0, (sockaddr*)&g_addrSynchro2, &nAddrLen))
	{
		return;
	}
	const char dataType = szBuff[0];
	string strItem(szBuff+1);

	if (DATA_TYPE_SYN==dataType)//同步帧
	{
		EnterCriticalSection(&m_cs);
		if (m_WaitSynchroMap.end() == m_WaitSynchroMap.find(strItem))//若是其他机器挑起的
		{
			OnSynchro(strItem);
		}
		LeaveCriticalSection(&m_cs);
	} 
	else//确认帧
	{
		EnterCriticalSection(&m_cs);
		if (m_WaitSynchroMap.end() != m_WaitSynchroMap.find(strItem))//若是自己挑起的
		{
			m_WaitSynchroMap[strItem] = 1+m_WaitSynchroMap[strItem];
			if (m_WaitSynchroMap[strItem] >= m_nBakCount)
			{
				m_WaitSynchroMap.erase(strItem);
			}
		}	
		LeaveCriticalSection(&m_cs);
	}
}

void CXFSynchro::OnSynchro(string &strItem)
{
	char szSend[1024*8];
	ZeroMemory(szSend, sizeof(szSend));
	szSend[0] = DATA_TYPE_ACK;
	strcat(szSend+1, strItem.c_str());

	EnterCriticalSection(&m_cs);
	sendto(m_SendSock, szSend, 1+strlen(strItem.c_str()), 0, (sockaddr*)&g_addrSynchro1, sizeof(g_addrSynchro1));
	LeaveCriticalSection(&m_cs);
}

int CXFSynchro::GetNotACK(CStringArray &strNotACKArray)
{
	strNotACKArray.RemoveAll();
	map<string,int>::iterator iter;
	EnterCriticalSection(&m_cs);
	for (iter=m_WaitSynchroMap.begin(); iter!=m_WaitSynchroMap.end(); iter++)
	{		
		CString str = iter->first.c_str();
		strNotACKArray.Add(str);
	}
	LeaveCriticalSection(&m_cs);
	return strNotACKArray.GetSize();
}


本人能力有限,如有疑问可联系我 wuxfei@gmail.com。

### 配置Ubuntu系统下的多台服务器间数据同步 #### 使用Rsync进行文件同步 对于Ubuntu系统的多台服务器间的文件同步,一种高效的方法是利用`rsync`工具。该工具能够有效地比较源目录和目标目录中的文件差异,并仅传输那些发生变化的部分,从而减少网络带宽消耗以及提高效率[^1]。 为了设置基于`rsync`的服务端,在每台参与同步的机器上都需要安装`rsync`: ```bash sudo apt-get update && sudo apt-get install rsync ``` 接着定义好要同步的目标路径与远程主机地址,编写脚本定期执行同步操作或是通过SSH密钥认证来简化登录过程。 另一种更为自动化的方式则是采用`Lsyncd`(Live Syncing Daemon),它可以在检测到本地文件变化时立即触发向其他节点推送更新的动作[^4]。 #### 利用共享云硬盘实现高可用性 除了传统的文件级同步外,还可以考虑使用共享云硬盘作为中间介质来进行多台服务器之间的数据交换。这种方式特别适合于需要频繁读写的场景,因为其允许多达十六台不同类型的云服务器同时挂载同一块磁盘空间,提供极高的I/O性能和支持复杂的业务逻辑需求[^3]。 不过需要注意的是,这种方法更适合静态资源或者日志类别的数据存储;而对于数据库等结构化数据,则建议采取专门设计用于此类用途的技术栈,比如MySQL集群环境下的Galera Cluster解决方案[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值