一个客户端服务器文件共享应用程序






4.50/5 (8投票s)
一个客户端服务器文件共享应用程序
2011年1月15日 下午5:15
这篇博客文章是一个用C#编写的客户端/服务器文件共享或传输应用程序。该应用程序由两个项目组成,它可以在单台计算机上进行测试,但如果在两台计算机上进行测试,一台计算机作为客户端运行,另一台计算机作为服务器运行,则其功能将得到最好的体现。
在我们开始编码之前,必须了解Socket
,它是网络编程中最重要的方面。
Socket
是一个对象,它代表了对互联网协议(IP)栈的底层访问点,它用于发送和接收数据,因此它可以被打开和关闭。要发送的数据总是以称为数据包的块发送。
数据包必须包含数据包的源IP地址和数据要发送到的目标计算机的IP地址,并且可以选择包含一个端口号。端口号的范围是1到65,535。端口是计算机可以通信的通信通道或端点。始终建议程序使用高于1024的端口号,以避免与系统上运行的其他应用程序发生冲突,因为没有两个应用程序可以使用相同的端口。
包含端口号的数据包可以使用 UDP (用户数据报协议) 或 TCP/IP (传输控制协议) 发送。 UDP比TCP更容易使用,因为TCP更复杂并且具有更长的延迟,但是当要传输数据的完整性比性能更重要时,则TCP优先于UDP,因此对于我们的文件共享应用程序,将使用TCP/IP,因为它保证我们的文件在传输过程中不会损坏,并且如果在传输过程中丢失了数据包,它将被重新传输,从而确保维护我们的文件完整性。
因此,此应用程序将允许您将任何文件从一台计算机发送到另一台计算机,我个人已使用它将一个350MB的文件从一台台式PC发送到另一台。
现在开始,创建两个新的Windows Forms应用程序。一个命名为FileSharingServer
,另一个命名为FileSharingClient
。
现在,对于FileSharingClient
Windows Form应用程序,向窗体添加三个文本框和两个按钮,如下面的屏幕所示
适当地重命名文本框和按钮。
这是文件共享客户端应用程序的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.IO;
namespace FileSharingClient
{
public partial class Form1 : Form
{
private static string shortFileName = "";
private static string fileName = "";
public Form1()
{
InitializeComponent();
}
private void btnBrowse_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "File Sharing Client";
dlg.ShowDialog();
txtFile.Text = dlg.FileName;
fileName = dlg.FileName;
shortFileName = dlg.SafeFileName;
}
private void btnSend_Click(object sender, EventArgs e)
{
string ipAddress = txtIPAddress.Text;
int port = int.Parse(txtHost.Text);
string fileName = txtFile.Text;
Task.Factory.StartNew(() => SendFile(ipAddress,port,fileName,shortFileName) );
MessageBox.Show("File Sent");
}
public void SendFile(string remoteHostIP, int remoteHostPort,
string longFileName, string shortFileName)
{
try
{
if (!string.IsNullOrEmpty(remoteHostIP))
{
byte[] fileNameByte = Encoding.ASCII.GetBytes(shortFileName);
byte[] fileData = File.ReadAllBytes(longFileName);
byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];
byte[] fileNameLen = BitConverter.GetBytes(fileNameByte.Length);
fileNameLen.CopyTo(clientData, 0);
fileNameByte.CopyTo(clientData, 4); fileData.CopyTo(clientData, 4 + fileNameByte.Length);
TcpClient clientSocket = new TcpClient(remoteHostIP, remoteHostPort);
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Write(clientData, 0, clientData.GetLength(0));
networkStream.Close();
}
}
catch
{
}
}
}
}
}
请注意,以下命名空间已添加到Windows Form应用程序
System.Threading.Tasks; // used to include the .NET Parallel computing lclasses
System.Net;
System.Net.Sockets;
System.Net.NetworkInformation;
以上三个命名空间包含用于网络编程的.NET类。
System.IO; // contain classes used for file operations
当单击浏览按钮时,将创建一个OpenFileDialog
对象以打开一个对话框,以获取要发送的文件的文件名。当单击发送按钮时,将并行调用和处理SendFile
方法,以便在发送文件时主窗体用户界面不会冻结,并且在多核环境中充分利用处理器。
SendFile
方法接受目标计算机的IP地址和端口号,以及文件路径和文件名。文件名和文件都转换为字节,并使用创建的TCPCLient
和NetworkStream
类对象发送到目标计算机。
文件共享客户端应用程序的用户界面在运行时如下所示。
服务器的源代码是
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.IO;
using System.Threading.Tasks;
namespace FileSharingServer
{
public partial class Form1 : Form
{
public delegate void FileRecievedEventHandler(object source, string fileName);
public event FileRecievedEventHandler NewFileRecieved;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.NewFileRecieved+=new FileRecievedEventHandler (Form1_NewFileRecieved);
}
private void Form1_NewFileRecieved(object sender, string fileName)
{
this.BeginInvoke( new Action( delegate()
{ MessageBox.Show("New File Received\n"+fileName);
System.Diagnostics.Process.Start("explorer", @"c:\");
}));
}
private void btnListen_Click(object sender, EventArgs e)
{
int port = int.Parse(txtHost.Text);
Task.Factory.StartNew(() => HandleIncomingFile(port));
MessageBox.Show("Listening on port"+port);
}
public void HandleIncomingFile(int port)
{
try
{
TcpListener tcpListener = new TcpListener(port);
tcpListener.Start();
while (true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
{
string fileName = string.Empty;
NetworkStream networkStream = new NetworkStream(handlerSocket);
int thisRead = 0;
int blockSize = 1024;
Byte[] dataByte = new Byte[blockSize];
lock (this)
{
string folderPath = @"c:\";
int receivedBytesLen = handlerSocket.Receive(dataByte);
int fileNameLen = BitConverter.ToInt32(dataByte, 0);
fileName = Encoding.ASCII.GetString(dataByte, 4, fileNameLen);
Stream fileStream = File.OpenWrite(folderPath + fileName);
fileStream.Write(dataByte, 4+fileNameLen,(1024-(4+fileNameLen)));
while (true)
{
thisRead = networkStream.Read(dataByte, 0, blockSize);
fileStream.Write(dataByte, 0, thisRead);
if (thisRead == 0)
break;
}
fileStream.Close();
}
if (NewFileRecieved != null)
{
NewFileRecieved(this, fileName);
}
handlerSocket = null;
}
}
}
catch { }
}
}
}
在文件共享服务器应用程序上,提供一个端口号,服务器将在该端口上侦听要接收的传入文件。
就像文件共享客户端应用程序一样,单击“开始侦听”按钮时,将并行调用HandleIncomingFile
方法。创建一个TcpListener
对象,以开始在指定端口上侦听传入文件,当收到连接时,将从接收到的字节中重建与从客户端发送的文件同名的文件,并将其保存到C盘,然后触发一个事件,以指示在服务器用户界面上已收到一个新文件。
当触发事件时,将通知该事件的所有订阅者,在这种情况下,将调用事件处理程序方法Form1_NewFileRecieved
,并且用于显示消息框并打开包含接收文件的文件夹的代码被包装在窗体的BeginInvoke
方法周围,以避免线程错误。
这两个应用程序的完整源代码可在此处下载here。