65.9K
CodeProject 正在变化。 阅读更多。
Home

如何远程复制文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (22投票s)

2010年1月13日

CPOL

4分钟阅读

viewsIcon

84069

downloadIcon

4152

使用套接字远程复制文件的两个应用程序。

RemoteCopyFiles

引言

我们在工作中有许多,许多服务器。SQL Server、Oracle等企业级应用程序由系统管理员安装在其中。但是,当我们(开发人员)创建新应用程序或新组件时,我们必须将新的程序集部署到每个服务器上。我们不喜欢这样做,我们讨厌这样做,所以我尝试制作一个应用程序,使其任务对我们来说更轻松……

背景

有两个应用程序。它们都使用套接字进行通信,并传输文件名和数据。这些是应用程序

ReceiveFiles

这是一个监听新请求的控制台应用程序。当发送请求到服务器时,此应用程序会接收它并将文件复制到所需的最终路径。这不是一个一直监听的 Windows 服务。我稍后会解释如何远程启动此程序。

SendFiles

这是一个具有简单 GUI 的 Windows 应用程序,用于启动远程 ReceiveFiles 应用程序并发送文件到服务器。

PsExec

PsExec 是一个 Windows 应用程序,您可以使用它来启动远程进程。它用于远程启动 ReceiveFiles。我无法在此处附加它,因为这是禁止的。但您可以从这里免费下载:http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx

如何使用

  1. 将 ReceiveFiles 复制到您想要部署文件的服务器上。如果运气好的话,这将是您最后一次需要自己复制任何东西。
  2. 您必须从 Microsoft 网页下载 PsExec,才能远程启动 ReceiveFiles。下载后,您必须将 PsExec 复制到 SendFiles 安装的同一路径下。
  3. 在配置文件中填入服务器名称、用户名和密码。
  4. 启动 SendFiles 应用程序。在第一个文本框“ReceiveFile 所在路径…”中,您必须输入 ReceiveFiles 已安装的远程路径。建议所有机器上的路径都相同。
  5. 选择所需的服务器,然后单击“启动远程监听器”以启动远程 ReceiveFiles 应用程序。
  6. 一旦远程应用程序启动(您可以在 MS DOS 窗口中检查),您就可以通过单击“获取文件”按钮选择要复制的文件。选择您想要的。
  7. 单击“发送文件”按钮将选定的文件复制到所有服务器。
  8. 进程完成后,您可以单击“关闭远程监听器”来关闭远程应用程序。

就这样了...

使用代码

代码是对网络上找到的一些代码的修改;到目前为止,它运行正常!

一旦 ReceiveFiles 应用程序启动,它将打开两个套接字无限循环,直到应用程序被手动关闭或收到关闭请求。

第一个套接字由 ReceiveFilename 方法打开。它将等待文件名和路径来启动进程。当接收到数据(文件名)时,它将在路径不存在的情况下创建该路径。稍后,ReceiveFile 方法将打开另一个套接字以等待二进制数据,即文件的内容。文件创建后,它将等待任何其他请求。如果文件名是“CLOSE APP”,应用程序将关闭,因为这是远程关闭应用程序的方式。

ReceiveFiles 应用程序的核心是

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace RecepcionFicherosSocket
{
    public class SocketsFileTransfer
    {
        private const string STRING_TO_CLOSE = "CLOSE APP";
        public void ReceiveFile(int port, string filepathandname)
        {
            string methodname = "ReceiveFile";
            try
            {
                IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, port);
                Socket sock = new Socket(AddressFamily.InterNetwork, 
                                  SocketType.Stream, ProtocolType.IP);
                sock.Bind(ipEnd);
                sock.Listen(1);
                Socket serverSocket = sock.Accept();
                byte[] data = new byte[1000000];
                int received = serverSocket.Receive(data);
                int filenameLength = BitConverter.ToInt32(data, 0);
                string filename = Encoding.ASCII.GetString(data, 4, filenameLength);
                this.CreateDirectoryFromPath(filepathandname);
                BinaryWriter bWrite = new BinaryWriter(
                              File.Open(filepathandname, FileMode.Create));
                bWrite.Write(data, filenameLength + 4, received - filenameLength - 4);
                int received2 = serverSocket.Receive(data);
                while (received2 > 0)
                {
                    bWrite.Write(data, 0, received2);
                    received2 = serverSocket.Receive(data);
                }
                bWrite.Close();
                serverSocket.Close();
                sock.Close();
                MyLogs.WriteLog(methodname, "File copied ok: " + 
                                filepathandname, false);
            }
            catch (Exception ex)
            {
                MyLogs.WriteLog(methodname, "Port: " + port + 
                                " file: " + filepathandname + 
                                " " + ex.ToString(), true);
            }
        }
        
        public string ReceiveFilename(IPAddress ipAddress, int port)
        {
            string filename = string.Empty;
            string methodname = "ReceiveFilename";
            try
            {
                
                TcpListener tcpListener = new TcpListener(ipAddress, port);
                //Starting the listening
                tcpListener.Start();
                //Wait for a client
                Socket socketForClient = tcpListener.AcceptSocket();
                if (socketForClient.Connected)
                {       
                    // If connected
                    MyLogs.WriteLog(methodname,"Connected",false);
                    NetworkStream networkStream = new NetworkStream(socketForClient);
                    StreamWriter streamWriter = new StreamWriter(networkStream);
                    StreamReader streamReader = new StreamReader(networkStream);            
                    string theString = "Ok so far";
                    //Wait for the client request
                    filename = streamReader.ReadLine();
                    MyLogs.WriteLog(methodname,theString + 
                                    " " + filename,false);
                    //Answering the client
                    streamWriter.WriteLine(theString);
                    streamWriter.Flush();
                    //Close
                    streamReader.Close();
                    streamWriter.Close();
                    networkStream.Close();
                    socketForClient.Close();
                    tcpListener.Stop();
                    //If the client has requested the close of the server
                    if (filename == STRING_TO_CLOSE)
                    {
                        MyLogs.WriteLog(methodname, "Closing requested", false);
                        Environment.Exit(999);
                    }
                }
            }
            catch (Exception ex)
            {
                MyLogs.WriteLog("ReceiveFilename", ex.ToString(), true);
            }
            return filename;
        }
        public IPAddress GetIpFromHostName(string servername)
        {
            IPAddress ip = null;
            String strHostName = string.Empty;
            if (servername == string.Empty)
            {
                strHostName = Dns.GetHostName();
                MyLogs.WriteLog("GetIpFromHostName", 
                       "Machine name: " + strHostName,false);
            }
            else
            {
                strHostName = servername;
            }
            // Then using host name, get the IP address list..
            IPHostEntry ipEntry = Dns.GetHostByName(strHostName);
            IPAddress[] addr = ipEntry.AddressList;
            ip = addr[0];
            return ip;
        }
        private void CreateDirectoryFromPath(string path)
        {
            string directoryPath = System.IO.Path.GetDirectoryName(path);
            if (Directory.Exists(directoryPath) == false)
            {
                try
                {
                    Directory.CreateDirectory(directoryPath);
                    MyLogs.WriteLog("CreateDirectoryFromPath", 
                                    "Directory: " + directoryPath + 
                                    " created", false);
                }
                catch (Exception ex)
                {
                    MyLogs.WriteLog("CreateDirectoryFromPath", 
                          "Cant create directory for: " + path + 
                          " " + ex.ToString(), true);
                }
            }
        }
    }
}

ReceiveFiles 应用程序的主要重点将是应用程序的非停止执行,直到它被关闭或收到关闭请求。

ReceiveFiles 应用程序的主要重点是

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace RecepcionFicherosSocket
{
    class Program
    {
        static void Main(string[] args)
        {
            ReceiveFiles ns = new ReceiveFiles();
            SocketsFileTransfer sft = new SocketsFileTransfer();
            ReceiveFiles.ipAddress = sft.GetIpFromHostName(string.Empty);
            ns.Start();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace RecepcionFicherosSocket
{
    public class ReceiveFiles
    {
        public static IPAddress ipAddress;
        public void Start()
        {
            SocketsFileTransfer sockets = new SocketsFileTransfer();
            
            //The file names are received from 9999 port
            int port = 9999;
            string filename = sockets.ReceiveFilename(ipAddress, port);
            //The file data is received from 9998 port
            port = 9998;
            sockets.ReceiveFile(port, filename);
            MyLogs.WriteLog("Start","Process finished",false);
            //Start the process again
            this.Start();
        }
    }
}

SendFiles 应用程序使用两个套接字(与 ReceiveFiles 相同数量)来发送文件名和文件数据(二进制)。首先,它会将文件名发送到远程应用程序并等待 ReceiveFile 的确认。一旦收到确认,文件将以二进制模式打开,数据将被读取并通过另一个套接字发送到 ReceiveFiles。

SendFiles 应用程序的核心是

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace SendFiles
{
    public class SocketsFileTransfer
    {
        private const string STRING_TO_CLOSE = "CLOSE APP";
        public void SendFileName(string server, int port, string filename)
        {
            TcpClient socketForServer;
            try
            {
                //Creamos un TcpCliente y le pasamos el server y el puerto.
                socketForServer = new TcpClient(server, port);
            }
            catch (Exception ex)
            {
                Console.WriteLine("No se pudo conectar a " + port + 
                                  ":" + server + " " + ex.ToString());
                return;
            }//aqui es lo mismo que en el server. Usamos StreamWriter y Reader.
            NetworkStream networkStream = socketForServer.GetStream();
            StreamReader streamReader = new System.IO.StreamReader(networkStream);
            StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
            try
            {
                streamWriter.WriteLine(filename);
                streamWriter.Flush();
                string outputString = streamReader.ReadLine();
                Console.WriteLine(outputString);
            }
            catch
            {
                Console.WriteLine("Exception reading from Server");
            }
            finally
            {
                networkStream.Close();
            }
        }
        public void SendFile(IPAddress ipAddress, int port, string filenameToUse)
        {
            //send file:
            IPEndPoint ipEnd = new IPEndPoint(ipAddress, port);
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, 
                                             SocketType.Stream, ProtocolType.IP);
            filenameToUse = filenameToUse.Replace("\\", "/");
            byte[] filenameData = Encoding.ASCII.GetBytes(filenameToUse);
            byte[] output = new byte[4 + filenameData.Length];
            BitConverter.GetBytes(filenameData.Length).CopyTo(output, 0);
            filenameData.CopyTo(output, 4);
            clientSocket.Connect(ipEnd);
            clientSocket.SendFile(filenameToUse, output, null, 
                                  TransmitFileOptions.UseDefaultWorkerThread);
            clientSocket.Close();
        }
        public IPAddress GetIpFromHostName(string servername)
        {
            IPAddress ip = null;
            String strHostName = string.Empty;
            if (servername == string.Empty)
            {
                strHostName = Dns.GetHostName();
                MyLogs.WriteLog("GetIpFromHostName", 
                                "Machine name: " + strHostName, false);
            }
            else
            {
                strHostName = servername;
            }
            // Then using host name, get the IP address list..
            IPHostEntry ipEntry = Dns.GetHostByName(strHostName);
            IPAddress[] addr = ipEntry.AddressList;
            ip = addr[0];
            return ip;
        }
    }
}

在发送文件之前,手动逐个服务器启动远程 ReceiveFiles 应用程序将会非常麻烦。因此,我使用 Microsoft PsExec 应用程序来远程启动 ReceiveFiles。基本上,我使用 Process 类来启动 PsExec 并传递必要的命令参数以在远程服务器上启动 ReceiveFiles。

Send 方法会循环遍历每个文件,并调用 SendFileNameSendFile 来传输数据。

Close 方法发送一个特殊消息作为文件名(“CLOSE APP”)以请求 ReceiveFiles 应用程序关闭;此处不需要 PsExec,因为之前已经建立了两个应用程序之间的通信。

现在让我们看看如何远程启动 ReceiveFiles 应用程序,发送文件,然后关闭 ReceiveFiles 应用程序。

启动应用程序

private void btnStartRemoteListeners_Click(object sender, RoutedEventArgs e)
{
    bool bcontinue = true;
    bool wasanyerror = false;
    string psexecPath = System.Windows.Forms.Application.StartupPath + "\\psexec.exe";
    string remoteExecutablePath = txtPathWhereReceiveFilesIs.Text;
    string parameters = string.Empty;
    bool showFinalMessage = true;
    progressBar1.Maximum = lstServers.SelectedItems.Count;
    progressBar1.Value = 0;
    txtLog.Text = String.Empty;
    if (ValidateStart()==true)
    {
        foreach (string serverName in lstServers.SelectedItems)
        {
            Server server = null;
            if (ServersList.TryGetValue(serverName, out server) == true)
            {
                server.User = server.User == "" ? "Error" : server.User;
                server.Password = server.Password == "" ? "Error" : server.Password;
                try
                {
                    if (bcontinue == true)
                    {
                        if (server.MyProcess == null)
                        {
                            Process p = new Process();
                            ProcessStartInfo psinfo = new ProcessStartInfo(psexecPath);
                            parameters = @"\\" + server.ServerName + 
                               " -u " + server.User + " -p " + 
                               server.Password + " -i 0 " + remoteExecutablePath;
                            psinfo.Arguments = parameters;
                            txtLog.AppendText(psexecPath + " " + 
                               parameters + Environment.NewLine);
                            psinfo.CreateNoWindow = true;
                            psinfo.WindowStyle = ProcessWindowStyle.Minimized;
                            p = Process.Start(psinfo);
                            server.MyProcess = p;
                            System.Threading.Thread.Sleep(1000);
                            if (p.HasExited == true)
                            {
                                server.MyProcess = null;
                                throw new Exception();
                            }
                        }
                        else
                        {
                            System.Windows.Forms.MessageBox.Show("The process " + 
                              "is already running at the server: " + 
                              server.ServerName, "Start Listener", 
                              MessageBoxButtons.OK, MessageBoxIcon.Information);
                            showFinalMessage = false;
                        }
                    }
                }
                catch (Exception ex)
                {
                    string msg = "Error starting the remote listener at " + 
                                 server + Environment.NewLine + ex.Message + 
                                 Environment.NewLine + "Path: " + 
                                 psexecPath + Environment.NewLine +
                                 "Parameters: " + parameters + Environment.NewLine +
                                 "Maybe the remote path does not exists, " + 
                                 "the password is incorrect or the remote " + 
                                 "listener is still running";
                    txtLog.AppendText(msg + Environment.NewLine);
                    System.Windows.Forms.MessageBox.Show(msg, "Error", 
                           MessageBoxButtons.OK, MessageBoxIcon.Error);
                    wasanyerror = true;
                    if (System.Windows.Forms.MessageBox.Show(
                        "Do you want to continue?", 
                        "Continue", MessageBoxButtons.YesNo, 
                        MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
                    {
                        bcontinue = false;
                    }
                }
                progressBar1.Value++;
            }
        }
        if (showFinalMessage == true)
        {
            if (wasanyerror == false)
            {
                System.Windows.Forms.MessageBox.Show(
                  "Remote listeners started ok", "Ok", 
                  MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                System.Windows.Forms.MessageBox.Show(
                  "Remote listener started with errors", 
                  "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

复制文件

private void btnSendFiles_Click(object sender, RoutedEventArgs e)
{
    SocketsFileTransfer socketsFileTransfer = new SocketsFileTransfer();
    int filenamePort = 9999;  //port number for the file name
    int filedataPort = 9998;  //port number for the file data
    string serversWithError = string.Empty;
    bool bcontinue = true;
    bool wasanerror = false;
    if (this.ValidateSending() == true)
    {
        this.Cursor = System.Windows.Input.Cursors.Wait;
        progressBar1.Maximum = lstServers.SelectedItems.Count;
        progressBar1.Value = 0;
        txtLog.Text = String.Empty;
        foreach (string serverName in lstServers.SelectedItems)
        {
            //Get the IP of the remote server
            System.Net.IPAddress ipAddress = 
              socketsFileTransfer.GetIpFromHostName(serverName);
            txtLog.AppendText(serverName + " ip: " + 
              ipAddress.ToString() + Environment.NewLine);
            foreach (string filePath in filesToSend)
            {
                string fileName = System.IO.Path.GetFileName(filePath);
                string finalPath = cboRemotePaths.Text + "\\" + fileName;
                txtLog.AppendText("Uploading " + fileName + 
                  " to " + serverName + "::" + 
                  finalPath + Environment.NewLine);
                try
                {
                    if (bcontinue == true)
                    {
                        //Send the file name
                        socketsFileTransfer.SendFileName(serverName, filenamePort, finalPath);
                        txtLog.AppendText("File name sent" + Environment.NewLine);
                        //Wait
                        System.Threading.Thread.Sleep(250);
                        //Send the file data
                        socketsFileTransfer.SendFile(ipAddress, filedataPort, filePath);
                        txtLog.AppendText("Data sent" + Environment.NewLine);
                    }
                }
                catch (Exception ex)
                {
                    string msg = "Error sending: " + fileName + 
                      " to " + serverName + Environment.NewLine + ex.Message;
                    txtLog.AppendText(msg);
                    System.Windows.Forms.MessageBox.Show(msg, "Error at " + 
                      serverName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    wasanerror = true;
                    serversWithError += serverName + Environment.NewLine;
                    if (System.Windows.Forms.MessageBox.Show("Do you want " + 
                        "to continue with the send process?", "Continue", 
                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == 
                        System.Windows.Forms.DialogResult.No)
                    {
                        bcontinue = false;
                    }
                }
            }
            progressBar1.Value++;
            System.Windows.Forms.Application.DoEvents();
        }
        if (wasanerror == false)
        {
            System.Windows.Forms.MessageBox.Show("Process finished ok", 
                   "Ok", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        else
        {
            System.Windows.Forms.MessageBox.Show("Process finished " + 
              "with errors at: " + Environment.NewLine + serversWithError, 
              "Errors", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        this.Cursor = System.Windows.Input.Cursors.Arrow;
    }
}

关闭应用程序

private void btnCloseRemoteListeners_Click(object sender, RoutedEventArgs e)
{
    bool bcontinue = true;
    bool wasanyerror = false;

    progressBar1.Maximum = lstServers.SelectedItems.Count;
    progressBar1.Value = 0;
    txtLog.Text = String.Empty;
    foreach (string serverName in lstServers.SelectedItems)
    {
        if (bcontinue == true)
        {
            if (this.CloseServer(serverName) == false)
            {
                wasanyerror = true;
                if (System.Windows.Forms.MessageBox.Show(
                    "Do you want to close the remote listeners?", 
                    "Continue", MessageBoxButtons.YesNo, 
                    MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                {
                    bcontinue = false;
                }
            }
        }
        progressBar1.Value++;
    }
    if (wasanyerror == false)
    {
        System.Windows.Forms.MessageBox.Show("Remote listeners closed", 
           "Ok", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    else
    {
        System.Windows.Forms.MessageBox.Show(
          "Remote listeners closed with errors", 
          "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

配置文件

在此文件中,您可以指定将要操作的服务器的名称、域、用户名和密码。这些数据显示在 SendFiles 表单左侧的列表中。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <Server>
    <ServerName>machine1.domain.xxx</ServerName>
    <User>domain\user</User>
    <Password>password</Password>
  </Server>
  <Server>
    <ServerName>machine2.domain.xxx</ServerName>
    <User>domain\user</User>
    <Password>password</Password>
  </Server>
</configuration>

关注点

请随时发表您的评论。我在这里学习。

历史

  • 版本 1.0。
© . All rights reserved.