分类: 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();
                }
            }
        }
    }
}

利用Socket进行大文件传输的更多相关文章

  1. WCF大文件传输服务

    由于项目需要,自己写一个基于WCF的大文件传输服务雏形.觉得有一定的参考价值,因此放在网上分享. 目前版本为v1.1特点如下: 1.文件传输端口为18650 2.上传和下载文件 3.支持获取文件传输状 ...

  2. php 利用socket上传文件

    php 利用socket上传文件 张映 发表于 2010-06-02 分类目录: php 一,利用fsockopen来上传文件 以前我写过一篇关于socket通信原理的博文http://blog.51 ...

  3. 转:wcf大文件传输解决之道(2)

    此篇文章主要是基于http协议应用于大文件传输中的应用,现在我们先解析下wcf中编码器的定义,编码器实现了类的编码,并负责将Message内存中消息转变为网络发送的字节流或者字节缓冲区(对于发送方而言 ...

  4. 转:wcf大文件传输解决之道(1)

    首先声明,文章思路源于MSDN中徐长龙老师的课程整理,加上自己的一些心得体会,先总结如下: 在应对与大文件传输的情况下,因为wcf默认采用的是缓存加载对象,也就是说将文件包一次性接受至缓存中,然后生成 ...

  5. WCF大文件传输【转】

    http://www.cnblogs.com/happygx/archive/2013/10/29/3393973.html WCF大文件传输 WCF传输文件的时候可以设置每次文件的传输大小,如果是小 ...

  6. AetherUpload大文件传输

    AetherUpload-Laravel是laravel框架下的一个大文件传输组件 github:https://github.com/peinhu/AetherUpload-Laravel 文件传输 ...

  7. 基于socket实现大文件上传

    import socket 1.客户端: 操作流程: 先拿到文件--->获取文件大小---->创建字典 1.制作表头 header  如何得到 他是一个二进制字符串 序列化得到 字典字符串 ...

  8. 大文件传输 分片上传 上传id 分片号 授权给第三方上传

    https://www.zhihu.com/question/39593108 作者:ZeroOne链接:https://www.zhihu.com/question/39593108/answer/ ...

  9. python tcp黏包和struct模块解决方法,大文件传输方法及MD5校验

    一.TCP协议 粘包现象 和解决方案 黏包现象让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)执行远程命令的模块 需要用到模块subprocess sub ...

随机推荐

  1. javaScript 预编译过程浅尝

    javaScript 预编译过程 1.创建AO对象(Activation Object) AO{ a: } 2.找形参和变量声明,将变量和形参作为AO属性名,值为undefined AO{ a:und ...

  2. Scrapy中将数据保存至数据库

    一.在settings.py文件中配置数据库连接参数 # 数据库连接参数 DB_HOST = '192.168.183.1' DB_PORT = 3306 DB_USER = 'root' DB_PA ...

  3. java中锁的理解

    在并发编程中,经常遇到多个线程访问同一个 共享资源 ,这时候作为开发者必须考虑如何维护数据一致性,在java中synchronized关键字被常用于维护数据一致性.synchronized机制是给共享 ...

  4. Python基础班培训视频课程

    课程目录:│  ├─第01天视频│  │      01-课程介绍.avi│  │      02-什么是操作系统.avi│  │      03-生活中的操作系统.avi│  │      04-操 ...

  5. Nginx模型 & 惊群问题

    这篇写的不错 http://www.cnblogs.com/linguoguo/p/5511293.html Nginx为啥性能高-多进程异步IO模型 1. 对于每个worker进程来说,独立的进程, ...

  6. ios in-house 公布整个过程(startssl认证)

    首先大体说一下步骤: 1.申请苹果enterprise 账号 为应用生成app id,provision profile等 详见:http://www.th7.cn/Program/IOS/20131 ...

  7. android中9-patch图片的使用

    看了非常多文章的介绍,9.png图片有两种区域:可扩展区和内容显示区. 弄了半天才明确什么叫做可扩展区,什么叫做内容显示区. 分享一下自己的理解. 下图是某博客的截图: 图片来自:http://blo ...

  8. 第一个WPF

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

  9. dfs算法中求数列的组合

    /* 从13个书中挑选5个值,他们的组合可能是 什么, 如下代码 dfs深度遍历, 和全排列是一种方法,但是思路不同 */ public class Main { static int count = ...

  10. POJ 2185 正解 KMP

    题意: 思路: 把每一行压成一个数 求一下 KMP 把每一列压成一个数 求一下KMP 答案就是两个周期之积 网上的好多题解都是错的---------.. //By SiriusRen #include ...