ubantu端使用命令直接在Windows端打开文件或目录

思路:ubantu通过IP地址以及指定端口向Windows端发送命令,Windows端用python脚本监听端口变化,收到ubantu发来的指令后去执行对应指令。因为本人从事Linux、android底层驱动工作,实现该功能的代码主要是面相过程的风格。
1、ubantu端,将要打开的文件或目录的路径转化为Windows端能识别并访问的路径,具体代码实现如下:


#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

char shell_cmd(char *cmd, char *cmd_result)
{
	FILE *fp = NULL;
	char result[1024] = {0};

	if(cmd_result != NULL){
		fp = popen(cmd, "r");
		if(fp == NULL){
			printf("Failed to run command %s
", cmd);
			return -1;
		}
		// 读取命令输出
		while (fgets(result, sizeof(result), fp) != NULL);
		// 关闭管道
		pclose(fp);
		fp = NULL;
		memcpy(cmd_result, result, strlen(result)-1);		
	}else{
		//system("curl -d "explorer.exe \\\\192.168.1.162\lxx\lxx_test" http://192.168.1.83:8080 > /dev/null 2>&1");
		system(cmd);
	}

	return 0;
}

int main(int argc, char const *argv[])
{
	int ret = -1;
	char windows_ip[1024] = {0};
	char ubantu_ip[1024] = {0};
	char file_path[1024] = {0};
	//char samba_path[1024] = {0};
	char new_path[1024] = {0};
	char open_path[1024] = {"\\"};
	char curl_cmd[1024] = {0};
	struct stat path_stat;

	//printf("argc:%d
", argc);
	//if(argv[1] != NULL)
	//	printf("argv:%s len:%lu
", argv[1], strlen(argv[1]));

	ret = shell_cmd("echo $SSH_CLIENT | awk '{print $1}'", windows_ip);
	if(ret)
		printf("get windows_ip Failed
");
	//printf("windows_ip:%s len:%lu
", windows_ip, strlen(windows_ip));

	ret = shell_cmd("ifconfig | awk '/inet 192/ {print $2}'", ubantu_ip);
	if(ret)
		printf("get ubantu_ip Failed
");
	//printf("ubantu_ip:%s len:%lu
", ubantu_ip, strlen(ubantu_ip));

	ret = shell_cmd("echo "$PWD" | sed 's|/[^/]*/|/|'", new_path);
	if(ret)
		printf("get new_path Failed
");
	//printf("new_path:%s len:%lu
", new_path, strlen(new_path));

	ret = shell_cmd("echo "$PWD"", file_path);
	if(ret)
		printf("get file_path Failed
");
	//printf("file_path:%s len:%lu
", file_path, strlen(file_path));

	//samba_path = shell_cmd("awk "/$USER/" /etc/samba/smb.conf | sed -n '/path/p' | awk '{print $3}'", samba_path);
	//if(ret)
	//	printf("get samba_path Failed
");
	//printf("samba_path:%s len:%lu
", samba_path, strlen(samba_path));

	strcat(open_path, ubantu_ip);
	strcat(open_path, new_path);
	if(argv[1] != NULL){
		if(argv[1][0] == '.' && argv[1][1] == '/'){
			sprintf(open_path + strlen(open_path), "/%s", &argv[1][2]);
			sprintf(file_path + strlen(file_path), "/%s", &argv[1][2]);			
		}else{
			sprintf(open_path + strlen(open_path), "/%s", argv[1]);
			sprintf(file_path + strlen(file_path), "/%s", argv[1]);
		}
	}

	for (int i = 0; i < strlen(open_path); ++i){
		if(open_path[i] == '/')
			open_path[i] = '\';
	}
	//printf("
###open_path###: %c
", open_path[strlen(open_path)-1]);
	if(open_path[strlen(open_path)-1] == '\')
		open_path[strlen(open_path)-1] = ' ';

	printf("########################################################################
");
	if(stat(file_path, &path_stat) == 0){
		if(S_ISDIR(path_stat.st_mode)){//文件夹
			printf("
###打开目录###: %s
", open_path);
			sprintf(curl_cmd, "%s%s%s%s%s", "curl -d "\\", open_path,"" http://", windows_ip, ":6666 > /dev/null 2>&1");
			//printf("
###curl_cmd###: %s
", curl_cmd);
		}else{//文件
			printf("
###打开文件###: %s
", open_path);
			sprintf(curl_cmd, "%s%s%s%s%s", "curl -d "\\", open_path,"" http://", windows_ip, ":6666 > /dev/null 2>&1");
			//printf("
###curl_cmd###: %s
", curl_cmd);
		}
		ret = shell_cmd(curl_cmd, NULL);
		if(ret)
			printf("curl_cmd Failed
");
	}else{
		perror("无法获取状态,请检查路径是否正确");
	}
	printf("
########################################################################
");

	return 0;
}

2、文件命名为fw.c,在ubantu上将fw.c编译成可执行文件,对应命令如下


gcc -o fw fw.c

3、这一步主要针对uabntu 没有root操作权限的同学,在当前用户根目录下创建.bashrc和.profile两个文件,.profile主要是在登录时候去引导执行.bashrc内的命令,.bashrc中主要是将我们的fw命令全局到当前用户,不需要每次执行都要加上fw命令的路径
.profile文件内容:


# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
    PATH="$HOME/.local/bin:$PATH"
fi

.bashrc内容:主要是添加alias fw=‘~/bin/fw’,fw命令也需要放到对应路径,不然找不到


# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar

# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;
esac

# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
        # We have color support; assume it's compliant with Ecma-48
        # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
        # a case would tend to support setf rather than setaf.)
        color_prompt=yes
    else
        color_prompt=
    fi
fi

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}[33[01;32m]u@h[33[00m]:[33[01;34m]w[33[00m]$ '
else
    PS1='${debian_chroot:+($debian_chroot)}u@h:w$ '
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="[e]0;${debian_chroot:+($debian_chroot)}u@h: wa]$PS1"
    ;;
*)
    ;;
esac

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
    #alias dir='dir --color=auto'
    #alias vdir='vdir --color=auto'

    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi

# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'

# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias fw='~/bin/fw'

# Add an "alert" alias for long running commands.  Use like so:
#   sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '''s/^s*[0-9]+s*//;s/[;&|]s*alert$//''')"'

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

export JAVA_HOME=/opt/jdk1.6.0_45   
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export LC_ALL="en_US.UTF-8"
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

2、Windows端,监听端口并解析收到的命令,并执行收到的命令。cmd命令行直接输入python,如果电脑不支持python命令,可以在弹出的窗口直接安装就行
python脚本代码:


import os
import time
import ctypes
import socket
import logging
import threading
import subprocess

from datetime import datetime
from pathlib import Path

LOG_FILE = "D:\logs\logcat\python.log"

class PortListener:
    def __init__(self, host='0.0.0.0', port=6666):
        self.host = host
        self.port = port
        self.running = False
        self.server_socket = None
        
    def start_listening(self):
        """启动端口监听服务"""
        try:
            # 创建TCP socket
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            
            # 绑定地址和端口
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)
            self.running = True
            logging.info("####日志系统初始化成功")
            logging.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 开始监听端口 {self.port}")
            
            while self.running:
                try:
                    # 接受客户端连接
                    client_socket, client_address = self.server_socket.accept()
                    logging.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 客户端连接: {client_address}")
                    
                    # 为每个客户端创建新线程处理
                    client_thread = threading.Thread(
                        target=self.handle_client, 
                        args=(client_socket, client_address)
                    )
                    client_thread.daemon = True
                    client_thread.start()
                    
                except socket.error:
                    if self.running:
                        continue
                    break
                    
        except Exception as e:
            logging.info(f"监听端口时发生错误: {e}")
        finally:
            self.stop_listening()

    def handle_client(self, client_socket, client_address):
        """处理客户端连接"""
        try:
            # 接收客户端数据
            data = client_socket.recv(1024)
            if data:
                message = data.decode('utf-8')
                logging.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 来自 {client_address} 的消息: {message}")
                lines = data.splitlines()  # 按行分割为列表
                line_count = len(lines)    # 行数统计
                last_line = lines[-1] if lines else ""  # 安全获取最后一行
                path = last_line.decode('utf-8')
                logging.info(path)
                if os.path.exists(path):
                    if os.path.isfile(path):
                        logging.info(f"打开文件:{path}")
                        subprocess.run(['D:\wake_apk\SublimeText3\sublime_text.exe', path])
                    elif os.path.isdir(path):
                        logging.info(f"打开目录:{path}")
                        os.startfile(path)
                    else:
                        logging.info(f"未知路径")
                else:
                    logging.info(f"路径不存在")

                # 发送响应
                response = f"服务器已收到消息: {message}"
                client_socket.send(response.encode('utf-8'))
                
        except Exception as e:
            logging.info(f"处理客户端 {client_address} 时发生错误: {e}")
        finally:
            client_socket.close()
    
    def stop_listening(self):
        """停止监听服务"""
        self.running = False
        if self.server_socket:
            self.server_socket.close()
        logging.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 已停止监听端口 {self.port}")

# 初始化日志
def setup_logger():
    try:
        log_path = Path(LOG_FILE)
        log_path.parent.mkdir(parents=True, exist_ok=True)  # 自动创建日志目录
        
        logging.basicConfig(
            filename=str(log_path),
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        logging.info("日志系统初始化成功")
    except PermissionError as e:
        print(f"权限错误: {e}
请检查日志目录写入权限")
    except Exception as e:
        print(f"日志初始化失败: {e}")

if __name__ == "__main__":
    ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)  # 隐藏窗口
    setup_logger()
    # 创建监听器实例
    listener = PortListener(port=6666)
    # 在后台线程中启动监听
    listener_thread = threading.Thread(target=listener.start_listening)
    listener_thread.daemon = True
    listener_thread.start()
    
    logging.info("端口监听服务已启动,按Ctrl+C停止...")
    
    try:
        # 主线程保持运行
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        logging.info("
正在停止服务...")
        listener.stop_listening()

python脚本需要设置成开机启动,具体方法可以直接百度,以下方法可做参考:


创建基本任务‌
按 Win+R 输入 taskschd.msc 打开任务计划程序
操作步骤:
‌触发器‌:选择"登录时"(所有用户或特定用户)
‌操作‌:
程序/脚本:pythonw.exe(无窗口模式)
参数:脚本绝对路径(如 D:scriptmain.py)
‌条件‌:取消勾选"只有在计算机使用交流电源时才启动"
‌设置‌:勾选"如果任务失败,重新启动"

将编写好的python脚本放到C:UsersAdministratorAppDataRoamingMicrosoftWindowsStart MenuProgramsStartup下能达到开机运行的效果
还可以编写一个vbs脚本放到C:UsersAdministratorAppDataRoamingMicrosoftWindowsStart MenuProgramsStartup下也能达到开机启动效果

vbs脚本:


Set wshShell = WScript.CreateObject("WScript.Shell")
wshShell.Run "D:wake_apkPythonFilePythonFile.py", 1, True

注:使用过程中发现问题会持续更新优化!!!

© 版权声明

相关文章

暂无评论

none
暂无评论...