我是靠谱客的博主 无语方盒,这篇文章主要介绍C#学习之文件传输,现在分享给大家,希望可以做个参考。

             最近一直在忙,今天正好抽空来总结下最近忙的东西。

           文件传输:c/s模式。这样摆在眼前的第一个问题就是 网络编程 , 这里,C#的网络编程,推荐去张子阳的博文学习学习,大牛写的,就是流弊。但是,最近他的博文网站上不去了,大家可以去找找其他人转载张子阳的博文。这里丢一个连接:http://download.csdn.net/detail/pemwoo/4934863, 转载博客:http://www.xuebuyuan.com/295625.html

        不废话了, 进入正题。

       1、 文件传输,服务器与客户端就要使用同一套协议。协议包括了传输消息的格式,还有关于消息的编码与解码。这个相当重要呢。 

       2、在传输数据的过程中,发送方发出去的数据类型是什么,接收方就要使用相同的数据类型的缓冲区去接收。(我就是因为这个,调试老半天了)。比如, 发送方某次发送数据类型为 long, 接收方却用 int 去接收,接收方只能接收前4个字节, 还有4个字节的数据在网络上。

       下面是关键部分代码:

        服务器:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
///---请求客户端文件(可执行文件) public void SendVersionContextToClient() { try { ///---发送消息格式为:文件名长度 、 文件名、内容长度、文件内容 ///------1、发送文件名长度 string filenName = "1.rar"; byte[] fileNameLen = BitConverter.GetBytes(filenName.Length); lock (ClientNetworkStream) { ClientNetworkStream.Write(fileNameLen, 0, fileNameLen.Length); ClientNetworkStream.Flush(); } ///-----2、发送文件名 byte[] byteFileName = Encoding.Default.GetBytes(filenName);//Encoding.Unicode.GetBytes(filenName); lock (ClientNetworkStream) { ClientNetworkStream.Write(byteFileName, 0, byteFileName.Length); ClientNetworkStream.Flush(); } ///---3、发送文件大小 string filePath = Environment.CurrentDirectory+@"" + filenName; ///---创建文件流 FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read); ///---获取文件大小 long fileLen = fileStream.Length; int int_FileLen = (int)fileLen; byte[] fileLenArr = BitConverter.GetBytes(int_FileLen); lock (ClientNetworkStream) { ClientNetworkStream.Write(fileLenArr, 0, fileLenArr.Length); ClientNetworkStream.Flush(); } ///---4、发送文件内容 lock (ClientNetworkStream) { ///---发送文件缓存:1KB byte[] readBuf = new byte[1024 * 16]; int readByte = 0; ///---读到的数据全部存入缓冲区 byte [] sendBuf = new byte[fileLen]; int count = 0; readByte = fileStream.Read(readBuf, 0, readBuf.Length); do { Array.Copy(readBuf, 0, sendBuf, count, readByte); count += readByte; ///---清空读文件缓存区 Array.Clear(readBuf, 0, readBuf.Length); ///---再次读取文件内容 readByte = fileStream.Read(readBuf, 0, readBuf.Length); } while (readByte > 0); Debug.WriteLine(count); ///---断开文件操作流 fileStream.Dispose(); fileStream.Close(); ///---发出去 ClientNetworkStream.Write(sendBuf, 0, sendBuf.Length); ClientNetworkStream.Flush(); } } catch (Exception ex) { Trace.WriteLine("failed to send versionContext to client. Reason :" + ex.Message); throw ex; } }

        客户端关键代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
private void Form1_Load(object sender, EventArgs e) { ///---建立套接字 TcpClient client = new TcpClient(); try { client.Connect("localhost", 8119); } catch (Exception ex) { Trace.WriteLine(ex.Message); return; } NetworkStream streamToServer = client.GetStream(); /-------------------------已经建立套接字连接 /---1、请求客户端版本号:长度|用户名|密码|消息类型(整型)|消息内容 //Request_FileVersion(ref streamToServer); /---2、接收服务器返回的消息 //byte[] recvBuf = new byte[4]; //int newVersion = Receive(streamToServer, recvBuf, 4); /---解码获取返回的版本号 //newVersion = BitConverter.ToInt32(recvBuf, 0); int curVersion = 0; ///---服务器返回的客户端版本号大于当前客户端版本号 ///接着向服务器发出请求:更新当前客户端 if (2 > curVersion) { ///---2.1、请求更新客户端 ReQuest_FileContext(streamToServer); ///---接收分为4步: ///---1、文件名长度 ///---2、文件名 ///---3、文件内容长度 ///---4、文件内容 ///---1、接收文件名长度,默认为4字节长,格式为 X.rar byte[] fileNameLenBuf = new byte[4]; Receive(streamToServer, fileNameLenBuf, 4); ///---获取文件名长度 int fileNameLen = BitConverter.ToInt32(fileNameLenBuf, 0); //MessageBox.Show(fileNameLen.ToString()); ///---2、接收文件名 byte[] fileNameByteBuf = new byte[fileNameLen]; int l1 = MyNetAPI.Receive(streamToServer, fileNameByteBuf, fileNameLen); ///---取出接收到的文件名 string recvFileName = Encoding.Default.GetString(fileNameByteBuf); //MessageBox.Show(recvFileName + " 长度:" + l1.ToString()); ///---3、接收文件内容长度 byte[] fileContextLen = new byte[4]; MyNetAPI.Receive(streamToServer, fileContextLen, 4); ///---取出文件长度,显示 int fileLength = BitConverter.ToInt32(fileContextLen, 0); //MessageBox.Show(fileLength.ToString() +" 文件内容长度"); ///---4、接收文件内容 byte[] fileContextByte = new byte[fileLength]; streamToServer.Flush(); int backLen = MyNetAPI.Receive(streamToServer, fileContextByte, fileLength); //MessageBox.Show("客户端接收到的文件的长度为:" + backLen.ToString()); try { ///---保存文件 ///--1、设置文件存储路径 string filePath = @"C:UsersRGDesktop第二进度ClientbinDebug"+ recvFileName; ///---保存文件 File.WriteAllBytes(filePath, fileContextByte); //MessageBox.Show("成功"); } catch (Exception ex) { streamToServer.Dispose(); streamToServer.Close(); client.Close(); MessageBox.Show(ex.Message); } } }

      客户端在接收代码中使用的函数 Recieve,能保证完整接收到服务器发送的数据。 Recieve原型如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/// <summary> /// 从网络从接收 wdatlen个字节数据到buf,必须收满后才返回 /// </summary> /// <param name="ns"></param> /// <param name="buf"></param> /// <param name="wdatlen">期望接收数据的长度</param> /// <returns></returns> public static int Receive(NetworkStream ns, byte[] buf, int wdatlen) { int count=0; int alen = 0; byte []tmp = new byte[wdatlen]; // 如果接收缓冲区不够长,直接返回 if (buf.Length < wdatlen) { return -1; } while (count < wdatlen) { try { alen = ns.Read(tmp, 0, tmp.Length); } // 网络断开异常 catch (IOException ex) { throw ex; } // 如果没有读到数据,继续读 if (alen == 0) { //throw new Exception("网络连接异常断开"); continue; } // 把每次收的加入到总的缓冲区 Array.Copy(tmp, 0, buf, count, alen); count += alen; } return count; }

      由于是项目代码, 就不丢完整代码链接了。 

提示自己:

                网络编程,慢慢磨吧, 路还长,

最后

以上就是无语方盒最近收集整理的关于C#学习之文件传输的全部内容,更多相关C#学习之文件传输内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(96)

评论列表共有 0 条评论

立即
投稿
返回
顶部