zoukankan      html  css  js  c++  java
  • 利用Socket进行大文件传输

    分类: WINDOWS

    最近接触到利用socket进行大文件传输的技术,有些心得,与大家分享.首先看看这个过程是怎么进行的(如下图):   
     
    所以,我们需要三个socket在窗体加载的时候初始化:
    1. 等到收货请求的socket(即等待对方向自己发出发送文件的请求:monitorSocket,端口:monitorPort)
    2. 接收收货方响应的socket(即对方是否愿意接收大文件的回应:responseSocket:端口:responsePort)
    3. 收货方收货的socket(即接收大文件:receiveSocket:端口:receivePort)
     
    界面的设计如下(由于没有建立服务器,所以在通信时需要首先知道对方的IP和等待请求的端口):
     
    具体步骤:
    1. 在发送方和接收方的主窗体界面中分别将对方的IP和等待对方发送请求的端口填入;
    2. Browser_Click(按钮的点击事件),主要完成以下操作:
        (1)选择要发送的文件,并得到文件名fileName;
        (2)将文件名(fileName),本机IP(localIP)和本机接收对方回应的端口(responsePort)发送给对方的monitorSocket端口
    3. 接收方接收发送方文件传输请求.在接收方的monitorSocket中完成以下操作:
        (1)解析出发送方传递的三个信息(fileName,responsePort和monitorSocket)
        (2)弹出另存为窗口.定义是否接收的变量bool isReceive = false;若点击保存,则isReceive=true;
        (3)将isReceive,本机IP和本机接收大文件的端口(receivePort)发送给发送方
    4. 发送等待接收方的回复.主要完成以下操作:
         (1)解析出接收方回复的信息,看对方是否同意接收,并且得到对方的IP和接受文件的端口
             若对方同意接收:
        (2)连接到对方接收文件的端口(即receviPort)
        (3)创建文件流fileStream
        (4)得到文件流的长度fileStream.Length(long型数据,比int类型传的数据量的上限更高),并且先将文件流的长度发送给接收方,让其准备足够的缓冲区
        (5)对文件分包,每个包大小为partSize
        (6)建一个缓冲区buffer大小为partSize,从fileStream向buffer中写数据,并将buffer中的数据发送,这个过程一直循环,直到所有的数据都写完(循环的次数为long partCount                   =fileSize/partSize,).
    5. 接收方接收文件,主要完成以下操作:
        (1)首先接收到文件流的长度
        (2)定义一个文件流fileStream
        (3)定义一个接收数据的缓冲区bufferData,长度为8096(这个数字可以调整)
        (4)将接收的数据写到bufferData中,每次写入8096字节,将bufferData中的数据写到文件流fileStream中,直到所以的数据都写入
     
    相关代码:
    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.Threading;
    using System.IO;
    namespace SocketTest
    {
        public partial class FormChat : Form
        {
            public FormChat()
            {
                InitializeComponent();
            }
            //声明本机ip
            private IPAddress localIP = null;
            //接收对方信息的socket
            private Socket socketReceiveMsg = null;
            private int portReceiveMsg;
            private Thread threadReceiveMsg = null;
            //是否接受文件的Socket
            private Socket socketWaiting = null;
            private int portWaiting;
            private Thread threadWaiting = null;
            //等待对方响应是否接受的socket
            private Socket socketResponse = null;
            private int portResponse;
            private Thread threadResponse = null;
            //接收文件的Socket
            private Socket socketReceiveData;
            private int portReceiveData;
            private Thread threadReceiveData;
            private void rtbHistory_Load(object sender, EventArgs e)
            {
                IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName());
                this.localIP = hostEntry.AddressList[1];
                this.txtLocalIP.Text = this.localIP.ToString();
                Random random = new Random();
                this.portWaiting = random.Next(20000, 30000);
                this.portReceiveMsg = random.Next(10000,20000);
                this.portReceiveData = random.Next(20000, 40000);
                this.portResponse = random.Next(10000,30000);
                this.txtLocalReceiveMsgPort.Text = this.portReceiveMsg.ToString();
                this.txtLocalWaitingPort.Text = this.portWaiting.ToString();
                IPEndPoint endPointReceiveMsg = new IPEndPoint(this.localIP, this.portReceiveMsg);
                this.socketReceiveMsg = new Socket(endPointReceiveMsg.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                this.socketReceiveMsg.Bind(endPointReceiveMsg);
                this.threadReceiveMsg = new Thread(new ThreadStart(ReceiveMsgListener));
                this.threadReceiveMsg.Start();
                IPEndPoint endPointWaiting = new IPEndPoint(this.localIP, this.portWaiting);
                this.socketWaiting = new Socket(endPointWaiting.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                this.socketWaiting.Bind(endPointWaiting);
                this.threadWaiting = new Thread(new ThreadStart(WaitingListener));
                this.threadWaiting.Start();
                IPEndPoint endPointResponse = new IPEndPoint(this.localIP, this.portResponse);
                this.socketResponse = new Socket(endPointResponse.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                this.socketResponse.Bind(endPointResponse);
                this.threadResponse = new Thread(new ThreadStart(ResponseListener));
                this.threadResponse.Start(); 
                IPEndPoint endPointReceiveData = new IPEndPoint(this.localIP, this.portReceiveData);
                this.socketReceiveData = new Socket(endPointReceiveData.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                this.socketReceiveData.Bind(endPointReceiveData);
                this.threadReceiveData = new Thread(new ThreadStart(ReceiveDataListener));
                this.threadReceiveData.Start();
            }
            private void ReceiveMsgListener()
            {
                this.socketReceiveMsg.Listen(10);
                while (true)
                {
                    Socket socketTemp = this.socketReceiveMsg.Accept();
                    byte[] buffer = new byte[1024];
                    int byteCount = socketTemp.Receive(buffer);
                    string message = Encoding.Default.GetString(buffer);
                    this.rtbHistory.AppendText(message);
                }
            }
            //等待对方的文件发送请求
            private void WaitingListener()
            {
                this.socketWaiting.Listen(10);
                while (true)
                {
                    Socket socketTemp = this.socketWaiting.Accept();
                    this.Invoke(new MyDelegete(SaveShow),socketTemp);
                }
            }
            private delegate void MyDelegete(Socket socket);
            private void SaveShow(Socket socketTemp)
            {
                byte[] buffer = new byte[1024];
                int byteCount = socketTemp.Receive(buffer);
                string request = Encoding.Default.GetString(buffer, 0, byteCount);
                string fileName = request.Substring(0, request.IndexOf("[fileName]"));
                string ip = request.Substring(request.IndexOf("[fileName]") + 10, request.IndexOf("[ip]") - (request.IndexOf("[fileName]") + 10));
                string port = request.Substring(request.IndexOf("[ip]") + 4, request.IndexOf("[port]") - (request.IndexOf("[ip]") + 4));
                int remoteResponsePort = int.Parse(port);
                SaveFileDialog saveFileDlg = new SaveFileDialog();
                saveFileDlg.FileName = fileName;
                bool isReceive = false;
                if (saveFileDlg.ShowDialog() == DialogResult.OK)
                {
                    isReceive = true;
                    this.txtSaveAs.Text = saveFileDlg.FileName;
                }
                else
                {
                    isReceive = false;
                    this.txtSaveAs.Text = "";
                }
                //向发送方发出回复
                IPEndPoint endPointRemote = new IPEndPoint(IPAddress.Parse(this.txtRemoteIP.Text), remoteResponsePort);
                Socket socektResponse = new Socket(endPointRemote.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                socektResponse.Connect(endPointRemote);
                if (socektResponse.Connected)
                {
                    string messageResponse = string.Format("{0}[isReceive]{1}[port]",isReceive,this.portReceiveData);
                    byte[] bufferResponse = Encoding.Default.GetBytes(messageResponse);
                    socektResponse.Send(bufferResponse);
                }
            }
            //等到接收方的回复
            private void ResponseListener()
            {
                this.socketResponse.Listen(10);
                while (true)
                {
                    Socket socketTemp = this.socketResponse.Accept();
                    byte[] buffer = new byte[1024];
                    int byteCount = socketTemp.Receive(buffer);
                    string messageResponse = Encoding.Default.GetString(buffer, 0, byteCount);
                    bool isReceive = bool.Parse(messageResponse.Substring(0, messageResponse.IndexOf("[isReceive]")));
                    string portReceiveRemote = messageResponse.Substring(messageResponse.IndexOf("[isReceive]") + 11, messageResponse.IndexOf("[port]") - (messageResponse.IndexOf("[isReceive]") + 11));
                    if (isReceive)
                    {
                        //对方愿意接收文件,准备发送
                        IPEndPoint endPointRemote = new IPEndPoint(IPAddress.Parse(this.txtRemoteIP.Text), int.Parse(portReceiveRemote));
                        Socket socketTransmint = new Socket(endPointRemote.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                        socketTransmint.Connect(endPointRemote);
                        if (socketTransmint.Connected)
                        {
                            string filePath = this.txtFilePath.Text;
                            //创建文件流
                            FileStream fileStream = new FileStream(filePath, FileMode.Open);
                            //得到文件流的长度
                            //int fileSize = (int)fileStream.Length;
                            long fileSize = fileStream.Length;
                            //先将要发送的文件长度发送给接收方,让对方准备缓冲区
                            socketTransmint.Send(BitConverter.GetBytes(fileSize));
                            //定义一个每次要发送的文件的大小(10M)
                            //int partSize = 10 * 1024 * 1024;
                            long partSize = 50 * 1024 * 1024;
                            //int partCount = (int)fileSize / partSize;
                            long partCount = fileSize / partSize;
                            //int rest = fileSize % partSize;
                            long rest = fileSize % partSize;
                            for (int index = 0; index < partCount; index++)
                            {
                                byte[] bufferData = new byte[partSize];
                                fileStream.Read(bufferData, 0, (int)partSize);
                                socketTransmint.Send(bufferData);
                            }
                            if (rest != 0)
                            {
                                byte[] bufferData = new byte[rest];
                                fileStream.Read(bufferData, 0, (int)rest);
                                socketTransmint.Send(bufferData);
                            }
                                fileStream.Close();
                        }
                    }
                    else
                    {
                        MessageBox.Show("对方拒绝了您的发送请求!"); 
                    }
                }
            }
            //接收文件
            private void ReceiveDataListener()
            {
                this.socketReceiveData.Listen(10);
                while (true)
                {
                    Socket socketTemp = this.socketReceiveData.Accept();
                   // byte[] bufferSize = new byte[4];
                    byte[] bufferSize =new byte[8];
                    int byteCount = socketTemp.Receive(bufferSize);
                    //int fileSize = BitConverter.ToInt32(bufferSize, 0);
                    long fileSize = BitConverter.ToInt64(bufferSize, 0);
                    //定义一个已经接收的数据量的变量
                    //int finishSize = 0;
                    long finishSize = 0;
                    string fileSavePath = this.txtSaveAs.Text;
                    FileStream fileStream = new FileStream(fileSavePath, FileMode.Create);
                    while (finishSize < fileSize)
                    {
                        byte[] bufferData = new byte[8096];
                        int byteSize = socketTemp.Receive(bufferData);
                        fileStream.Write(bufferData, 0, byteSize);
                        finishSize += byteSize;
                    }
                    fileStream.Close();
                }
            }
            //文字消息发送
            private void btnSend_Click(object sender, EventArgs e)
            {
                IPEndPoint endPointRemote = new IPEndPoint(IPAddress.Parse(this.txtRemoteIP.Text), int.Parse(this.txtRemoteReceiveMsgPort.Text));
                Socket socketClient = new Socket(endPointRemote.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                socketClient.Connect(endPointRemote);
                if (socketClient.Connected)
                {
                    string message = this.txtMessage.Text;
                    byte[] buffer = Encoding.Default.GetBytes(message);
                    socketClient.Send(buffer);
                    this.rtbHistory.AppendText(message);
                    this.txtMessage.Text = "";       
                }
            }
            //发送文件
            private void btnBrowser_Click(object sender, EventArgs e)
            {
                OpenFileDialog openDlg = new OpenFileDialog();
                if (DialogResult.OK == openDlg.ShowDialog())
                {
                    this.txtFilePath.Text = openDlg.FileName;
                    string filePath = this.txtFilePath.Text;
                    string fileName = filePath.Substring(filePath.LastIndexOf(@"")+1); 
                    string ip = this.localIP.ToString();
                    string port = this.portResponse.ToString();
                    string message = string.Format("{0}[fileName]{1}[ip]{2}[port]",fileName,ip,port);
                    byte[] buffer = Encoding.Default.GetBytes(message);
                    IPEndPoint endPointRemote = new IPEndPoint(IPAddress.Parse(this.txtRemoteIP.Text), int.Parse(this.txtRemoteWaitingPort.Text));
                    Socket socketTemp = new Socket(endPointRemote.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    socketTemp.Connect(endPointRemote);
                    if (socketTemp.Connected)
                    {
                        socketTemp.Send(buffer);
                    }
                }
            }
            //关闭
            private void FormChat_FormClosed(object sender, FormClosedEventArgs e)
            {
                if (this.socketReceiveMsg != null)
                {
                    this.socketReceiveMsg.Close();
                }
                if (this.threadReceiveMsg != null)
                {
                    if (this.threadReceiveMsg.IsAlive)
                    {
                        this.threadReceiveMsg.Abort();
                    }
                }
                if (this.socketReceiveData != null)
                {
                    this.socketReceiveData.Close();
                }
                if (this.threadReceiveData != null)
                {
                    if (this.threadReceiveData.IsAlive)
                    {
                        this.threadReceiveData.Abort();
                    }
                }
                if (this.socketResponse != null)
                {
                    this.socketResponse.Close();
                }
                if (this.threadResponse != null)
                {
                    if (this.threadResponse.IsAlive)
                    {
                        this.threadResponse.Abort();
                    }
                }
                if (this.socketWaiting != null)
                {
                    this.socketWaiting.Close();
                }
                if (this.threadWaiting != null)
                {
                    if (this.threadWaiting.IsAlive)
                    {
                        this.threadWaiting.Abort();
                    }
                }
            }

        }
    }
  • 相关阅读:
    大话位运算
    Docker部署jar包
    linux系统备份mysql数据库
    关于Centos7 firewalld防火墙开放端口后仍不能访问ftp和nginx的问题解决
    MySql查询当天、本周、本月、本季度、本年的数据
    c#模拟线性回归
    监控服务器配置(五)-----Redis_exporter安装配置
    监控服务器配置(二)-----Grafana安装配置
    监控服务器配置(三)-----Node_exporter安装配置
    js网页唤起支付宝进行支付
  • 原文地址:https://www.cnblogs.com/shuenjian901/p/3586747.html
Copyright © 2011-2022 走看看