1. 程式人生 > 實用技巧 >檔案斷點續傳實現 ( 2-- C# 客戶端)

檔案斷點續傳實現 ( 2-- C# 客戶端)

服務端用的是java寫的服務端:

檔案斷點續傳實現 ( 1 -- java實現)

C# 版客戶端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using Gdl.Common.Utils;
using Gdl.Common.Log;
using System.Threading;
using System.Text.RegularExpressions;
using System.Windows.Forms; namespace Gdl.Common.Upload2 { public class UploadClient { private static Logger LOG = new Logger("UploadClient"); /// <summary> /// 上傳 /// </summary> /// <param name="file">上傳檔案全路徑</param> /// <param name="ip">
上傳伺服器IP</param> /// <param name="port">上傳伺服器埠</param> /// <param name="charset">文字編碼</param> public static void Upload(string file, string ip, int port,string charset) { if(!File.Exists(file)) { throw new Exception("
上傳檔案不存在"); } //通過Lambda表示式 Thread thread = new Thread(() => new UploadClient(file,ip,port,charset).Execute()); thread.Start(); } private string filePath;//上傳檔案 private string ip;//伺服器IP private int port;//伺服器埠 private string charset;//文字編碼 public UploadClient(string filePath, string ip, int port, string charset) { this.filePath = filePath; this.ip = ip; this.port = port; this.charset = charset; } /// <summary> /// 執行上傳 /// </summary> public void Execute() { FileInfo fileInfo = new FileInfo(filePath); if (!fileInfo.Exists) { throw new Exception("上傳檔案不存在"); } IPEndPoint address = new IPEndPoint(IPAddress.Parse(ip), port); using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { socket.Connect(ip, port); socket.Blocking = true;//是否為阻塞(同步)模式 long fileLength = fileInfo.Length; string fileMD5 = MD5Util.MD5FromFile(filePath); string fileName = fileInfo.Name; string msg = fileMD5 + "|" + fileLength + "|" + fileName; LOG.info("傳送報文:" + msg); SendMsg(socket, msg);//傳送報文 LOG.info("傳送成功,開始接收報文"); //接收報文 msg = ReceiveMsg(socket); LOG.info("接收報文:" + msg); /* * 收到報文後第二階段 * 00 檔案大小為0 * 01 檔案存在,不需要重新上傳 * 02 臨時檔案,豎線後是檔案大小 * 03 檔案存在,但是md5不同 */ if (msg.StartsWith("02")) { string[] strs = Regex.Split(msg.Trim(), "\\|", RegexOptions.None); int size = int.Parse(strs[1]); long offset = int.Parse(strs[2]); using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { stream.Seek(offset, SeekOrigin.Begin); int length = 0; byte[] buf = new byte[size]; LOG.info("開始上傳檔案"); while ((length = stream.Read(buf, 0, size)) > 0) { socket.Send(buf, 0, length, SocketFlags.None); } stream.Close(); LOG.info("上傳結束"); } //接收報文 msg = ReceiveMsg(socket); LOG.info("接收報文:" + msg); } socket.Close(); } } /// <summary> /// 傳送文字 /// </summary> /// <param name="socket"></param> /// <param name="msg"></param> private void SendMsg(Socket socket, string msg) { byte[] byteArray = Encoding.GetEncoding(charset).GetBytes(msg); int length = byteArray.Length; byte[] byteLength = new byte[] { (byte)(rrr(length,24) & 0xFF), (byte)(rrr(length,16) & 0xFF), (byte)(rrr(length, 8) & 0xFF), (byte)(rrr(length, 0) & 0xFF) }; socket.Send(byteLength); socket.Send(byteArray); } private string ReceiveMsg(Socket socket) { int len = 0; StringBuilder res = new StringBuilder(); byte[] buffer = new byte[4]; //不阻塞一下無法獲取獲取到資料不知道為什麼 int i = 100; while (i-->0 && socket.Available == 0) { Thread.Sleep(200); } socket.Receive(buffer, buffer.Length, SocketFlags.Partial); if ((buffer[0] | buffer[1] | buffer[2] | buffer[3]) < 0) { LOG.error("EOF錯誤;資料:{" + buffer[0] + "," + buffer[1] + "," + buffer[2] + "," + buffer[3] + "}"); throw new Exception("EOF"); } len = ((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + (buffer[3] << 0)); LOG.debug("報文長度:" + len + " , 資料 {" + buffer[0] + "," + buffer[1] + "," + buffer[2] + "," + buffer[3] + "}"); buffer = new byte[len]; socket.Receive(buffer, buffer.Length, SocketFlags.Partial);//返回結果是接收到的位元組數 string msg = Encoding.GetEncoding(charset).GetString(buffer); LOG.info("接收報文:" + msg); return msg; } /// <summary> /// 實現運算子 >>> /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static int rrr(int x, int y) { int mask = 0x7fffffff; // Integer.MAX_VALUE for (int i = 0; i < y; i++) { x >>= 1; x &= mask; } return x; } } }

工具類(獲取檔案MD5)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Gdl.Common.Utils
{
    /// <summary>
    /// 獲取MD5
    /// </summary>
    public class MD5Util
    {

        /// <summary>
        /// 獲取檔案MD5
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static String MD5FromFile(string fileName)
        {
            FileStream file = null;
            try
            {
                file = new FileStream(fileName, FileMode.Open);

                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("MD5FromFile() fail,error:" + ex.Message);
            }
            finally
            {
                if (null != file)
                {
                    file.Close();
                }
            }
        }
    }
}