多台Linux服务器的一键关机


引言

目前使用远程客户端上的Putty,对Linux服务器重启关机等操作,操作过程较繁琐,而遇到n台服务器的情况,操作任务*n,实在不方便,现在就试着写一个程序,可以多台服务器的一键关机等操作。


一、原理

简单点,服务器运行一个服务进程,监听客户端,当有操作命令后,执行相应的命令。二者使用TCP/IP协议通讯。

二、服务器端源码

1.Tcp/IP服务

网上直接找了一段,直接拷贝过来:

//-------tcp相关头文件------
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> //close()


static int socket_fd = 0;
static int socket_c_fd = 0;
//tcp_server_init()
#if 0
1、创建socket
2、设置本地ip和端口以及协议类型
3、绑定
4、监听
5、等待客户端连接
6、收发数据
7、关闭连接
#endif

int tcp_server_init(int port)
{
	int ret;
	//1 
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(socket_fd == -1)
	{
		printf("create socket fail\n");
		return -1;
	}
	//2 
	struct sockaddr_in local_addr,c_addr;
	local_addr.sin_family = AF_INET;//IPv4协议	
	local_addr.sin_port = htons(port);//服务器端口号	
	local_addr.sin_addr.s_addr = INADDR_ANY;//设置服务器ip
	//3
	ret = bind(socket_fd, &local_addr, sizeof(local_addr));
	if(ret == -1)
	{
		printf("bind fail\n");
		return -1;
	}
	//4
	ret = listen(socket_fd, 3);
	if(ret == -1)
	{
		printf("listen fail\n");
		return -1;
	}
	//5
	socklen_t addrlen = 0;
	while(1)
	{
		socket_c_fd = accept(socket_fd, &c_addr, &addrlen);
		if(addrlen != 0)
			break;
	}
	printf("client connect\n");
}

//tcp_server_send()
int tcp_server_send(char *buff, int len)
{
	write(socket_c_fd, buff, len);
}

//tcp_server_rcv()
int tcp_server_rcv(char *buff, int len)
{
	int ret;
	
	ret = read(socket_c_fd, buff, len);
	return ret;
}

//tcp_server_close()
int tcp_server_close()
{
	close(socket_fd);
}

2.main文件

代码稍微修改以下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "tcp_server.h"

int main()
{
	int rcv_len;
	char buff[1024] = {0};
	
	tcp_server_init(9090);
	
	while(1)
	{
		rcv_len = tcp_server_rcv(buff, 1024);
		if(rcv_len == 15)
		{
			printf("tcp rcv: %s\n", buff);
			tcp_server_send("server rcv ok\n", 14);
			sleep(1);
			system(buff);
			break;
		}
		else
		{
			printf("There is no command from client, waiting!\n");
			sleep(1);
		}
	}
	return 0;
}

三、客户端源码

客户端使用QT编写。

1.Tcp/IP客户端

源码修改以下:

#include "clientshut.h"

ClientShut::ClientShut()
{
    m_socket = new QTcpSocket();
}

ClientShut::~ClientShut()
{
    delete this->m_socket;
}

int ClientShut::Tcp_socket_connect(QString IP)
{
    int port = 9090;
//    IP = "target2";

    //取消已有的连接
    m_socket->abort();
    //连接服务器
    m_socket->connectToHost(IP, port);

     //等待连接成功
    if(!m_socket->waitForConnected(3000))
    {
         qDebug() << "Connection failed!";
         m_socket->disconnect();
         return -1;
     }
     qDebug() << "Connect successfully!";
     return 0;

}

void ClientShut::Tcp_socket_disconnect(){
    m_socket->disconnectFromHost();
}

int ClientShut::Tcp_socket_Send(char* buff){

    int txlen = m_socket->write(buff);
    m_socket->flush();
    qDebug() << "Send the Command!";
    return txlen;
}

int ClientShut::Tcp_socket_Receive(){
    QByteArray ba;
        //读取缓冲区数据
    ba = m_socket->readAll();
    qDebug() << "Receive from the server:";
    qDebug() << QString(ba.data());
    if(QString(ba.data()) == "server rcv ok")
    {
 //           qDebug() << "Receive from Sever";
         m_socket->disconnect();
         return 0;
    }

    else
        return -1;
}

调试的时候发现客户端发送命令后,服务器端并没有反应,需要等到客户端程序关闭。找找资料,才知道原来write并不会直接把数据发送出去,而要等到缓冲满或其他条件,所以这里加了一个flush,可以即时发送。

2.main

#include <QCoreApplication>
#include "clientshut.h"
//#include <iostream>
#include <windows.h>
#include <QTextStream>
//using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ClientShut *Me = new ClientShut();

    QTextStream cin(stdin, QIODevice::ReadOnly);
    QTextStream cout(stdout, QIODevice::WriteOnly);
    QTextStream cerr(stderr, QIODevice::WriteOnly);

    QString Remcmd = "";
    QString Servers="";
    cout<<"Enter shutdown command NO.:"<<Qt::endl;
    while(1)
    {
        cout<<"1.shutdown -h now"<<Qt::endl;
        cout<<"2.shutdown -H now"<<Qt::endl;
        cout<<"3.shutdown -r now"<<Qt::endl;
        QString cmdNo = cin.readLine();
        if(cmdNo.isValidUtf16())
        {   int tmpNo = cmdNo.toInt();
            if (tmpNo==1){
                Remcmd = "shutdown -h now";
                break;
            }
            else if(tmpNo==2){
                Remcmd = "shutdown -H now";
                break;
            }
            else if(tmpNo==3){
                Remcmd = "shutdown -r now";
                break;
            }
            else
                printf("Enter the right NO. please:\n");

        }
        else
            printf("Select and Enter the cmomand NO. please:\n");
    }

    cout<<"Enter the Servers name:"<<Qt::endl;
    Servers = cin.readLine();
    QStringList serverList = Servers.split(QRegExp("\\s+"));
//    for(int i = 0; i<serverList.length();i++)
//        cout<<serverList[i]<<Qt::endl;

//    QString Server = "192.168.2.162";
    printf("Start...\n");
//    cout<<"Start...\n"<<Qt::endl;

    for(int i = 0; i<serverList.length();i++)
    {

        QString Server = serverList[i];

        int Connect = Me->Tcp_socket_connect(Server);
        if(!Connect)
        {
            QByteArray ba= Remcmd.toLatin1();
//            char* cmd= "shutdown";
            char* cmd;
            cmd = ba.data();
            int lenTx = Me->Tcp_socket_Send(cmd);
            if(lenTx > 0)
                 qDebug() << "Send sucessfully!";
            else
                qDebug() << "Send failed!";

            cout<<"shutdown " + Server + " now!"<<Qt::endl;

        }
        else
           cout<<"cann't connect " + Server + " !"<<Qt::endl;

        Me->Tcp_socket_disconnect();
    }
    delete Me;
    printf("Complete!\n");
//    cout<<"Complete!\n";
    return a.exec();
//    return 0;
}

四、配置服务自启动

服务器端的服务程序应随系统自启动,这里使用service服务实现。
写一个rem-servershut.service文件:

[Unit]
Description=Remote target shutdowN server
After=network.target

[Service]
Type=simple
ExecStart=/home/xxx/RemShutdown/main_tcp_server
User=root
Restart=always

[Install]
WantedBy=multi-user.target

将文件放在/etc/systemd/system/中,使用
systemctl enable rem-servershut.service
命令用于设置开机自启服务。
使用

systemctl start rem-servershut.service

可直接启动相应的服务程序。

运行结果

运行结果如下,多台服务器轻松关闭:
在这里插入图片描述

后续

后续把客户端的服务程序打包成安装文件,客户端试试多线程。

参考

linux TCP编程示例
Linux系统之service创建

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值