• 文件断点续传实现 ( 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();
                    }
                }
            }
        }
    }
  • 相关阅读:
    【剑指offer】对称的二叉树
    【剑指offer】数组中的逆序对
    【剑指offer】不用加减乘除做加法
    【剑指offer】和为S的连续正数序列
    【剑指offer】删除链表中重复的结点
    【剑指offer】平衡二叉树
    Math.ceil()、Math.floor()和Math.round()
    document.querySelectorAll遍历
    JS选择器querySelector和~All,三个原生选择器
    js 操作select和option常见用法
  • 原文地址:https://www.cnblogs.com/hi-gdl/p/14116717.html
Copyright © 2020-2023  润新知