如何远程复制文件






4.67/5 (22投票s)
使用套接字远程复制文件的两个应用程序。
引言
我们在工作中有许多,许多服务器。SQL Server、Oracle等企业级应用程序由系统管理员安装在其中。但是,当我们(开发人员)创建新应用程序或新组件时,我们必须将新的程序集部署到每个服务器上。我们不喜欢这样做,我们讨厌这样做,所以我尝试制作一个应用程序,使其任务对我们来说更轻松……
背景
有两个应用程序。它们都使用套接字进行通信,并传输文件名和数据。这些是应用程序
ReceiveFiles
这是一个监听新请求的控制台应用程序。当发送请求到服务器时,此应用程序会接收它并将文件复制到所需的最终路径。这不是一个一直监听的 Windows 服务。我稍后会解释如何远程启动此程序。
SendFiles
这是一个具有简单 GUI 的 Windows 应用程序,用于启动远程 ReceiveFiles 应用程序并发送文件到服务器。
PsExec
PsExec 是一个 Windows 应用程序,您可以使用它来启动远程进程。它用于远程启动 ReceiveFiles。我无法在此处附加它,因为这是禁止的。但您可以从这里免费下载:http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx。
如何使用
- 将 ReceiveFiles 复制到您想要部署文件的服务器上。如果运气好的话,这将是您最后一次需要自己复制任何东西。
- 您必须从 Microsoft 网页下载 PsExec,才能远程启动 ReceiveFiles。下载后,您必须将 PsExec 复制到 SendFiles 安装的同一路径下。
- 在配置文件中填入服务器名称、用户名和密码。
- 启动 SendFiles 应用程序。在第一个文本框“ReceiveFile 所在路径…”中,您必须输入 ReceiveFiles 已安装的远程路径。建议所有机器上的路径都相同。
- 选择所需的服务器,然后单击“启动远程监听器”以启动远程 ReceiveFiles 应用程序。
- 一旦远程应用程序启动(您可以在 MS DOS 窗口中检查),您就可以通过单击“获取文件”按钮选择要复制的文件。选择您想要的。
- 单击“发送文件”按钮将选定的文件复制到所有服务器。
- 进程完成后,您可以单击“关闭远程监听器”来关闭远程应用程序。
就这样了...
使用代码
代码是对网络上找到的一些代码的修改;到目前为止,它运行正常!
一旦 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
方法会循环遍历每个文件,并调用 SendFileName
和 SendFile
来传输数据。
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。