Skip to content

Instantly share code, notes, and snippets.

@aethur
Created January 19, 2009 15:46
Show Gist options
  • Select an option

  • Save aethur/49029 to your computer and use it in GitHub Desktop.

Select an option

Save aethur/49029 to your computer and use it in GitHub Desktop.
C#檔案傳輸
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.Encoding;
public static class FileTransfer
{
private const int BufferSize = 16384;
private const int Port = 2070;
/// <summary>
/// 捕獲外來訊息的伺服器類別
/// </summary>
/// <remarks></remarks>
public class FileServer
{
public static Form1 Mainform;
public int Port = FileTransfer.Port;
private Socket ServerSocket;
public FileServer(ref Form form)
{
Mainform = form;
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPHostEntry ipen = Dns.GetHostEntry(Dns.GetHostName);
var endpoint = new IPEndPoint(IPAddress.Any, Port);
ServerSocket.Bind(endpoint);
ServerSocket.Listen(1000);
ServerSocket.BeginAccept(CatchSocket, ServerSocket);
}
//捕捉新連線
public void CatchSocket(IAsyncResult result)
{
//重新導向到轉接器
TempInterObject TIO = new TempInterObject(ServerSocket.EndAccept(result));
TIO.Sock.ReceiveBufferSize = BufferSize;
//開始處理基本傳輸資料
TIO.Sock.BeginReceive(TIO.Buffer, 0, TIO.Buffer.Length, 0, InfoWorker, TIO);
ServerSocket.BeginAccept(CatchSocket, ServerSocket);
}
//處理開頭資料
public void InfoWorker(IAsyncResult result)
{
TempInterObject TIO = (TempInterObject)result.AsyncState;
int len = TIO.Sock.EndReceive(result);
string Src = UTF8.GetString(TIO.Buffer, 0, len);
string Command = Src.Substring(0, Src.IndexOf(" "));
string File = Src.Substring(Src.IndexOf(" ") + 1);
TransferTask nTask = default(TransferTask);
//對方要求檔案
if (Command == "GET") {
nTask = new TransferTask(File, TIO.Sock, TransferTask.Method.SEND);
//發送檔案資訊->傳輸檔案
}
//對方要求傳送檔案給本機
else {
byte[] Sign = new byte[1];
Sign(0) = (My.Computer.FileSystem.FileExists(File) ? 0 : 1);
//如果檔案存在則不允許
TIO.Sock.Send(Sign, 1, SocketFlags.None);
//傳送准許憑證
nTask = new TransferTask(File, TIO.Sock, TransferTask.Method.GET);
//開始下載
nTask.FileSize = Conversion.Val(Command.Substring(Command.IndexOf("[") + 1, Command.IndexOf("]") - Command.IndexOf("[")));
//分析檔案大小
}
}
}
/// <summary>
/// 轉接Socket用的暫時類別
/// </summary>
/// <remarks></remarks>
public class TempInterObject
{
public byte[] Buffer = new byte[BufferSize];
public Socket Sock;
public TempInterObject(Socket SocketObject)
{
this.Sock = SocketObject;
}
}
/// <summary>
/// 傳送檔案 控制類別("下載工作"物件)
/// </summary>
/// <remarks></remarks>
public class TransferTask
{
public enum Method
{
GET = 0,
SEND = 1
}
public string FilePath = "";
public string Host = "";
public int Port = FileTransfer.Port;
private byte[] Data = new byte[BufferSize];
private IO.FileStream Reader;
private Socket Sock;
private IO.FileStream WriteStream;
protected internal uint FileSize = 0;
private uint ReadSize = 0;
private int LastProgress = 0;
private Method mType = 0;
private delegate void InvokeFinished(bool Error);
private InvokeFinished FinishedInvoker = new InvokeFinished(onProgressFinished);
//接收檔案(主動)
private void GetNew(string File, string LocalFile, string Host)
{
Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Sock.Connect(Host, Port);
FilePath = LocalFile;
Sock.SendBufferSize = BufferSize;
SendString("GET " + File);
Sock.BeginReceive(Data, 0, Data.Length, SocketFlags.None, GetSize, this);
}
//傳送檔案(主動)
private void SendNew(string File, string RemoteFile, string Host)
{
Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Sock.Connect(Host, Port);
FilePath = File;
Sock.SendBufferSize = BufferSize;
FileSize = GetFileSize(File);
SendString("SEND[" + FileSize + "] " + RemoteFile);
//偵測憑證
Sock.BeginReceive(Data, 0, 1, SocketFlags.None, Accepted, this);
}
//傳送或接收檔案(主動)
public TransferTask(string FileA, string FileB, string Host, Method Type, [System.Runtime.InteropServices.OptionalAttribute, System.Runtime.InteropServices.DefaultParameterValueAttribute(2070)] int Port)
{
mType = Type;
this.Host = Host;
this.Port = Port;
if (Type == Method.GET) GetNew(FileA, FileB, Host); else SendNew(FileA, FileB, Host);
}
//傳送或接收檔案(被動)
public TransferTask(string File, Socket Sock, Method Type)
{
mType = Type;
this.Sock = Sock;
FilePath = File;
Sock.SendBufferSize = BufferSize;
if (Type == Method.SEND) {
//傳送檔案
//送出檔案大小
FileSize = GetFileSize(File);
SendString(FileSize);
//偵測憑證
Sock.BeginReceive(Data, 0, 1, SocketFlags.None, Accepted, this);
}
else {
//接收檔案
Sock.BeginReceive(Data, 0, Data.Length, SocketFlags.None, Recived, this);
}
}
//對方准許我方傳送
private void Accepted(IAsyncResult Result)
{
Sock.EndReceive(Result);
if (Data(0) == 0) {
onProgressFinished(true);
Sock.Close();
return;
}
Reader = new IO.FileStream(FilePath, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read);
if (Reader.Length < BufferSize) {
System.Array.Resize(Data, Reader.Length);
}
Reader.BeginRead(Data, 0, Data.Length, FileReaded, this);
}
//我方接收檔案串流
private void Recived(IAsyncResult result)
{
//讀取
int Len = 0;
try {
Len = Sock.EndReceive(result);
}
catch {
}
if (Len == 0) {
Sock.Shutdown(SocketShutdown.Both);
Sock.Close();
if (WriteStream != null) {
//下載終了
WriteStream.Close();
WriteStream.Dispose();
}
onProgressFinished(false);
return;
}
if (WriteStream == null) {
WriteStream = new IO.FileStream(FilePath, IO.FileMode.Append);
}
//修改進度!
ReadSize += Len;
onProgressChanged();
WriteStream.Write(Data, 0, Len);
try {
Sock.BeginReceive(Data, 0, Data.Length, SocketFlags.None, Recived, this);
}
catch {
WriteStream.Close();
WriteStream.Dispose();
onProgressFinished(!(ReadSize == Len));
}
}
//取得被動的對方傳送的檔案大小
private void GetSize(IAsyncResult result)
{
int Len = Sock.EndReceive(result);
FileSize = Conversion.Val(UTF8.GetString(Data, 0, Len));
byte[] Sign = new byte[1];
Sock.Send(Sign, 1, SocketFlags.None);
Sock.BeginReceive(Data, 0, Data.Length, SocketFlags.None, Recived, this);
}
//傳送字串
private void SendString(string msg)
{
byte[] Buffer = System.Text.Encoding.UTF8.GetBytes(msg);
Sock.BeginSend(Buffer, 0, Buffer.Length, SocketFlags.None, StringSended, Sock);
}
//傳送字串的End偵聽函式
private void StringSended(IAsyncResult result)
{
try {
((Socket)result.AsyncState).EndSend(result);
}
catch {
}
}
//傳送串流的End偵聽函式
private void StreamSended(IAsyncResult result)
{
Sock.EndSend(result);
//結束非同步傳送Stream
//如果讀到盡頭
if (Reader.Length <= Reader.Position) {
Sock.Close();
Reader.Close();
Reader.Dispose();
onProgressFinished(false);
return;
}
//如果剩下位傳送的位元組不到BufferSize
if (Reader.Length - Reader.Position < BufferSize) {
System.Array.Resize(Data, Reader.Length - Reader.Position);
}
ReadSize += Data.Length;
//增加進度
onProgressChanged();
Reader.BeginRead(Data, 0, Data.Length, FileReaded, this);
}
//讀取串流的End偵聽函式
private void FileReaded(IAsyncResult result)
{
Reader.EndRead(result);
//結束非同步讀取Stream
Sock.BeginSend(Data, 0, Data.Length, SocketFlags.None, StreamSended, this);
//開始傳送資料
}
//進度改變檢測
private void onProgressChanged()
{
if (FileServer.Mainform.InvokeRequired) {
FileServer.Mainform.BeginInvoke(new MethodInvoker(onProgressChanged));
return;
}
if (Conversion.Int(Progress) - LastProgress > 0) {
if (ProgressChanged != null) {
ProgressChanged(this, Progress);
}
}
LastProgress = Conversion.Int(Progress);
}
//結束下載
private void onProgressFinished(bool Error)
{
if (FileServer.Mainform.InvokeRequired) {
FileServer.Mainform.BeginInvoke(FinishedInvoker, Error);
return;
}
if (ProgressChanged != null) {
ProgressChanged(this, 100);
}
if (ProgressFinished != null) {
ProgressFinished(this, Error);
}
}
//屬性
public float Progress {
get {
if (FileSize > 0) {
return (ReadSize / FileSize) * 100;
}
else {
return 0;
}
}
}
public uint Length {
get { return FileSize; }
}
public Method Type {
get { return mType; }
}
/// <summary>
/// 當下載進度改變時呼叫
/// </summary>
/// <param name="Sender">"下載工作"物件</param>
/// <param name="value">進度(百分比)</param>
/// <remarks></remarks>
public event ProgressChangedEventHandler ProgressChanged;
public delegate void ProgressChangedEventHandler(TransferTask Sender, int value);
/// <summary>
/// 下載完成時呼叫
/// </summary>
/// <param name="Sender">"下載工作"物件</param>
/// <param name="Error">是否錯誤</param>
/// <remarks></remarks>
public event ProgressFinishedEventHandler ProgressFinished;
public delegate void ProgressFinishedEventHandler(TransferTask Sender, bool Error);
}
/// <summary>
/// 取得檔案大小
/// </summary>
/// <param name="Path">檔案路徑</param>
/// <returns>檔案大小(位元組)</returns>
/// <remarks></remarks>
public static int GetFileSize(string Path)
{
return My.Computer.FileSystem.GetFileInfo(Path).Length;
}
/// <summary>
/// 非同步傳送檔案
/// </summary>
/// <param name="Local">本機檔案(被傳送的)</param>
/// <param name="Remote">遠端位置(被傳送後要放置的位置)</param>
/// <param name="Host">遠端主機</param>
/// <param name="onEnd">結束時呼叫</param>
/// <param name="onChange">進度更新呼叫</param>
/// <remarks></remarks>
public static void BeginTransFile(string Local, string Remote, string Host, TransferTask.ProgressFinishedEventHandler onEnd, TransferTask.ProgressChangedEventHandler onChange)
{
TransferTask Task = new TransferTask(Local, Remote, Host, TransferTask.Method.SEND);
if (onEnd != null) Task.ProgressFinished += onEnd;
if (onChange != null) Task.ProgressChanged += onChange;
}
/// <summary>
/// 非同步下載檔案
/// </summary>
/// <param name="Local">本機檔案(被傳送後要放置的位置)</param>
/// <param name="Remote">遠端位置(被傳送的)</param>
/// <param name="Host">遠端主機</param>
/// <param name="onEnd">結束時呼叫</param>
/// <param name="onChange">進度更新呼叫</param>
/// <remarks></remarks>
public static void BeginGetFile(string Remote, string Local, string Host, TransferTask.ProgressFinishedEventHandler onEnd, TransferTask.ProgressChangedEventHandler onChange)
{
TransferTask Task = new TransferTask(Remote, Local, Host, TransferTask.Method.GET);
if (onEnd != null) Task.ProgressFinished += onEnd;
if (onChange != null) Task.ProgressChanged += onChange;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment