📄 p2pfilessend.cs
字号:
{
set{_buf=value;}
get{return _buf;}
}
private int outTime=2;
[Category("全局设置")]
[Description("设置UDP每一次传输数据包的超时秒数")]
[DefaultValue(2)]
public int OutTime
{
set{outTime=value;}
get{return outTime;}
}
public void SetParameter(bool isSend,string LabFileName,string fileName,int fileSize,System.Net.IPAddress ServerIP,int ServerPort,string fileExtension)
{
//文件传输前建立双方连接的参数设置函数
this.IsSend=isSend;
this.FileSize=fileSize;
this.serverIp=ServerIP;
this.serverPort=ServerPort;
this.Extension =fileExtension;
this.labFileName.Text =LabFileName;//文件名称
this.Listen();
this.timer1.Enabled=true;//保持UDP端口在外网上的映射
this.PBar1.PositionMax =fileSize;
this.fileSizeStr=this.GetSizeStr(fileSize);//获得文件尺寸字符串
this.labProcess.Text ="(0/"+this.fileSizeStr+")";
if(IsSend)
{
this.FileName=fileName;//文件的绝对路径
this.linkSaveAs.Visible=false;
this.labOr.Visible=false;
this.labelState.Text="等待对方接收文件...";
}
else
{
this.labelState.Text="对方在等待您接收文件";
this.sockUDP1.Send(this.serverIp,this.serverPort,new ClassSerializers().SerializeBinary(new sendFileInfo(100,0,0,null)).ToArray());
}
}
private const float GB= 1024*1024*1024;
private const float MB= 1024*1024;
private const float KB= 1024;
public string GetSizeStr(int fileSize)//获得传输文件的尺寸字符串
{
try
{
float TempSize=fileSize/GB;
if(TempSize>1)
{
return TempSize.ToString("0.00") +"GB";
}
TempSize=fileSize/MB;
if(TempSize>1)
{
return TempSize.ToString("0.00") +"MB";
}
TempSize=fileSize/KB;
if(TempSize>1)
{
return TempSize.ToString("0.00") +"KB";
}
return fileSize+"字节";
}
catch{return fileSize+"字节";}
}
private void linkLabelCancel_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
{
if(MessageBox.Show("确定要终止文件的传输吗?","提示",System.Windows.Forms.MessageBoxButtons.YesNo,System.Windows.Forms.MessageBoxIcon.Question)==System.Windows.Forms.DialogResult.Yes )
{
if(!this.IsSendState)//如果当前还没有开始传输,则要发消息给对方,告诉对方已经取消文件传输
IsCancel=true;//取消为真
this.sendData(new sendFileInfo(0,0,0,null));//给对方发送“取消文件传输”消息
if(!this.IsSend )//如果是接收者
fileSendCancel(this,new FileSendEventArgs(true,this.labFileName.Text ));//触发“文件取消发送事件”(自己取消的)
}
}
private void linkSaveAs_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
{
try
{
System.Windows.Forms.SaveFileDialog fd=new SaveFileDialog ();
fd.Filter="所有文件(*"+ this.Extension +")|*"+ this.Extension;
fd.FileName=this.labFileName.Text;
if(fd.ShowDialog()==System.Windows.Forms.DialogResult.OK)
{
this.linkSaveAs.Visible=false;
this.labOr.Visible=false;
this.Refresh();
this.FileName=fd.FileName;
this.sendData (new sendFileInfo(1,0,0,null));//当用户单击接收文件时,发送消息给对方,要求对方开始发送文件数据块
this.fileSend(this,new FileSendEventArgs(true,this.labFileName.Text));//触发文件发送事件
}
}
catch{}
}
private void linkReceive_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
{
try
{
this.sendData (new sendFileInfo(1,0,0,null));//当用户单击接收文件时,发送消息给对方,要求对方开始发送文件数据块
}
catch{}
}
public void Listen()//UDP开始侦听来自外部的消息.
{
xx:
System.Random i =new Random();
int j= i.Next(2000,6000);
try
{
this.sockUDP1.Listen (j);
}
catch
{goto xx;}
}
private delegate void DataArrivaldelegate(byte[] Data, System.Net.IPAddress Ip, int Port);
private void DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)
{
try
{
sendFileInfo msg=new ClassSerializers().DeSerializeBinary((new System.IO.MemoryStream(Data))) as sendFileInfo ;
serverIp=Ip;
this.serverPort=Port;
switch(msg.MsgInfoClass)
{
case 0://对方已经取消了文件传输
userCancelSendFile();//对方“取消了文件传输”
break;
case 1://对方发送“发送文件请求”过来,要求发送文件过去
ReadySendFile();//准备发送文件给对方
break;
case 2://对方发送文件数据过来,保存数据到文件
ReceivedFileBlock(msg);
break;
case 3://对方发送消息告诉已经收到上一次发送的文件数据块
ReceivedFileMsg(msg.pSendPos);
break;
}
}
catch
{}
}
private void ReceivedFileMsg(int CurrPos)//对方发送文件数据过来
{
try
{
this.pSendPos=CurrPos;
}
catch{}
}
System.DateTime RecTime=System.DateTime.Now;//接收数据的时间间隔
int pRec=0;//上次接收的位置
private void ReceivedFileBlock(sendFileInfo msg)//当对方发送文件数据块过来
{
try
{
if(this.pSendPos!=msg.pSendPos)
{
this.sendData(new sendFileInfo(3,0,this.PBar1.Position,null));//发送消息通知文件发送方已经收到数据并保存,可以继续发送下一文件块数据
return;
}
this.pSendPos=(msg.pSendPos + msg.FileBlock.Length);//记录文件发送方当前发送文件块的起点位置
this.labelState.Text="正在接收...";
this.PBar1.Position=this.pSendPos;
if(!IsSendState)//如果当前没有接收文件,则打开文件并保存数据块,如果当前文件是处于接收状态,则文件已经打开,不需要再执行打开操作
{
fStream =new System.IO.FileStream(FileName , FileMode.Create, FileAccess.Write, FileShare.Read);
RecTime=System.DateTime.Now;//接收数据的时间间隔
}
fStream.Write(msg.FileBlock,0,msg.FileBlock.Length );//将收到的文件块存于文件中
fStream.Flush();
IsSendState=true;//标识当前正在传输文件
if(this.DateDiff(RecTime,System.DateTime.Now)>1)//计算速度
{
pRec=this.PBar1.Position -pRec;//发送速度
this.labProcess.Text ="剩余"+GetSpeedStr(pRec)+"\n(" + GetSizeStr(this.PBar1.Position) +"/"+ this.fileSizeStr +")";
pRec=this.PBar1.Position;
RecTime=System.DateTime.Now;
}
this.sendData(new sendFileInfo(3,0,this.PBar1.Position,null));//发送消息通知文件发送方已经收到数据并保存,可以继续发送下一文件块数据
if(this.PBar1.Position>=this.FileSize)//如果文件传输已经完成
{
IsSendState=false;//文件传输状态设置为否,表示文件没有在传输中
this.sendOver=true;//文件发送完成值设为真
fStream.Close(); //关闭打开的文件
this.sockUDP1.CloseSock();
IsCancel=true;//取消为真
fileSendEnd(this,new FileSendEventArgs(false,this.labFileName.Text));//触发文件传输结束事件
}
}
catch{}
}
private void ReadySendFile()//准备发送文件给对方
{
try
{
System.IO.FileInfo f=new FileInfo(this.FileName);
if(!f.Exists)return;
this.FileSize=(int)f.Length;
System.Threading.Thread RThread = new System.Threading.Thread( new System.Threading.ThreadStart(sendFileData));
RThread.Start(); //开始发送文件
this.fileSend(this,new FileSendEventArgs(false,this.labFileName.Text));//触发文件发送事件
}
catch{}
}
private void sendFileData()//发送文件
{
try
{
this.labelState.Text="正在发送...";
byte[] buffer = new byte[buf];
this.fStream =new System.IO.FileStream(this.FileName , FileMode.Open, FileAccess.Read, FileShare.Read);//打开文件,准备发送数据
this.IsSendState=true;//设置文件发送状态为真,表示文件正在发送中
System.DateTime sendTime =System.DateTime.Now;//超时读数器清零
System.DateTime sendS=System.DateTime.Now;//发送速度
int pSend=0;//当前发送的字节数
while(currSendPos<this.FileSize)//当前已发送文件的终点位置小于文件尺寸并且对方没有取消文件传输时执行发送文件下一区块数据 && !userCancelSend
{
if(currSendPos==this.pSendPos)//当对方收到的文件块终点位置等于前一次发送的文件块终点位置时才发送一下区块数据,确保文件发送的完整性
{
if((currSendPos+this.buf)>this.FileSize)//如果上次发送的数据位置加上缓冲区最大数BUF大于文件尺寸,则只发送最后一部分数据
{
buffer = new byte[Convert.ToInt32(this.FileSize-currSendPos)];
}
ReadCount=fStream.Read(buffer,0,buffer.Length);//将要发送的文件块数据存入发送缓冲区
if(ReadCount!=0)//如果缓冲区中的数据不为空,则将数据发送给对方
{
this.sendData(new sendFileInfo(2,this.FileSize,currSendPos,buffer));//发送已读取的文件数据给对方
currSendPos +=ReadCount;//上一次发送终点位置更改为这一次发送的终点位置
this.PBar1.Position = currSendPos;//更新进度条进度显示
sendTime=System.DateTime.Now;//超时读数器清零
}
}
if(this.IsCancel)//当对方取消文件传输时
{
fStream.Close(); //关闭打开的文件
fileSendCancel(this,new FileSendEventArgs(false,this.labFileName.Text) );//触发“文件取消发送事件”(对方取消的)
return;
}
if(this.currSendPos!=this.pSendPos && this.DateDiff(sendTime,System.DateTime.Now)>this.OutTime)//如果已经超时,则重新发送上次的数据包
{
//当对方收到的文件块终点位置不等于前一次发送的文件块终点位置时才发送一下区块数据并且已经起时
fileSendOutTime(this,new FileSendEventArgs(true,this.labFileName.Text));
this.sendData(new sendFileInfo(2,this.FileSize,(currSendPos-ReadCount),buffer));//发送已读取的文件数据给对方
sendTime=System.DateTime.Now;//超时读数器清零
}
if(this.DateDiff(sendS,System.DateTime.Now)>1)//计算速度
{
pSend=this.PBar1.Position -pSend;//发送速度
this.labProcess.Text ="剩余"+GetSpeedStr(pSend)+"\n(" + GetSizeStr(this.PBar1.Position) +"/"+ this.fileSizeStr +")";
pSend=this.PBar1.Position;
sendS=System.DateTime.Now;
}
}
//程序执行到这里表示文件已经结束或是对方取消了文件传输
fStream.Close(); //关闭打开的文件
this.sockUDP1.CloseSock();//关闭通信端口
IsSendState=false;//文件传输状态设置为否,表示文件没有在传输中
IsCancel=true;//取消为真
if(!userCancelSend)//如果对方没有取消文件传输而文件是正常传输结束,则标识
{
this.sendOver=true;
fileSendEnd(this,new FileSendEventArgs(true,this.labFileName.Text)) ;//触发文件正常传输结束事件
}
}
catch
{
}
}
private string GetSpeedStr(int SendByteCount)
{
try
{
int speed=(this.PBar1.PositionMax -this.PBar1.Position)/SendByteCount +1;
string s="";
int tempSpeed=speed / 3600;
if(tempSpeed>0)
{
s=tempSpeed.ToString() + "小时";
speed=speed % 3600;
}
tempSpeed=speed / 60;//获得分钟
if(tempSpeed>0)
{
s += tempSpeed.ToString() + "分";
speed=speed % 60;
}
s += speed.ToString() + "秒";
return s.ToString();
}
catch{return SendByteCount.ToString();}
}
private int DateDiff(DateTime DateTime1,DateTime DateTime2)
{
int dateDiff=0;
try
{
TimeSpan ts1=new TimeSpan(DateTime1.Ticks);
TimeSpan ts2=new TimeSpan(DateTime2.Ticks);
dateDiff=ts2.Subtract(ts1).Seconds;
}
catch
{}
return dateDiff;
}
private void userCancelSendFile()//当对方“取消了文件传输”
{
if(IsCancel)return;
IsCancel=true;//取消为真
if(!this.IsSend)//如果是接收者
fileSendCancel(this,new FileSendEventArgs(false,this.labFileName.Text) );//触发“文件取消发送事件”(对方取消的)
}
private void sockUDP1_DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)
{
DataArrivaldelegate outdelegate = new DataArrivaldelegate( DataArrival);
this.BeginInvoke (outdelegate, new object[]{ Data,Ip,Port});
}
private void sendData(sendFileInfo fInfo)
{
try
{
this.sockUDP1.Send(serverIp,this.serverPort,new ClassSerializers().SerializeBinary(fInfo).ToArray());
}
catch
{}
}
public void SendData(System.Net.IPAddress Ip,int Port,byte[] MsgContent)
{
try
{
this.sockUDP1.Send (Ip,Port,MsgContent);
}
catch{}
}
private void timer1_Tick(object sender, System.EventArgs e)//保持UDP端口在外网上的映射
{
try
{
this.sockUDP1.Send(this.serverIp ,this.serverPort,new ClassSerializers().SerializeBinary(new sendFileInfo(100,0,0,null)).ToArray());
}
catch{}
}
private void filesSend_fileSend(object sender, FileSendEventArgs e)
{
this.picWait.Visible=false;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -