項(xiàng)目地址:Academy remote system: 一種不需要客戶(hù)端ip的命令行遠(yuǎn)程工具 - Gitee.com
項(xiàng)目介紹:
傳統(tǒng)的遠(yuǎn)程命令行工具如ssh,scp都需要目標(biāo)服務(wù)器的ip才可以連接。
我設(shè)計(jì)的這款命令行遠(yuǎn)程工具可以基于多個(gè)中間服務(wù)器進(jìn)行遠(yuǎn)程,而不需要設(shè)置目標(biāo)ip。
部分代碼(20240317年更新)
academy_client-aca.c:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-841889.html
#include <stdio.h>
#include "yamlreader.h"
#include "codereader.h"
#include <string.h>
//#define DEBUGMODE
void show_copyright(void){
printf("@copyright2024 Anchengan\n");
}
void show_help(void){
printf("Help document for aca software:\n");
printf("aca [authkey of remote client] [path to settings.yaml] [password of remote client]\n");
printf("aca listenmode [path to settings.yaml]\n");
}
int is_path_in_ld_library_path(const char *path_to_check) {
const char *ld_library_path = getenv("LD_LIBRARY_PATH");
if (ld_library_path == NULL) {
// 如果LD_LIBRARY_PATH未設(shè)置,則直接返回0(不在其中)
return 0;
}
// 分割LD_LIBRARY_PATH并檢查每個(gè)路徑
char *path_copy = strdup(ld_library_path); // 復(fù)制環(huán)境變量值
char *token = strtok(path_copy, ":");
while (token != NULL) {
// 比較當(dāng)前路徑和要檢查的路徑
if (strcmp(token, path_to_check) == 0) {
free(path_copy); // 釋放內(nèi)存
return 1; // 找到路徑,返回1
}
token = strtok(NULL, ":"); // 繼續(xù)查找下一個(gè)路徑
}
free(path_copy); // 釋放內(nèi)存
return 0; // 未找到路徑,返回0
}
char* remove_char(const char* str, char c) {
int count = 0;
for (const char* p = str; *p; p++) {
if (*p != c) {
count++;
}
}
// 分配足夠的空間來(lái)存儲(chǔ)新字符串
char* result = (char*)malloc(count + 1); // +1 為 '\0'
if (!result) {
return NULL; // 內(nèi)存分配失敗
}
int i = 0;
for (const char* p = str; *p; p++) {
if (*p != c) {
result[i++] = *p;
}
}
result[i] = '\0'; // 確保新字符串以 '\0' 結(jié)尾
return result;
}
int main(int argc, char *argv[]) {
// 打印傳遞的參數(shù)
if(argc-1==0){
show_copyright();
printf("Enter -h or --help after aca for help.\n");
printf("Example:\naca -h\naca --help\n");
return 0;
}
for(int i=1;i<=argc-1;i++){
if(strcmp(argv[i],"-h")==0 || strcmp(argv[i],"--help")==0){
show_copyright();
show_help();
return 0;
}
}
if(argc-1>3){
printf("Unknown usage of aca...\n");
show_help();
return 0;
}
int yamllength=strlen(argv[2]);
if(yamllength<5 || argv[2][yamllength-5]!='.' || argv[2][yamllength-4]!='y' || argv[2][yamllength-3]!='a' || argv[2][yamllength-2]!='m' || argv[2][yamllength-1]!='l'){
printf("Please check your path to settings.yaml!\n");
printf("Example:./settings.yaml\n");
show_help();
return 0;
}
int islistenmode=0;
if (strcmp(argv[1],"listenmode")==0){
if(argc-1>2){
printf("Unknown usage of aca...\n");
show_help();
return 0;
}
printf("listenmode setup successfully...\n");
islistenmode=1;
}else{
printf("your authkey of remote client is:%s\n",argv[1]);
}
printf("setting env...\n");
int env_return_value;
const char *path_to_check = "./"; // 要檢查的路徑
const char *bashrc_path = getenv("HOME"); // 獲取用戶(hù)主目錄
if (bashrc_path == NULL) {
perror("Error getting HOME environment variable");
return EXIT_FAILURE;
}
// 拼接.bashrc文件的完整路徑
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s/.bashrc", bashrc_path);
// 打開(kāi).bashrc文件
FILE *file = fopen(full_path, "r");
if (file == NULL) {
perror("Error opening ~/.bashrc");
return EXIT_FAILURE;
}
// 要搜索的內(nèi)容
const char *search_content = "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./";
char line[1024]; // 假設(shè)每行不會(huì)超過(guò)1023個(gè)字符
// 逐行讀取并搜索內(nèi)容
int found = 0; // 標(biāo)記是否找到內(nèi)容
while (fgets(line, sizeof(line), file)) {
if (strstr(line, search_content) != NULL) {
#ifdef DEBUGMODE
printf("Found the content in ~/.bashrc: %s", line);
#endif
found = 1; // 找到內(nèi)容,設(shè)置標(biāo)記
break; // 如果只需要找到一次就退出循環(huán)
}
}
// 關(guān)閉文件
fclose(file);
if (!is_path_in_ld_library_path(path_to_check) && !found) {
// 使用system()函數(shù)運(yùn)行命令行命令
env_return_value = system("echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./' >> ~/.bashrc");
// 檢查命令的退出碼
#ifdef DEBUGMODE
if (env_return_value == -1) {
// system()函數(shù)調(diào)用失敗
// 在這種情況下,你可以查看errno來(lái)獲取錯(cuò)誤詳情(需要包含errno.h頭文件)
perror("system() failed");
} else if (WIFEXITED(env_return_value)) {
// 命令正常退出,WEXITSTATUS(env_return_value)可以獲取命令的退出狀態(tài)
printf("Command exited with status %d\n", WEXITSTATUS(env_return_value));
} else if (WIFSIGNALED(env_return_value)) {
// 命令因?yàn)榻邮盏叫盘?hào)而終止,WTERMSIG(env_return_value)可以獲取信號(hào)的編號(hào)
printf("Command terminated by signal %d\n", WTERMSIG(env_return_value));
}
#endif
printf("env set successfully...\n");
printf("please run: source ~/.bashrc\n");
return 0;
}else if(!is_path_in_ld_library_path(path_to_check) && found){
printf("please run: source ~/.bashrc\n");
return 0;
}
#include "libsender.h"
#include "libreceiver.h"
printf("your path to settings.yaml is:%s\n",argv[2]);
printf("Reading settings.yaml...\n");
struct item_ret* yaml_data = get_item(argv[2]);
struct ip* ip_reader;
struct port* port_reader;
ip_reader=yaml_data->ip_items;
port_reader=yaml_data->port_items;
char mac_device[20];
char c = ':';
strcpy(mac_device,yaml_data->mac_device);
int iplength = 0;
struct ip* ip_pin = ip_reader;
while (ip_pin != NULL) {
iplength++;
ip_pin = ip_pin->next;
}
char send_ip_info[iplength*100];
char send_port_info[iplength*100];
while (ip_reader != NULL){
printf("ip:%s\n", ip_reader->ip);
strcat(send_ip_info,ip_reader->ip);
strcat(send_ip_info,"-");
ip_reader = ip_reader->next;
for(int i=0;i<2;i++){
printf("port:%s\n", port_reader->port);
strcat(send_port_info,port_reader->port);
strcat(send_port_info,"-");
port_reader = port_reader->next;
}
}
printf("settings.yaml read completed...\n");
if(islistenmode){
//waiting for connection...
printf("Getting connecting code of this device...\n");
struct device_ret* device_data=get_device_code(mac_device);
char* device_code=device_data->mac_device;
char* address_code=device_data->mac_address;
printf("Connecting code of this device is:%s\n",device_code);
char* password = remove_char(address_code, c);
printf("Your password is:%s\n",password);
Receiver(device_code,password,send_ip_info,send_port_info);
}else{
Sender(argv[1],argv[3],send_ip_info,send_port_info);
//connecting...
}
return 0;
}
academy_server-acade.go:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-841889.html
package main
import (
"fmt"
"bufio"
"net"
"sync"
"io/ioutil"
"log"
"os"
"strconv"
"gopkg.in/yaml.v2"
)
type client struct {
conn net.Conn
connid string
name string
messages chan string
}
type Message struct {
conn net.Conn
connid string
SenderName string
Content string
}
var (
entering = make(chan client)
leaving = make(chan client)
messages = make(chan Message) // 所有接收的消息
)
type Config struct {
Database struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Port2 int `yaml:"port2"`
} `yaml:"database"`
}
func broadcast() {
clients := make(map[string]client) // 鍵是客戶(hù)端的名稱(chēng),值是客戶(hù)端結(jié)構(gòu)體實(shí)例
for {
select {
case msg := <-messages:
// 將消息廣播給除了發(fā)送者以外的所有客戶(hù)端
for _,cli := range clients {
if cli.name != msg.SenderName && cli.connid==msg.connid {
cli.messages<- msg.Content
}
}
case newClient := <-entering:
clients[newClient.name] = newClient
case leavingClient := <-leaving:
delete(clients, leavingClient.name)
close(leavingClient.messages)
}
}
}
func handleConn(conn net.Conn,connid string) {
input := bufio.NewScanner(conn)
var wg sync.WaitGroup
// 創(chuàng)建一個(gè)新的客戶(hù)端
ch := make(chan string,1) // 客戶(hù)端的消息通道
go clientWriter(conn, ch)
cli := client{conn: conn, connid:connid,name: conn.RemoteAddr().String(), messages: ch}
entering <- cli
fmt.Println(cli.name)
wg.Add(1)
go func() {
defer wg.Done()
for input.Scan() {
messages <-Message{SenderName: cli.name, Content: input.Text(),conn:conn,connid:connid} // cli.name + ": " + input.Text()
_, err := conn.Write([]byte("Received your message\n"))
if err != nil {
fmt.Println("Error writing to connection:", err.Error())
break
}
}
}()
wg.Wait()
leaving <- cli
conn.Close()
}
func clientWriter(conn net.Conn, ch <-chan string) {
for msg := range ch {
fmt.Fprintln(conn, msg) // 注意:網(wǎng)絡(luò)寫(xiě)入應(yīng)該有錯(cuò)誤處理
}
}
func main() {
argCount := len(os.Args) - 1
if argCount == 0 {
fmt.Println("沒(méi)有傳遞任何參數(shù)。")
fmt.Println("acade -h")
fmt.Println("acade --help")
os.Exit(1) // 使用非零狀態(tài)碼退出,表示錯(cuò)誤
}
// 如果參數(shù)數(shù)量不符合預(yù)期(例如,你需要恰好2個(gè)參數(shù)),提前返回
if argCount != 1 {
fmt.Printf("需要1個(gè)參數(shù),但傳遞了%d個(gè)參數(shù)。\n", argCount)
os.Exit(1) // 使用非零狀態(tài)碼退出,表示錯(cuò)誤
}
yamlfilename:=os.Args[1]
if yamlfilename=="-h" || yamlfilename=="--help"{
fmt.Println("acade [path to settings.yaml]")
os.Exit(0)
}
// 讀取YAML文件內(nèi)容
yamlFile, err := ioutil.ReadFile(yamlfilename)
if err != nil {
log.Fatalf("無(wú)法讀取YAML文件: %v", err)
}
// 解析YAML內(nèi)容
var config Config
err = yaml.Unmarshal(yamlFile, &config)
if err != nil {
log.Fatalf("無(wú)法解析YAML內(nèi)容: %v", err)
}
// 輸出解析后的內(nèi)容
fmt.Printf("Host: %s\n", config.Database.Host)
fmt.Printf("Port: %d\n", config.Database.Port)
fmt.Printf("Port2: %d\n", config.Database.Port2)
Host:=config.Database.Host
Port:=strconv.Itoa(config.Database.Port)
Port2:=strconv.Itoa(config.Database.Port2)
listener, err := net.Listen("tcp",Host+":"+Port)
if err != nil {
fmt.Println(err)
return
}
listener2, err2 := net.Listen("tcp",Host+":"+Port2)
if err2 != nil {
fmt.Println(err2)
return
}
go broadcast()
go func(){
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
continue
}
go handleConn(conn,"1")
}
}()
go func(){
for{
conn2, err2 := listener2.Accept()
if err2 != nil {
fmt.Println(err2)
continue
}
go handleConn(conn2,"2")
}
}()
for{}
// 程序正常執(zhí)行完畢,使用零狀態(tài)碼退出
os.Exit(0)
}
到了這里,關(guān)于一種不需要客戶(hù)端ip的命令行遠(yuǎn)程工具的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!