[原创] 使用Tcp/Ip下载文件(图)
[原创] 使用Tcp/Ip下载文件(图)
使用Tcp/Ip下载文件(图) 简单设计思路是在服务器端启动TcpListener监听客户端的Socket连接。 当Client发送连接请求,TcpListener捕获当前请求的Socket,并获取收到的数据(字符串,称为命令)。 然后由命令处理程序分析字符串,如果字符串头部包含GET_FILE则为下载文件请求。 例:如客户机向服务器程序发送请求:"GET_FILE|D:\PUBLISH\TEST.DLL"。首先TcpListener捕获 当前请求的Socket,收到字符串,如果是下载文件请求就通过socket.SendFile(file="D:\PUBLISH\ TEST.DLL")将文件传送给当前Socket。在客户端由NetworkStream.Read()方法接收来自服务器发送的文件。 同理,如果实现网上象棋对战游戏,通过Socket.Send(命令)->分析->执行->移动棋子,不就实现了吗? Socket应用往往不止这些,学会Socket组件是网络编程基础。 服务器界面运行图。 客户机界面截图: 输入要下载的文件名及保存目录。
思考: 1.如果提供一个下载文件清单,是不是可以批量下载文件? 2.如果服务器上的文件与本机的文件最后修改日期相比较,是不是可以改装为版本升级程序? 3.如果客户端向服务器上传文件,是不是可以改装成mini版的ftp程序? 4.如果收到的byte[]是某对象的序列化数据,而后将byte[]还原成对象,是不是实现tcp/ip传送对象? 5.如果对象是一个电脑向另一个电脑传送的某个命令,是不是可以实现网上对战游戏? 6.你思想有多远socket就能走多远。
部分原代码: UpgraderClient.cs using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Net; using System.IO; namespace VJSDN.Tech.TcpIpDownloader { /// <summary> /// Tcp/ip下载器客户端 /// </summary> public class UpgraderClient { private OutputInvoke _writeOutput = null; public UpgraderClient(OutputInvoke writeOutput) { _writeOutput = writeOutput; } /// <summary> /// 下载文件 /// </summary> public bool DownloadFile(string file, string savePath) { string hostIp = "8.8.8.2"; //主机ip int hostPort = 12346; //主机端口 try { TcpClient client = new TcpClient(); client.ReceiveTimeout = 1000 * 60; if (client == null || file.Trim() == "") return false; TryConnect(client, hostIp, hostPort); //连接服务器 if (!client.Connected) return false;//连线线失败,退出 byte[] bs = Encoding.Unicode.GetBytes("GET_FILE|" + file); client.Client.Send(bs); //发送请求 //开始接受数据.... NetworkStream ns = client.GetStream(); MemoryStream ms = new System.IO.MemoryStream(); byte[] resBytes = new byte[256]; int resSize; do { resSize = ns.Read(resBytes, 0, resBytes.Length); string msg = Byte2Str(resBytes); if (msg.Trim().ToUpper() == "FILE_NOT_FOUND") { if (_writeOutput != null) _writeOutput("找不到文件:" + file); break; } if (resSize == 0) break; ms.Write(resBytes, 0, resSize); } while (ns.DataAvailable); if (ms.Length > 0) { FileStream fs = File.Open(savePath, FileMode.OpenOrCreate, FileAccess.Write); fs.Write(ms.ToArray(), 0, (int)ms.Length); fs.Flush(); fs.Close(); //关闭文件流 if (_writeOutput != null) _writeOutput("文件已下载:" + file); } ms.Close(); //关闭内存流 client.Close(); return true; } catch { return false; } } private string Byte2Str(byte[] buffer) { string msg = Encoding.Unicode.GetString(buffer).Replace("\0", ""); return msg.Trim(); } private void TryConnect(TcpClient client, string hostIP, int hostPort) { try { client.Connect(IPAddress.Parse(hostIP), hostPort); //连接服务器 } catch { throw new Exception("主机已关闭或网络存在问题,不能建立连线!"); } } } } UpgraderServer.cs using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Threading; using System.Net; using System.Windows.Forms; using System.IO; namespace VJSDN.Tech.TcpIpDownloader { public delegate void OutputInvoke(string msg); public class UpgraderServer { private TcpListener _ServerListener = null; //本地监听 private Thread _ServerListenerThread = null; //监听使用的线程 private bool _ServerRunning = false; private Form _owner = null; private OutputInvoke _writeOutput = null; public UpgraderServer(Form owner, OutputInvoke method) { _owner = owner; _writeOutput = method; } //启动服务器程序. 参数说明 ip:本地消息服务器IP地址; port:端口 public void StartListening(string ip, int port) { if (_ServerRunning) return; //构建监听 _ServerListener = new TcpListener(IPAddress.Parse(ip), port); _ServerListener.Start(255); _ServerRunning = true; //启动线程 _ServerListenerThread = new Thread(new ThreadStart(DoStartServerListener)); _ServerListenerThread.IsBackground = true; _ServerListenerThread.Start(); } //关闭服务器程序. public void Stop() { _ServerRunning = false; _ServerListenerThread.Abort(101); _ServerListenerThread = null; _ServerListener.Stop(); } /// <summary> ///启动服务器程序. /// </summary> private void DoStartServerListener() { //监听客户连线请求 while (_ServerRunning) { try { if (_ServerListener == null) return; //防止其它地方关闭监听 Application.DoEvents(); Socket socket = _ServerListener.AcceptSocket(); //有客户请求连接 if (socket == null) continue; byte[] buffer = new Byte[socket.ReceiveBufferSize]; int i = socket.Receive(buffer); //接收请求数据. if (i <= 0) continue; string msg = Encoding.Unicode.GetString(buffer).Replace("\0", ""); msg = msg.Trim(); if (msg.ToUpper().StartsWith("GET_FILE")) //命令字符串:GET_FILE|.\a.dll { string[] sps = msg.Split(new char[] { char.Parse("|") }); string file = sps[1]; //取出文件a.dll this.SendFile(socket, file); } socket.Close();// } catch (Exception ex) { if (ex is ThreadAbortException) { if ((ex as ThreadAbortException).ExceptionState.ToString() == "101") { _ServerRunning = false; ShowMessage("用户关闭服务器."); } else ShowMessage(ex.Message); } else { ShowMessage(ex.Message); } } } } private void ShowMessage(string msg) { _owner.Invoke(this._writeOutput,msg); } private void SendFile(Socket socket, string file) { if (File.Exists(file)) { ShowMessage("获取文件[" + file + "]...."); socket.SendFile(file); ShowMessage("[" + file + "]已发送."); } else { socket.Send(Encoding.Unicode.GetBytes("FILE_NOT_FOUND")); //通知客户程序 ShowMessage("[" + file + "]不存在."); } } } } 服务器界面代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using VJSDN.Tech.TcpIpDownloader; namespace VJSDN.Tech.TcpIpDownloaderServer { public partial class frmUpgraderServer : Form { private UpgraderServer _UpgradeListener = null; public frmUpgraderServer() { InitializeComponent(); } private void frmUpgraderServer_Load(object sender, EventArgs e) { // } private void btnStart_Click(object sender, EventArgs e) { string hostIp = "8.8.8.2"; int hostPort = 12346; _UpgradeListener = new UpgraderServer(this, this.Output); _UpgradeListener.StartListening(hostIp, hostPort); listBox1.Items.Add("已启动服务."); } private void btnStop_Click(object sender, EventArgs e) { if (_UpgradeListener != null) { _UpgradeListener.Stop(); _UpgradeListener = null; listBox1.Items.Add("已关闭服务."); } } public void Output(string msg) { this.listBox1.Items.Add(msg); } private void frmUpgraderServer_FormClosing(object sender, FormClosingEventArgs e) { if (_UpgradeListener != null) _UpgradeListener.Stop(); } } } 下载窗体代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using VJSDN.Tech.TcpIpDownloader; using System.IO; namespace TestProject { public partial class frmDownloader : Form { public frmDownloader() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string filename = Path.GetFileName(textBox1.Text); string local = textBox2.Text + @"\" + filename; bool ret = new UpgraderClient(this.ShowOutput).DownloadFile(textBox1.Text, local); if (ret) MessageBox.Show("下载完成!"); else MessageBox.Show("下载失败!"); } private void ShowOutput(string msg) { MessageBox.Show(msg); } } } 附完整源代码。解压后加载客户测试窗体到项目工程。 扫一扫加作者微信
参考文档:
[原创] 检查文件是否Flash格式(*.swf) 不使用配置文件构建和使用WCF服务(WCF Service) 使用ToolTipController自动提示GridView资料行的内容 使用DOC2CHM工具制作CHM帮助文件图解(原创) 使用.NET Reactor 5.0代码混淆加壳整个程序文件 使用Eziriz .NET Reactor 5.0 代码混淆加壳单个且独立的DLL文件 使用批处理文件(.bat)安装WCF服务失败解决方案 C#.NET IP地址工具类WebAPI服务器使用 WebApi接口使用HttpGet方式实现接受实体类参数(原创) C# 阿里云ECS服务器SMTP发送邮件使用80端口 - 原创! C#.NET IP端口绑定SSL证书支持HTTPS协议(用于Win服务自承载WebApi服务器) - C/S框架网原创 CSFramework.WebApi框架实现阿里云OSS上传、下载、删除文件功能 【原创】C# 深度拷贝对象 使用.NET反射+递归原理实现深度克隆 使用WebApi框架开发微信小程序后端程序详细设计说明书模板docx文件 C#使用Multipart form-data方式上传文件及提交其他数据
其它资料:
什么是C/S结构? | C/S框架核心组成部分 | C/S框架-WebService部署图 | C/S框架-权限管理 | C/S结构系统框架 - 5.1旗舰版介绍 | C/S结构系统框架 - 功能介绍 | C/S结构系统框架 - 产品列表 | C/S结构系统框架 - 应用展示(图) | 三层体系架构详解 | C/S架构轻量级快速开发框架 | C/S框架网客户案例 | WebApi快速开发框架 | C/S框架代码生成器 | 用户授权注册软件系统 | 版本自动升级软件 | 数据库底层应用框架 | CSFramework.CMS内容管理系统 | |