Created
January 19, 2009 15:46
-
-
Save aethur/49029 to your computer and use it in GitHub Desktop.
C#檔案傳輸
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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