第9章:网络编程


本章目标

  1. 熟悉网络编程相关协议

  2. 了解TCP协议 的通信原理

  3. 了解UDP协议的通信原理

  4. 掌握基于Socket 方式的网络编程

本章内容

相关概念

协议

TCP协议:

TCP是一种面向连接的、可靠的,基于字节流的传输层通信协议。为两台主机提供高可靠性的数据通信服务。它可以将源主机的数据无差错地传输到目标主机。当有数据要发送时,对应用进程送来的数据进行分片,以适合于在网络层中传输;当接收到网络层传来的分组时,它要对收到的分组进行确认,还要对丢失的分组设置超时重发等。为此TCP需要增加额外的许多开销,以便在数据传输过程中进行一些必要的控制,确保数据的可靠传输。因此,TCP传输的效率比较低。

UDP协议:

UDP是一种简单的、面向数据报的无连接的协议,提供的是不一定可靠的传输服务。所谓“无连接”是指在正式通信前不必与对方先建立连接,不管对方状态如何都直接发送过去。这与发手机短信非常相似,只要知道对方的手机号就可以了,不要考虑对方手机处于什么状态。UDP虽然不能保证数据传输的可靠性,但数据传输的效率较高。

IP

IP是Internet Protocol(网际互连协议)的缩写,是TCP/IP体系中的网络层协议。设计IP的目的是提高网络的可扩展性:一是解决互联网问题,实现大规模、异构网络的互联互通;二是分割顶层网络应用和底层网络技术之间的耦合关系,以利于两者的独立发展。根据端到端的设计原则,IP只为主机提供一种无连接、不可靠的、尽力而为的数据包传输服务。

A类 B类 C类 D类 E类
网络标志位 0 10 110 1110 11110
IP地址范围 1.0.0.0~ 127.255.255.255 128.0.0.0~ 191.255.255.255 192.0.0.0~ 223.255.255.255 224.0.0.0~ 239.255.255.255 240.0.0.0~ 247.255.255.255
可用IP地址范围 1.0.0.1~ 126.255.255.254 128.0.0.1~ 191.255.255.254 192.0.0.1~ 223.255.255.254
是否可以分配给主机使用
网络数量(个) 126 (2^7-2) 16384 (2^14) 2097152 (2^21)
每个网络中可容纳主机数(个) 16777214 (2^24-2) 65534 (2^16-2) 254 (2^8-2)
适用范围 大量主机的大型网络 中等规模主机数的网络 小型局域网 留给Internet体系结构委员会(IAB)使用【组播地址】 保留,仅作为搜索、Internet的实验和开发用

端口

端口“是英文port的意译,可以认为是设备与外界通讯交流的出口。端口可分为虚拟端口和物理端口,其中虚拟端口指计算机内部或交换机路由器内的端口,不可见。例如计算机中的80端口、21端口、23端口等。物理端口又称为接口,是可见端口,计算机背板的RJ45网口,交换机路由器集线器等RJ45端口。电话使用RJ11插口也属于物理端口的范畴。

核心类

DNS类

Dns类是一个静态类,它从 Internet 域名系统 (DNS) 检索关于特定主机的信息。在 IPHostEntry 类的实例中返回来自 DNS 查询的主机信息。 如果指定的主机在 DNS 数据库中有多个入口,则 IPHostEntry 包含多个 IP 地址和别名。

IPAddress类

IPAddress类提供了对IP地址的转换、处理等功能。其Parse方法可将IP地址字符串转换为IPAddress实例。如:

IPAddress ip = IPAddress.Parse(“192.168.1.1”);

IPEndPoint类

IPEndPoint类包含了应用程序连接到主机上的服务所需的IP地址和端口信息。

IPHostEntry类

IPHostEntry类将一个域名系统 (DNS) 主机名与一组别名和一组匹配的 IP 地址关联。

常用属性有:AddressList属性和HostName属性。

AddressList属性作用:获取或设置与主机关联的IP地址列表,是一个IPAddress类型的数组,包含了指定主机的所有IP地址;HostName属性则包含了服务器的主机名。

在Dns类中,有一个专门获取IPHostEntry对象的方法,通过IPHostEntry对象,可以获取本地或远程主机的相关IP地址。

Socket-TCP方式通信

服务端

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
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

namespace Socket_TCP_Server
{
/// <summary>
/// 基于TCP协议的Socket服务端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.创建服务端Socket
Socket serverSockekt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//2.绑定IP和端口
IPEndPoint point = new IPEndPoint(IPAddress.Parse("10.168.1.167"), 5555);
serverSockekt.Bind(point);

//3.启动监听(设置最大监听数量)
serverSockekt.Listen(100);
Console.WriteLine("服务端已启动,正在监听客户端....");

//4.等待客户端连接
while (true)
{
//客户端
Socket clientSocket= serverSockekt.Accept();

//为指定客户端开辟一个线程接收消息
new Thread(new ParameterizedThreadStart(Receive)).Start(clientSocket);
}
}

/// <summary>
/// 接收消息
/// </summary>
/// <param name="obj"></param>
static void Receive(object obj)
{
Socket socket = (Socket)obj;

//客户端终结点
IPEndPoint clientPoint = socket.RemoteEndPoint as IPEndPoint;
string ip = clientPoint.Address.ToString();

byte[] b = new byte[1024];


while (true)
{
int length = socket.Receive(b);
if (length == -1) continue;

string str = Encoding.UTF8.GetString(b,0,length);

Console.WriteLine(string.Format("{0}:{1}", ip, str));
}
}
}
}

客户端

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
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Socket_TCP_Client
{
/// <summary>
/// 基于TCP协议的Socket客户端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.Socket
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//2.连接到服务器(Ip地址和端口号要和服务器保持一致)
IPAddress ip = IPAddress.Parse("10.168.1.167");
IPEndPoint point = new IPEndPoint(ip, 5555);

try
{
socket.Connect(point);
Console.WriteLine("连接成功,请输入要发送的消息!");

//3.发送消息
Send(socket);
}
catch (Exception)
{
Console.WriteLine("服务端未启动");

}

Console.ReadKey();
}

static void Send(Socket socket)
{
while (true)
{
string msg = Console.ReadLine();
socket.Send(Encoding.UTF8.GetBytes(msg));
}
}
}
}

运行效果

Socket-UDP方式通信

服务端

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
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Socket_UDP_Server
{
/// <summary>
/// 基于UDP协议的服务端
/// </summary>
class Program
{
static Socket serverSocket = null;

static void Main(string[] args)
{
//创建Socket
serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);

//绑定ip和端口号
serverSocket.Bind(new IPEndPoint(IPAddress.Parse("10.168.1.167"), 5555));
Console.WriteLine("服务端已启动!");

//接收数据
new Thread(Receive).Start();

Console.ReadKey();
}

/// <summary>
/// 接收消息
/// </summary>
static void Receive()
{
//远程终结点
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);

byte[] b = new byte[1024];


while (true)
{
//接受消息
int length = serverSocket.ReceiveFrom(b, ref remoteEndPoint);

if (length == -1) continue;

string ip = ((IPEndPoint)remoteEndPoint).Address.ToString();
string str = Encoding.UTF8.GetString(b, 0, length);

Console.WriteLine(string.Format("{0}:{1}",ip , str));
}
}
}
}

客户端

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
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Socket_UDP_Client
{
/// <summary>
/// 基于UDP协议的Socket客户端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.客户端Socket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

IPEndPoint targetPoint = new IPEndPoint(IPAddress.Parse("10.168.1.167"), 5555);

//2.发送数据
Console.WriteLine("请输入要发送的数据!");
while (true)
{
string line = Console.ReadLine();
clientSocket.SendTo(Encoding.UTF8.GetBytes(line), targetPoint);
}

}
}
}

运行效果

Listener-TCP方式通信

服务端

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
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Text;

namespace TcpListener_Server
{
/// <summary>
/// 基于TCP协议的监听器 服务端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.对socket进行封装,tcpListener内本身包含套接字
TcpListener listener = new TcpListener(IPAddress.Parse("10.168.1.167"),5555);

//2.开始监听
listener.Start();
Console.WriteLine("服务端已启动监听...");

//3.等待客户端连接
TcpClient client = listener.AcceptTcpClient();

//4.获取客户端数据流通道
NetworkStream stream= client.GetStream();

//5.接收数据
byte[] b = new byte[1024];
while (true)
{

int length = stream.Read(b, 0, b.Length);
//string ip = client.Client.RemoteEndPoint.ToString().Split(':')[0];
string ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
string msg = Encoding.UTF8.GetString(b, 0, length);

Console.WriteLine(string.Format("{0}:{1}", ip, msg));
}

//6.释放资源
//tream.Close();
//client.Close();
//listener.Stop();

}
}
}

客户端

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
using System;
using System.Net.Sockets;
using System.Text;

namespace TcpListener_Client
{
/// <summary>
/// 基于TCP协议的监听器 客户端端
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.创建TCP对象的时候,就会与服务器建立联系
TcpClient client = new TcpClient("10.168.1.167", 5555);

//2.通过网络流获取数据信息
NetworkStream stream = client.GetStream();

Console.WriteLine("与服务端连接成功,请输入要发送的数据...");

while (true)
{
//手动输入需要发送的信息
string message = Console.ReadLine();
byte[] data = Encoding.UTF8.GetBytes(message);

//将信息写入网络流
stream.Write(data, 0, data.Length);
}

//3.释放资源
//stream.Close();
//client.Close();

Console.ReadKey();
}
}
}

运行效果

UdpClient方式通信

消息接收方

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UdpClient_Receive
{
/// <summary>
/// 基于UDP协议的UDPClinet 消息接收方
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.本地UDPClient
UdpClient udpLocal = new UdpClient(new IPEndPoint(IPAddress.Parse("10.168.1.167"), 5555));

//2.接收数据
IPEndPoint point = new IPEndPoint(IPAddress.Any, 0);

byte[] b = null;
Console.WriteLine("等待接收消息...");
while (true)
{
b = udpLocal.Receive(ref point);//通过point确定数据来自哪个ip和端口号,并返回接收的数据

string ip = point.Address.ToString();
string msg = Encoding.UTF8.GetString(b);

Console.WriteLine(string.Format("{0}:{1}", ip, msg));

}

Console.ReadKey();
}
}
}

消息发送方

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UdpClient_Send
{
/// <summary>
/// 基于UDP协议的UDPClinet 消息发送方
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.本地UdpClient
UdpClient client = new UdpClient();

//2.发送消息
Console.WriteLine("请输入要发送的消息...");
while (true)
{
string message = Console.ReadLine();
byte[] data = Encoding.UTF8.GetBytes(message);

client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("10.168.1.167"), 5555));
}

}
}
}

运行效果

综合案例1-局域网聊天室

N对N的方式实现局域网聊天室。

单播

单播地址是IP网络中最常见的。包含单播目标地址的分组发送给特定主机,一个这样的例子是,IP地址为192.168.1.5(源地址)的主机向IP地址为192.168.1.200(目标地址)的服务器请求网页,如下图所示

广播

广播分组的目标IP地址的主机部分全为1,这意味着本地网络(广播域)中的所有主机都将接收并查看该分组。诸如ARP和DHCP等很多网络协议都使用广播。

例如:

C类网络192.168.1.0的默认子网掩码为255.255.255.0(掩码的255个数对应网络的网络地址个数),其广播地址为192.168.1.255,其主机部分为十进制数255或二进制数11111111(全为1);

B类网络172.16.0.0的默认子网掩码为255.255.0.0,其广播地址为172.16.255.255

A类网络10.0.0.0的默认子网掩码为255.0.0.0,其广播地址为10.255.255.255

在以太网帧中,必须包含与广播IP地址对应的广播MAC地址。在以太网中,广播MAC地址长48位,其十六进制表示为FF-FF-FF-FF-FF-FF(全1为广播mac,主机地址为全1即广播ip地址)。图5.9所示的是一个广播IP分组。

多播

多播地址让源设备能够将分组发送给一组设备。属于多播组的设备将被分配一个多播组IP地址,多播地址范围为224.0.0.0~239.255.255.255。由于多播地址表示一组设备(有时被称为主机组),因此只能用作分组的目标地址。源地址总是为单播地址。

远程游戏就是一个使用多播地址的例子,很多玩家通过远程连接玩同一个游戏;另一例子是通过视频会议进行远程教学,其中很多学生连接到同一个教室。还有一个例子是硬盘映像应用程序,这种程序用于同时恢复众多硬盘的内容。

同单播地址和广播地址一样,多播IP地址也需要相应的多播MAC地址在本地网络中实际传送帧。多播MAC地址以十六进制值01-00-5E打头,余下的6个十六进制位是根据IP多播组地址的最后23位转换得到的。一个MAC多播地址是01-00-5E-0F-64-C5,如图5.10所示。每个十六进制位相对于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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Room2
{
public partial class Form1 : Form
{

//定义回调函数的委托
private delegate void AppentContentCallBack(string content);

//声明委托
private AppentContentCallBack appentContentCallBack;

public Form1()
{
InitializeComponent();
}

/// <summary>
/// 窗体加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
//实例化委托对象
appentContentCallBack = new AppentContentCallBack(AppendContent);

//开启线程,接收消息
Thread th = new Thread(ReciveMessage);
th.IsBackground = true;
th.Start();
}

private void button1_Click(object sender, EventArgs e)
{
try
{
// 广播地址,对于IPv4来说,255代表广播地址
IPAddress targetAddress=IPAddress.Parse("255.255.255.255");

//端口
int targetPort=5555;

//广播结点
IPEndPoint groupEP= new IPEndPoint(targetAddress, targetPort);

// UdpClient实例
UdpClient sendClient= new UdpClient();

// 设置广播选项
sendClient.EnableBroadcast = true;

//获取要发送的数据
string message = this.rtxtMsgSend.Text;
byte[] data = Encoding.UTF8.GetBytes(message);

// 发送广播数据
sendClient.Send(data, data.Length, groupEP);

this.rtxtMsgSend.Text = null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

/// <summary>
/// 接收消息
/// </summary>
public void ReciveMessage()
{
//1.本地UDPClient
UdpClient reciveClient = new UdpClient(new IPEndPoint(IPAddress.Any, 5555));//IPAddress.Parse("172.16.220.26")

//2.接收数据
IPEndPoint point = new IPEndPoint(IPAddress.Any, 0);

byte[] b = null;

while (true)
{
b = reciveClient.Receive(ref point);//通过point确定数据来自哪个ip和端口号,并返回接收的数据

string ip = point.Address.ToString();
int port = point.Port;
string msg = Encoding.UTF8.GetString(b);

string content = string.Format("{0}:{1}\n{2}", ip,port, msg);

//使用指定委托
this.rtxtMsgList.Invoke(appentContentCallBack, content);

}
}

/// <summary>
/// 追加内容
/// </summary>
/// <param name="content"></param>
public void AppendContent(string content)
{
this.rtxtMsgList.AppendText(content+"\n");
}
}
}

综合案例2-文件上传

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FileUpLoad_Server
{
internal class Program
{
static async Task Main(string[] args)
{
FileTransferServer server = new FileTransferServer(5555);
await server.StartAsync();

Console.ReadKey();
}
}
}

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace FileUpLoad_Server
{
/// <summary>
/// 文件上传服务类
/// </summary>
internal class FileTransferServer
{
private TcpListener listener;
private int port;

public FileTransferServer(int port)
{
this.port = port;
listener = new TcpListener(IPAddress.Any, port);
}

/// <summary>
/// 启动
/// </summary>
/// <returns></returns>
public async Task StartAsync()
{
listener.Start();
Console.WriteLine($"服务器已启动,IP:{this.GetIP()} 端口: {port}.");
while (true)
{
TcpClient client = await listener.AcceptTcpClientAsync();
await Task.Run(() => HandleClient(client));
}
}

/// <summary>
/// 处理客户端
/// </summary>
/// <param name="client"></param>
private void HandleClient(TcpClient client)
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
int bytesRead;

IPEndPoint point = client.Client.RemoteEndPoint as IPEndPoint;
try
{

string fileName = $"{point.Address}-{DateTime.Now.ToString("hhmmss")}.zip";
Console.WriteLine($"正在接收文件{fileName}...");

using (FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
fileStream.Write(buffer, 0, bytesRead);
}
}
Console.WriteLine($"文件{fileName}接收完成!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}

/// <summary>
/// 获取本机IP
/// </summary>
/// <returns></returns>
public string GetIP()
{
// 获取本地主机的相关信息
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());

string ip = "127.0.0.1";

// 遍历所有IP地址
foreach (IPAddress ipAddress in host.AddressList)
{
// 过滤掉IPv6地址和非本地链接地址
if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !IPAddress.IsLoopback(ipAddress))
{
ip = ipAddress.ToString();
}
}
return ip;
}
}
}

客户端

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FileUpLoad_Client
{
public partial class Form1 : Form
{
private string host;
private int port;

TcpClient server;

//定义回调函数的委托
private delegate void UpdateProgressCallBack(int length);

//声明委托
private UpdateProgressCallBack updateProgressCallBack;

int maxLength;

public Form1()
{
InitializeComponent();
}

/// <summary>
/// 连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
this.host = this.txtIP.Text.Trim();
this.port = int.Parse(this.txtPort.Text.Trim());

try
{
server = new TcpClient(host, port);
this.button1.Text = "OK";
this.button1.BackColor = Color.Green;
}
catch (Exception ex)
{
this.button1.Text = "Error";
this.button1.BackColor = Color.Red;
MessageBox.Show(ex.Message);
}
}

private void button2_Click(object sender, EventArgs e)
{
if (this.server == null)
{
MessageBox.Show("请先连接服务器!");
return;
}

//实例化回调委托对象
updateProgressCallBack = new UpdateProgressCallBack(UpdateProgress);

FileStream fileStream = new FileStream(this.txtFilePath.Text, FileMode.Open, FileAccess.Read);
this.progressBar1.Maximum = (int)fileStream.Length;
this.maxLength = (int)fileStream.Length;

//启动线程,发送文件
Thread th = new Thread(SendFile);
th.IsBackground = true;
th.Start();
}

/// <summary>
/// 发送文件
/// </summary>
public void SendFile()
{

//文件路径
string filePath = this.txtFilePath.Text.Trim();

try
{
//网络流
NetworkStream stream = server.GetStream();

//文件流
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024];
int bytesRead;

//从文件读取数据
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
//将数据写入网络流
stream.Write(buffer, 0, bytesRead);

//更新进度条
this.progressBar1.Invoke(updateProgressCallBack, bytesRead);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
server.Close();
}
}

/// <summary>
/// 更新进度条
/// </summary>
/// <param name="length"></param>
public void UpdateProgress(int length)
{
this.progressBar1.Value += length;
if (this.progressBar1.Value == this.maxLength)
{
MessageBox.Show("文件上传成功!");
}
}

/// <summary>
/// 选择文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void txtFilePath_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
{
this.txtFilePath.Text= this.openFileDialog1.FileName;
}
}
}
}

课后作业