P2pSendImage.cs
上传用户:lqb116
上传日期:2014-04-04
资源大小:2712k
文件大小:14k
源码类别:

P2P编程

开发平台:

C#

  1. using System;
  2. using System.Collections;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Data;
  6. using System.Windows.Forms;
  7. using System.IO;
  8. namespace LanMsg.Controls
  9. {
  10. /// <summary>
  11. /// filesSend 的摘要说明。
  12. /// </summary>
  13. public class P2pSendImage : System.Windows.Forms.UserControl
  14. {
  15. private System.Windows.Forms.Panel panel1;
  16. private System.ComponentModel.IContainer components;
  17. private LanMsg.Controls.SockUDP sockUDP1;
  18. private System.Windows.Forms.Timer timer1;
  19. [Serializable]
  20. private class sendFileInfo
  21. {
  22. public int MsgInfoClass=0;//文件发送消息类别
  23. public long fileSize=0;//文件尺寸
  24. public int pSendPos=0;//标记上次发送的位置
  25. public byte[] FileBlock=null;//当前发送的文件块
  26. public sendFileInfo( )
  27. {
  28. //
  29. // TODO: 在此处添加构造函数逻辑
  30. //
  31. }
  32. public sendFileInfo(int msgInfoClass,long FileSize,int PSendPos,byte[] fileBlock )
  33. {
  34. MsgInfoClass=msgInfoClass;
  35. fileSize=FileSize;
  36. pSendPos=PSendPos;
  37. FileBlock=fileBlock;
  38. }
  39. }
  40. public P2pSendImage()
  41. {
  42. // 该调用是 Windows.Forms 窗体设计器所必需的。
  43. InitializeComponent();
  44. // TODO: 在 InitializeComponent 调用后添加任何初始化
  45. }
  46. /// <summary> 
  47. /// 清理所有正在使用的资源。
  48. /// </summary>
  49. protected override void Dispose( bool disposing )
  50. {
  51. try
  52. {
  53. this.fStream.Close();//关闭打开的文件资源
  54. }
  55. catch(Exception e){}
  56. try
  57. {
  58. if((this.IsSendState && !this.sendOver) || !IsCancel)//如果文件正在传输中且没有成功便被用户关闭程序以强行终止,则给对方发送"取消文件传输"
  59. this.sendData(new sendFileInfo(0,0,0,null));
  60. }
  61. catch(Exception e){}
  62. try
  63. {
  64. this.sockUDP1.CloseSock();//关闭sockUDP1端口,清楚占用的资源 
  65. }
  66. catch(Exception e){ }
  67. if( disposing )
  68. {
  69. if(components != null)
  70. {
  71. components.Dispose();
  72. }
  73. }
  74. base.Dispose( disposing );
  75. }
  76. #region 组件设计器生成的代码
  77. /// <summary> 
  78. /// 设计器支持所需的方法 - 不要使用代码编辑器 
  79. /// 修改此方法的内容。
  80. /// </summary>
  81. private void InitializeComponent()
  82. {
  83. this.components = new System.ComponentModel.Container();
  84. this.panel1 = new System.Windows.Forms.Panel();
  85. this.sockUDP1 = new LanMsg.Controls.SockUDP(this.components);
  86. this.timer1 = new System.Windows.Forms.Timer(this.components);
  87. this.SuspendLayout();
  88. // 
  89. // panel1
  90. // 
  91. this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
  92. this.panel1.Location = new System.Drawing.Point(0, 0);
  93. this.panel1.Name = "panel1";
  94. this.panel1.Size = new System.Drawing.Size(24, 24);
  95. this.panel1.TabIndex = 0;
  96. // 
  97. // sockUDP1
  98. // 
  99. this.sockUDP1.Server = null;
  100. this.sockUDP1.DataArrival += new LanMsg.Controls.SockUDP.DataArrivalEventHandler(this.sockUDP1_DataArrival);
  101. // 
  102. // timer1
  103. // 
  104. this.timer1.Interval = 500;
  105. this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
  106. // 
  107. // P2pSendImage
  108. // 
  109. this.BackColor = System.Drawing.Color.Cyan;
  110. this.Controls.Add(this.panel1);
  111. this.Name = "P2pSendImage";
  112. this.Size = new System.Drawing.Size(24, 24);
  113. this.ResumeLayout(false);
  114. }
  115. #endregion
  116. #region  文件传输事件
  117. public delegate void fileSendEndEventHandler(object sender,bool isSelf);//文件传输结束事件
  118. public  event fileSendEndEventHandler fileSendEnd; 
  119. public delegate void fileSendCancelEventHandler(object sender,bool isSelf);//取消文件传输事件
  120. public  event fileSendCancelEventHandler fileSendCancel; 
  121.     
  122. #endregion
  123. public string FileName=Application.StartupPath + @"ReceiveFiles";//发送或接收文件所保存的位置
  124. private System.Net.IPAddress serverIp=System.Net.IPAddress.Parse("127.0.0.1");//对方ip地址 
  125. private int serverPort=0;//对方Ip端口
  126. private long FileSize=0;//文件尺寸
  127. private string Extension="";//文件扩展名
  128. private bool IsSendState=false;//标记文件是否在发送过程中
  129. private int  pSendPos=0;//标记上次发送的位置
  130. private int buf=8000;//标记一次传输文件数据块的大小
  131. private System.IO.FileStream fStream ;//文件操作流
  132. private bool userCancelSend=false;//记录对方是否取消文件传输
  133. private bool sendOver=false;//标记文件是否传输完成
  134.        
  135. private bool IsSend=false;//标识当前用户是发送文件还是接收文件
  136. private bool IsCancel=false;//标识文件传输是点击“取消”而取消的
  137. private int  OutTime=0;//发送数据块超时读数器
  138. public void SetParameter(bool isSend,string LabFileName,string fileName,long fileSize,System.Net.IPAddress ServerIP,int ServerPort,string fileExtension)
  139. {
  140. //文件传输前建立双方连接的参数设置函数
  141. this.IsSend=isSend;
  142. this.FileSize=fileSize;
  143. this.serverIp=ServerIP;
  144. this.serverPort=ServerPort;
  145. this.Extension =fileExtension;
  146. this.labFileName.Text =LabFileName;//文件名称
  147. this.Listen();
  148. this.timer1.Enabled=true;//保持UDP端口在外网上的映射
  149. this.labelProgress.Text="(0/"+ this.FileSize.ToString() +")";
  150. if(IsSend)
  151. {
  152. this.FileName=fileName;//文件的绝对路径
  153. this.linkReceive.Visible=false;
  154. this.linkSaveAs.Visible=false;
  155. this.labOr.Visible=false;
  156. this.labelState.Text="等待对方接收文件...";
  157. }
  158. else
  159. {
  160. this.labelState.Text="对方正等待您接收文件...";
  161. this.sockUDP1.Send(this.serverIp,this.serverPort,new Controls.ClassSerializers().SerializeBinary(new sendFileInfo(100,0,0,null)).ToArray());
  162. }
  163. }
  164. public string GetSizeStr(long fileSize)//获得传输文件的尺寸字符串
  165. {
  166. if(Convert.ToInt32(fileSize/1024)==0)
  167. return fileSize.ToString() +"字节";
  168. if(Convert.ToInt32(fileSize/1024)>0 && Convert.ToInt32(fileSize/(1024*1024))==0)
  169. return Convert.ToInt32(fileSize/1024).ToString() +"KB";
  170. if(Convert.ToInt32(fileSize/(1024*1024))>0 && Convert.ToInt32(fileSize/(1024*1024*1024))==0)    
  171. return Convert.ToInt32(fileSize/(1024*1024)).ToString() +"MB";
  172. if(Convert.ToInt32(fileSize/(1024*1024*1024))>0)    
  173. return Convert.ToInt32(fileSize/(1024*1024*1024)).ToString() +"GB";
  174. return "未知大小";
  175. }
  176. private void linkLabelCancel_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  177. {
  178. if(MessageBox.Show("确定要终止文件的传输吗?","提示",System.Windows.Forms.MessageBoxButtons.YesNo,System.Windows.Forms.MessageBoxIcon.Question)==System.Windows.Forms.DialogResult.Yes )
  179. {
  180. if(!this.IsSendState)//如果当前还没有开始传输,则要发消息给对方,告诉对方已经取消文件传输
  181. IsCancel=true;//取消为真
  182. this.sendData(new sendFileInfo(0,0,0,null));//给对方发送“取消文件传输”消息
  183. fileSendCancel(this,true);//触发“文件取消发送事件”(自己取消的)
  184. }
  185. }
  186. private void linkSaveAs_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  187. {
  188. System.Windows.Forms.SaveFileDialog fd=new SaveFileDialog ();
  189. fd.Filter="文档(*"+ this.Extension +")|*"+ this.Extension;
  190. fd.FileName=this.labFileName.Text;
  191. if(fd.ShowDialog()==System.Windows.Forms.DialogResult.OK)
  192. {
  193. this.linkSaveAs.Visible=false;
  194. this.labOr.Visible=false;
  195. this.Refresh();
  196. this.FileName=fd.FileName;
  197. this.sendData (new sendFileInfo(1,0,0,null));//当用户单击接收文件时,发送消息给对方,要求对方开始发送文件数据块
  198. }
  199. }
  200. private void linkReceive_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  201. {
  202. this.sendData (new sendFileInfo(1,0,0,null));//当用户单击接收文件时,发送消息给对方,要求对方开始发送文件数据块
  203. }
  204. public void Listen()//UDP开始侦听来自外部的消息.
  205. {
  206. xx:
  207. System.Random i =new Random();
  208. int j= i.Next(2000,6000);
  209. try
  210. {
  211. this.sockUDP1.Listen (j);
  212. }
  213. catch(Exception e)
  214. {goto xx;}
  215. }
  216. private delegate void DataArrivaldelegate(byte[] Data, System.Net.IPAddress Ip, int Port); 
  217. private void DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port) 
  218. try
  219. {
  220. sendFileInfo  msg=new LanMsg.Controls.ClassSerializers().DeSerializeBinary((new System.IO.MemoryStream(Data))) as sendFileInfo ;
  221. serverIp=Ip;
  222. this.serverPort=Port;
  223.                 
  224. switch(msg.MsgInfoClass)
  225. {
  226. case 0://对方已经取消了文件传输
  227. userCancelSendFile();//对方“取消了文件传输”
  228. break;
  229. case 1://对方发送“发送文件请求”过来,要求发送文件过去
  230. ReadySendFile();//准备发送文件给对方
  231. break;
  232. case 2://对方发送文件数据过来,保存数据到文件
  233. ReceivedFileBlock(msg);
  234. break;
  235. case 3://对方发送消息告诉已经收到上一次发送的文件数据块
  236. ReceivedFileMsg(msg.pSendPos);
  237. break;
  238. }
  239. }
  240. catch(Exception e)
  241. {}
  242. }
  243. private void ReceivedFileMsg(int CurrPos)//对方发送文件数据过来
  244. {
  245. this.pSendPos=CurrPos;
  246. }
  247. private void ReceivedFileBlock(sendFileInfo  msg)//当对方发送文件数据块过来
  248. {
  249. if(this.pSendPos!=msg.pSendPos)return;
  250. this.labelState.Text="正在接收文件...";
  251. this.progressBar1.Maximum=(int)msg.fileSize;
  252. this.progressBar1.Value=this.progressBar1.Value + msg.FileBlock.Length;
  253. this.labelProgress.Text="("+ this.progressBar1.Value.ToString()+"/"+ this.progressBar1.Maximum.ToString()+")";//显示文件传输(接收)进度
  254. //            this.xpProgressBar1.PositionMax=(int)msg.fileSize;
  255. // this.xpProgressBar1.Position=this.progressBar1.Value + msg.FileBlock.Length;
  256. //            this.xpProgressBar1.Text="("+ this.progressBar1.Value.ToString()+"/"+ this.progressBar1.Maximum.ToString()+")";
  257.           
  258. this.pSendPos=(msg.pSendPos + msg.FileBlock.Length);//记录文件发送方当前发送文件块的起点位置
  259.            
  260. if(!IsSendState)//如果当前没有接收文件,则打开文件并保存数据块,如果当前文件是处于接收状态,则文件已经打开,不需要再执行打开操作
  261. fStream =new System.IO.FileStream(FileName , FileMode.Create, FileAccess.Write, FileShare.Read);
  262. fStream.Write(msg.FileBlock,0,msg.FileBlock.Length );//将收到的文件块存于文件中
  263. fStream.Flush();
  264. IsSendState=true;//标识当前正在传输文件
  265. this.sendData(new sendFileInfo(3,0,this.progressBar1.Value,null));//发送消息通知文件发送方已经收到数据并保存,可以继续发送下一文件块数据
  266. if(this.progressBar1.Value>=this.FileSize)//如果文件传输已经完成
  267. {
  268. IsSendState=false;//文件传输状态设置为否,表示文件没有在传输中
  269. this.sendOver=true;//文件发送完成值设为真
  270. fStream.Close(); //关闭打开的文件
  271. this.sockUDP1.CloseSock();
  272. IsCancel=true;//取消为真
  273. fileSendEnd(this,false);//触发文件传输结束事件
  274. }
  275. }
  276. private void ReadySendFile()//准备发送文件给对方
  277. {
  278. System.IO.FileInfo f=new FileInfo(this.FileName);
  279. if(!f.Exists)return;
  280. this.FileSize=f.Length;
  281. System.Threading.Thread RThread = new System.Threading.Thread( new System.Threading.ThreadStart(sendFileData)); 
  282. RThread.Start(); //开始发送文件
  283. }
  284. private void sendFileData()//发送文件
  285. {
  286. try
  287. {
  288. this.labelState.Text="正在发送文件...";
  289. this.progressBar1.Maximum=Convert.ToInt32(this.FileSize) ;
  290. //                this.xpProgressBar1.PositionMax=Convert.ToInt32(this.FileSize);
  291. byte[] buffer = new byte[buf];
  292. int i=0;//记录当前读取文件所获得的字节数
  293. int currSendPos=0;//设置当前发送的文件块的终点位置
  294. this.fStream  =new System.IO.FileStream(this.FileName , FileMode.Open, FileAccess.Read, FileShare.Read);//打开文件,准备发送数据
  295. this.IsSendState=true;//设置文件发送状态为真,表示文件正在发送中
  296. while(currSendPos<this.FileSize && !userCancelSend)//当前已发送文件的终点位置小于文件尺寸并且对方没有取消文件传输时执行发送文件下一区块数据 
  297. {
  298. if(currSendPos==this.pSendPos)//当对方收到的文件块终点位置等于前一次发送的文件块终点位置时才发送一下区块数据,确保文件发送的完整性
  299. {
  300. if((currSendPos+this.buf)>this.FileSize)//如果上次发送的数据位置加上缓冲区最大数BUF大于文件尺寸,则只发送最后一部分数据
  301. {
  302. buffer = new byte[Convert.ToInt32(this.FileSize-currSendPos)];
  303. }
  304. i=fStream.Read(buffer,0,buffer.Length);//将要发送的文件块数据存入发送缓冲区
  305. if(i!=0)//如果缓冲区中的数据不为空,则将数据发送给对方
  306. {
  307. this.sendData(new sendFileInfo(2,this.FileSize,currSendPos,buffer));//发送已读取的文件数据给对方
  308. currSendPos +=i;//上一次发送终点位置更改为这一次发送的终点位置
  309. this.progressBar1.Value= currSendPos;//更新进度条进度显示
  310. this.labelProgress.Text="("+ this.progressBar1.Value.ToString()+"/"+ this.progressBar1.Maximum.ToString()+")";
  311. // this.xpProgressBar1.Position =currSendPos;
  312. // this.xpProgressBar1.Text ="("+ this.progressBar1.Value.ToString()+"/"+ this.progressBar1.Maximum.ToString()+")";
  313.     
  314. }
  315. }
  316. }
  317. //程序执行到这里表示文件已经结束或是对方取消了文件传输
  318. fStream.Close(); //关闭打开的文件
  319. this.sockUDP1.CloseSock();//关闭通信端口
  320. IsSendState=false;//文件传输状态设置为否,表示文件没有在传输中
  321. IsCancel=true;//取消为真
  322. if(!userCancelSend)//如果对方没有取消文件传输而文件是正常传输结束,则标识
  323. {
  324. this.sendOver=true;
  325. fileSendEnd(this,true) ;//触发文件正常传输结束事件 
  326. }
  327. }
  328. catch(Exception e)
  329. {
  330. //MessageBox.Show(e.Message );
  331. }
  332. }
  333. private void userCancelSendFile()//当对方“取消了文件传输”
  334. {
  335. IsCancel=true;//取消为真
  336. fileSendCancel(this,false);//触发“文件取消发送事件”(对方取消的)
  337. }
  338. private void sockUDP1_DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)
  339. {
  340. DataArrivaldelegate outdelegate = new DataArrivaldelegate( DataArrival); 
  341. this.BeginInvoke (outdelegate, new object[]{ Data,Ip,Port}); 
  342. }
  343. private void sendData(sendFileInfo fInfo)
  344. {
  345. this.sockUDP1.Send(serverIp,this.serverPort,new Controls.ClassSerializers().SerializeBinary(fInfo).ToArray());
  346. }
  347. public void SendData(System.Net.IPAddress Ip,int Port,byte[] MsgContent)
  348. {
  349. this.sockUDP1.Send (Ip,Port,MsgContent);
  350. }
  351. private void timer1_Tick(object sender, System.EventArgs e)//保持UDP端口在外网上的映射
  352. {
  353. this.sockUDP1.Send(this.serverIp ,this.serverPort,new Controls.ClassSerializers().SerializeBinary(new sendFileInfo(100,0,0,null)).ToArray());
  354. }
  355. }
  356. }