zoukankan      html  css  js  c++  java
  • 如何通过Socket TCP发送并接收一个文件?

    一.小结

    1.大包发小包收,只发一次。

    2.发时把文件扩展名,文件长度也随同一起发送,方便接收端接收时另存为正确的文件类型,并判断是否已经接收完毕。

       如果不一起发送,分为文件扩展名,文件长度,文件内容,发送三次,在接收端,也可能会一起收到,反而不利于解析。

    二.客户发送端代码

            private void btnSend_Click(object sender, EventArgs e)
            {
                //组合出远程终结点  
                IPAddress ipAddress = IPAddress.Parse(this.txtIP3.Text);
                IPEndPoint hostEP = new IPEndPoint(ipAddress, Convert.ToInt32(this.txtPort3.Text));
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    socket.Connect(hostEP);
    
                    //1.发送用户协议
                    string path1 = Environment.CurrentDirectory; //获取应用程序的当前工作目录。
                    string doc = "YourSendFile.pdf";
     string path = Path.Combine(path1, doc);
                    FileStream fs = File.Open(path, FileMode.Open);
    
                    //文件内容
                    byte[] bdata = new byte[fs.Length];
                    fs.Read(bdata, 0, bdata.Length);
                    fs.Close();
                    
                    //文件扩展名,固定3字节
                    byte[] fileExtArray = Encoding.UTF8.GetBytes(string.Format("{0:D3}", currentDocExt));
    
                    //文件长度, 固定为20字节,前面会自动补零
                    byte[] fileLengthArray = Encoding.UTF8.GetBytes(bdata.Length.ToString("D20"));
                    
                    //合并byte数组
                    byte[] fileArray = CombomBinaryArray(fileExtArray, fileLengthArray);
    
                    //合并byte数组
                    byte[] bdata1 = CombomBinaryArray(fileArray, bdata);
    
                    //发文件长度+文件内容
                    socket.Send(bdata1, bdata1.Length, 0);
    
                    //2.接收
                    //声明接收返回内容的字符串  
                    string recvStr = "";
    
                    //声明字节数组,一次接收数据的长度为 1024 字节  
                    byte[] recvBytes = new byte[1024];
    
                    //返回实际接收内容的字节数  
                    int bytes = 0;
    
                    //循环读取,直到接收完所有数据  
                    while (true)
                    {
                        bytes = socket.Receive(recvBytes, recvBytes.Length, 0);
                        //读取完成后退出循环  
                        if (bytes <= 0) break;
    
                        //将读取的字节数转换为字符串  
                        recvStr += Encoding.UTF8.GetString(recvBytes, 0, bytes);
                    }              
    
    
                    //禁用 Socket  
                    socket.Shutdown(SocketShutdown.Both);
    
                    //关闭 Socket  
                    socket.Close();
    
                    //... do some busness logic ...
    
                }
                catch (Exception e1)
                {
                    throw e1;
                }
            }

    三.服务接收端代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Net.Sockets;
    using System.Net;
    using System.Xml;
    using System.Configuration;
    using System.Windows.Forms;
    using System.IO;
    
    namespace ConsoleAppServer
    {
        class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                
                bool Done = false;
                IPAddress ipAddress = IPAddress.Parse(ConfigurationSettings.AppSettings["IP"].ToString());
                IPEndPoint hostEP = new IPEndPoint(ipAddress, Convert.ToInt32(ConfigurationSettings.AppSettings["Port"]));
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Bind(hostEP);
                socket.Listen(3);
                while (!Done)
                {
                    Console.WriteLine("waiting for client");
    
                    Socket client = socket.Accept();
    
                    Console.WriteLine("connected client");
    
                    //1.接收
                    //声明字节数组,一次接收数据的长度为 1024 字节  
                    byte[] recvBytes = new byte[1024];
                    //返回实际接收内容的字节数  
                    int bytes = 0;
                                    
                    int FileLength = 0; // 900866;
                    int ReceivedLength = 0;
    
                    //1.0 接收文件扩展名
                    bytes = client.Receive(recvBytes, 3, 0);
                    string fileExt = Encoding.UTF8.GetString(recvBytes, 0, bytes);
    
                    string vFilePath = Environment.CurrentDirectory;
                    string vFileName = vFilePath + "\Tmp" + Guid.NewGuid().ToString() + "." + fileExt;
    
                    //创建文件流,然后让文件流来根据路径创建一个文件
                    FileStream fs = new FileStream(vFileName, FileMode.Create);
    
                    //1.1 接收文件长度
                    bytes = client.Receive(recvBytes, 20, 0);
                    //将读取的字节数转换为字符串  
                    string fileLength = Encoding.UTF8.GetString(recvBytes, 0, bytes);
                    FileLength = Convert.ToInt32(fileLength);
    
                    //1.2接收文件内容
                    while (ReceivedLength < FileLength)
                    {
                        bytes = client.Receive(recvBytes, recvBytes.Length, 0);
                        ReceivedLength += bytes;
                        fs.Write(recvBytes, 0, bytes);
                    }
    
                    fs.Flush();
                    fs.Close();
    
    
                    //... do some business logic ...   
                   string returnData = SomeBusinessLogic();
    
                    //2.发送
                    byte[] bdata = Encoding.UTF8.GetBytes(returnData);
                    client.Send(bdata, bdata.Length, 0);
    
                    client.Close();
                }
    
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
            
        }
    }
  • 相关阅读:
    Javascript校验密码复杂度的正则表达式
    Git合并指定文件到另一个分支
    WebForm SignalR 实时消息推送
    基于SignalR的消息推送与二维码描登录实现
    yarn 错误There appears to be trouble with your network connection. Retrying...
    使用SqlConnectionStringBuilder构造数据库连接字符串
    邮箱核心业务领域建模
    C# NuGet常用命令
    阿里P7架构师是如何解决跨域问题的!你有遇到吗?
    WinForm 之 自定义标题栏的窗体移动
  • 原文地址:https://www.cnblogs.com/liuzhendong/p/4502621.html
Copyright © 2011-2022 走看看