php 直播功能如何实现现基于TCP/IP的断点续传

& & & 其实在tcp/ip协议中传输文件可以保证传输的有效性,但有一个问题文件传了一部分连接意外断开了怎样;那这种情况只能在重新连接后继续传输,由于文件那部分已经传了那部分没有完成并不是tcp/ip的范围,所以需要自己来制定协议达到到这个目的。实现这个续传的协议制定其实也是非常简单,通过协议把文件按块来划分,每完成一个块就打上一个标记;即使是连接断了通过标记状态就知道还需要传那些内容。下面通过beetle来实现一个简单断点续传的程序(包括服务端和客户端)。
& & & 在实现之前先整理一下流程思路,首先提交一个发送请求信息包括(文件名,块大小,块的数量等),等对方确认后就进行文件块发送,对方接收块写入后返回一个标记,然后再继续发直到所有发送完成。思路明确后就制定协了:
文件传输申请信息
public class Post:MessageBase
public string FileN
public long S
public int PackageS
public int P
public Post()
FileID = Guid.NewGuid().ToString("N");
public class PostResponse : MessageBase
public string S
FileID这个值是用来协同工作的,两端根据这个ID来找到具体操作的文件和相关信息;Response提供了一个Status属性,可以用来提供一个错误的描述,如果无有任何值的情况说明对方允许这个行为.
文件块传输信息
public class PostPackage:MessageBase
public byte[] D
public int I
public class PostPackageResponse : MessageBase
public int I
public string S
文件块传输也是一个请求,一个应答;分别带的信息就是块数据信息和块的位置,同样也是根据Status信息来标记块的处理是否成功。
& & & 结构定义完成了,那就进行逻辑处理部分;不过为了调用更方便还需要封装一些东西,如根据块大小来划分文件块的数目,获取某一文件块的内容和写入文件某一些的内容等功能。
public static int GetFilePackages(long filesize)
if (filesize % PackageSize & 0)
count = Convert.ToInt32(filesize / PackageSize) + 1;
count = Convert.ToInt32(filesize / PackageSize);
public static byte[] FileRead(string filename, int index, int size)
using (Smark.Core.ObjectEnter oe = new Smark.Core.ObjectEnter(filename))
byte[] resutl =
long length = (long)index * (long)size +
using (System.IO.FileStream stream = System.IO.File.OpenRead(filename))
if (length & stream.Length)
resutl = new byte[stream.Length - ((long)index * (long)size)];
resutl = new byte[size];
stream.Seek((long)index * (long)size, System.IO.SeekOrigin.Begin);
stream.Read(resutl, 0, resutl.Length);
public static void FileWrite(string filename, int index, int size, byte[] data)
using (Smark.Core.ObjectEnter oe = new Smark.Core.ObjectEnter(filename))
using (System.IO.FileStream stream = System.IO.File.OpenWrite(filename))
stream.Seek((long)index * (long)size, System.IO.SeekOrigin.Begin);
stream.Write(data, 0, data.Length);
stream.Flush();
& & & 准备工作完成了,就开始写接收端的代码了。之前的文章已经介绍了Beetle如果创建一个服务和绑定分包机制,在这里就不多说了;看下接收的逻辑是怎样处理了.
接收传文件请求
public void Post(ChannelAdapter adapter, Beetle.FileTransfer.Post e)
string file = txtFolder.Text + e.FileN
PostResponse response = new PostResponse();
response.FileID = e.FileID;
response.ID = e.ID;
if (FileTransferUtils.CreateFile(file, e.Size))
Logics.FileItem item = new Logics.FileItem();
item.FileID = e.FileID;
item.FileName =
item.Packages = e.P
item.PackageSize = e.PackageS
item.Completed = 0;
item.Size = e.S
Logics.Access.Update(item);
AddItem(item);
response.Status = "不能创建文件!";
catch (Exception e_)
response.Status = e_.M
adapter.Send(response);
接收请求后根据信息创建临时文件,创建成功就把文件相关信息保存到数据库中,如果失败或处理异常就设置相关Status信息返回.
接收文件块请求
public void PostPackage(ChannelAdapter adapter, Beetle.FileTransfer.PostPackage e)
PostPackageResponse response = new PostPackageResponse();
response.FileID = e.FileID;
response.ID = e.ID;
Logics.FileListItem item = fileListBox1.GetAtFileID(e.FileID);
if (item != null)
FileTransferUtils.FileWrite(
item.Item.FileName + ".up", e.Index, item.Item.PackageSize, e.Data);
item.Completed(e.Index);
response.Index = e.I
if (item.Status == Logics.FileItemStatus.Completed)
FileTransferUtils.Rename(item.Item.FileName);
response.Status = "不存在上传信息!";
catch (Exception e_)
response.Status = e_.M
adapter.Send(response);
接收块请求后处理也很简单,根据FileID获取相关信息,然后把数据写入到文件对应的位置中;当所有块都已经完成后把临时文件名改会来就行了。如果处理异常很简单通过设置到Status成员中告诉请求方。
以下就是请求端的代码了,其代码比接收端更加简单了
public void PostResponse(ChannelAdapter adapter, Beetle.FileTransfer.PostResponse e)
mResponse =
mResetEvent.Set();
public void PostPackageResponse(ChannelAdapter adapter, Beetle.FileTransfer.PostPackageResponse e)
Logics.FileListItem item = fileListBox1.GetAtFileID(e.FileID);
if (item != null)
if (string.IsNullOrEmpty(e.Status))
item.Completed(e.Index);
PostPacakge(item);
item.Status = Logics.FileItemStatus.D
private void PostPacakge(Logics.FileListItem item)
if (mChannel != null && mChannel.Socket != null && item.Status == Logics.FileItemStatus.Working
&& item.Item.Completed != item.Item.Packages)
PostPackage post = new PostPackage();
post.FileID = item.Item.FileID;
post.Index = item.Item.C
post.Data = FileTransferUtils.FileRead(item.Item.FileName,
item.Item.Completed, item.Item.PackageSize);
mAdapter.Send(post);
请求端要做的工作就是发送文件传输请求,等回应后就处理PostPacakge进行文件块发送,接收到当前文件块处理成功后就发送下一块直接完成。
& & & 到这里断点续传的功能代码就已经完成,两边的程序已经可以工作。不过对于一些使用者来说希望程序更友好的表现工作情况,这个时候还得对UI下一点功夫,如看到当前传输的状态和每个文件进度情况等。
& & & 以上效果看起来很不错,那接下来就把它实现吧,程序使用ListBox来显示传输文件信息,要达到以上效果需要简单地重写一下OnDrawItem达到我们需要的。在讲述代码之前介绍一个图标网站,毕竟好的图标可以让程序生色不少。下面看下这个重写的代码:
protected override void OnDrawItem(DrawItemEventArgs e)
base.OnDrawItem(e);
StringFormat ListSF;
Point imgpoint = new Point(e.Bounds.X + 2, e.Bounds.Y + 1);
ListSF = StringFormat.GenericD
ListSF.LineAlignment = StringAlignment.C
ListSF.FormatFlags = StringFormatFlags.LineLimit | StringFormatFlags.NoW
ListSF.Trimming = StringTrimming.EllipsisC
Rectangle labelrect = new Rectangle(e.Bounds.X + 44, e.Bounds.Y, e.Bounds.Width - 44, e.Bounds.Height);
if (Site == null || Site.DesignMode == false)
if (e.Index &= 0)
FileListItem item = (FileListItem)Items[e.Index];
LinearGradientB
new LinearGradientBrush(e.Bounds, Color.FromArgb(208, 231, 253),
Color.FromArgb(10, 94, 177), LinearGradientMode.Horizontal);
double pent = (double)item.Item.Completed / (double)item.Item.P
using (brush)
e.Graphics.FillRectangle(brush, e.Bounds.X + 40, e.Bounds.Y + 2, Convert.ToInt32((e.Bounds.Width - 40) * pent), e.Bounds.Height - 4);
if (item.Status == FileItemStatus.Working)
mImgList.Draw(e.Graphics, imgpoint, 1);
else if (item.Status == FileItemStatus.Completed)
mImgList.Draw(e.Graphics, imgpoint, 2);
mImgList.Draw(e.Graphics, imgpoint, 0);
e.Graphics.DrawString(item.ToString(),new Font("Ariel", 9), new SolidBrush(Color.Black),labelrect, ListSF);
重绘代码就是根据当前文件的进度内容来计算出填冲的宽度,还有根据当前文件状态绘制不同的图标,是不是比较简单:)
整个功能完成了看下总体的效果怎样:
下载完整代码
如果需要Smark名称空间的代码可以到&
阅读(...) 评论()他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)基于TCP-IP编程_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
基于TCP-IP编程
阅读已结束,下载文档到电脑
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩3页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢502 Bad Gateway
502 Bad Gateway

我要回帖

更多关于 单点登录如何实现 的文章

 

随机推荐