在Unix/Linux下模拟双机热备(客户端自适应方式)

来源:互联网 发布:unity3d解包 编辑:程序博客网 时间:2024/06/05 18:05
在Unix/Linux下模拟双机热备(客户端自适应方式)
    最近突然对双机热备的切换的过程产生了浓厚的兴趣。晚上动手写了份代码模拟了,双机切换的过程。该模拟方式是通过客户端自适应的方式来实现。当一个客户端发现链接的服务器关闭之后,便链接备用服务器。具体描述如下:
      启两个服务器进程在3000,3001这两个端口进行监听,当有客户进程链接服务进程时,服务进程,创建一个线程与之通信。启一个客户进程,初始化客户进程链接的3000端口的服务进程,当发现3000端口的服务进程需要更新而停止的时候,客户端会去试图链接另一个端口的服务进程。如何反复,从而可以实现在不停止对客户端的正常服务情况下,并同步更新服务进程。

代码如下

客户端代码:

#include <iostream>#include <stdlib.h>#include "client.h"using namespace std;char strMsg[30] = "hello server.";int serverPort[2] = {3000, 3001};void InitClient(Client & client, int index){if(!client.initialize()) {cout << "client initialize error program exit" << endl;exit(1);}if (!client.connection((char *)SERVER_IP, serverPort[index])) {cout << "client connection error program exit" << endl;cout << "server_ip = " << SERVER_IP << endl;cout << "server_port = " << serverPort[index] << endl;exit(1);}}int main(int argc, char * argv[]){int index = 0;Client client;InitClient(client, index);int count = 0;bool flag = true;sleep(2);bool out = true;while (1) {if (flag) {flag = client.recvMsg(strMsg);}if (flag) {if (out) {cout << "connection server" << endl;out = false;}sleep(2);}else {cout << "one server port close" << endl;cout << "change the another server port" << endl;index++;index %= 2;InitClient(client, index);flag = true;out = true;sleep(2);}}return 0;}

服务端代码:

#include <iostream>#include <stdlib.h>#include <pthread.h>#include <list>#include "adapter.h"#include "server.h"using namespace std;int nNewSocketId;void * Run(void * arg){ClientAdapter * pAdapter = (ClientAdapter *)arg;pAdapter->CreateClientAdapter();}int main(int argc, char * argv[]){if (argc != 2) {cout << "arg error!" << endl;}int listenPort = atoi(argv[1]);list<ClientAdapter * > vAdapter;pthread_t tid;struct sockaddr client;Server server;server.initialize();server.bindPort(listenPort);server.listenClient();int clientCnt = vAdapter.size();cout << "client count = " << clientCnt << endl;while (true) {if (clientCnt != vAdapter.size()) {cout << "client count = " << vAdapter.size() << endl;clientCnt = vAdapter.size();}nNewSocketId = server.acceptClient(client);if (nNewSocketId == -1) {//perror("accept");sleep(2);}else {ClientAdapter * pClient = new ClientAdapter();pClient->m_nsocketFd = nNewSocketId;cout << "get the client connection." << endl;cout << "new socketid = " << nNewSocketId << endl;vAdapter.push_back(pClient);pthread_create(&tid, NULL, Run, (void *)pClient);}list<ClientAdapter *>::iterator itr = vAdapter.begin();while (itr != vAdapter.end()) {if ((*itr)->m_bIfCanErase) {delete (*itr);vAdapter.erase(itr++);continue;}else {itr++;}}}return 0;}

client.cpp:

#include "client.h"Client::Client() {//nothing.}Client::~Client() {//nothing.}bool Client::initialize(){m_nSocketFd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == m_nSocketFd) {perror("socket create");return false;}else {return true;}}bool Client::connection(char * pStrServerIP, int serverPort){m_sServer.sin_family = AF_INET;m_sServer.sin_addr.s_addr = inet_addr(pStrServerIP);m_sServer.sin_port = htons(serverPort);if (connect(m_nSocketFd, (struct sockaddr *)&m_sServer, sizeof(m_sServer)) < 0) {perror("connecting stream socket");return false;}else {int nFlag = fcntl(m_nSocketFd,F_GETFL,0);fcntl(m_nSocketFd,F_SETFL,nFlag|O_NONBLOCK);return true;}}bool Client::recvMsg(char * pStrMsg){char buf[100];buf[0] = 0;if (recv(m_nSocketFd, buf, 100, 0) <= 0) {return false;}return true;}

server.cpp:

#include "server.h"Server::Server() {//nothing.}Server::~Server(){//nothing.}bool Server::initialize(){m_nSocketFd = socket(AF_INET, SOCK_STREAM, 0);if (m_nSocketFd < 0) {perror("opening stream socket");return false;}int nFlag = fcntl(m_nSocketFd,F_GETFL,0);fcntl(m_nSocketFd,F_SETFL,nFlag|O_NONBLOCK);int on = 1;setsockopt(m_nSocketFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));return true;}bool Server::bindPort(int nServerPort){m_sServer.sin_family = AF_INET;m_sServer.sin_port = htons(nServerPort);m_sServer.sin_addr.s_addr = INADDR_ANY;bzero(&(m_sServer.sin_zero), 8);if (bind(m_nSocketFd, (struct sockaddr *)&m_sServer, sizeof(m_sServer)) < 0) {perror("binding stream socket");return false;}else {return true;}}void Server::listenClient(){listen(m_nSocketFd, 5);}int Server::acceptClient(sockaddr & clientAddr){int len = sizeof(struct sockaddr);return accept(m_nSocketFd, (struct sockaddr *)&clientAddr, (socklen_t *)&len);}

adpater.cpp:

#include "adapter.h"ClientAdapter::ClientAdapter(){//nothing.this->m_bIfCanErase = false;}ClientAdapter::~ClientAdapter(){//nothing.}void ClientAdapter::CreateClientAdapter(){int rval;char buf[1024];pthread_t tid;tid = pthread_self();printf("thread id = %u\n", (unsigned int)tid);cout << "socket Id = " << m_nsocketFd << endl;while (true){int sendLen = send(m_nsocketFd, "hello client", 20, 0);sleep(2);if (sendLen <= 0) {printf("ending connection\n");m_bIfCanErase = true;break;}}}

运行结果如下:



模拟结果分析:
       其两个服务端进程,然后启一个客户端进程。停在3000端口监听的服务端进程,此时客户端进程发现在3000端口监听的服务进程已经停止便去链接在3001端口监听的服务端进程。然后再启在3000端口监听的服务进程,停在3001端口监听的服务进程。此时客户端进程发现在3001端口监听的服务进程已经停止便去链接在3000端口监听的服务端进程