C#网络编程
1. 网络通信的方式2. Dns类、IPAddress类、IPEndPoint类和IPHostEntry类1)同步方式
同步方式是指当发送方发送一个数据包以后,一直等到接收方响应后,才可以发送下一个数据包。(串行运行)
2)异步方式
异步方式是指发送方发送数据包以后,不等接收方响应,就接着发送下一个数据包。(并行运行)
3)阻塞套接字
阻塞套接字是指在执行此套接字的网络调用时,直到调用成功才返回,否则此套接字就一直阻塞在网络调用上。
4)非阻塞套接字
非阻塞套接字是指在执行此套接字的网络调用时,不管是否执行成功,都立即返回。
1) Dns类
Dns类是一个静态类,它从 Internet 域名系统 (DNS) 检索关于特定主机的信息。在 IPHostEntry 类的实例中返回来自 DNS 查询的主机信息。 如果指定的主机在 DNS 数据库中有多个入口,则 IPHostEntry 包含多个 IP 地址和别名。
常用方法说明
方 法 名 称
说 明
BeginGetHostAddresses
异步返回指定主机的Internet协议(IP)地址
BeginGetHostEntry
已重载。将主机名或IP地址异步解析为IPHostEntry实例
EndGetHostAddresses
结束对DNS信息的异步请求
EndGetHostEntry
结束对DNS信息的异步请求
GetHostAddresses
返回指定主机的Internet协议(IP)地址
GetHostByAddress
已重载。获取IP地址的DNS主机信息
GetHostName
获取本地计算机的主机名
GetType
获取当前实例的类型
GetHostEntry
将主机名或IP地址解析为IPHostEntry实例
2) IPAddress类
IPAddress类提供了对IP地址的转换、处理等功能。其Parse方法可将IP地址字符串转换为IPAddress实例。如:
IPAddress ip = IPAddress.Parse(“192.168.1.1”);
3) IPEndPoint类
IPEndPoint类包含了应用程序连接到主机上的服务所需的IP地址和端口信息。
4) IPHostEntry类
IPHostEntry类将一个域名系统 (DNS) 主机名与一组别名和一组匹配的 IP 地址关联。
常用属性有:AddressList属性和HostName属性。
AddressList属性作用:获取或设置与主机关联的IP地址列表,是一个IPAddress类型的数组,包含了指定主机的所有IP地址;HostName属性则包含了服务器的主机名。
在Dns类中,有一个专门获取IPHostEntry对象的方法,通过IPHostEntry对象,可以获取本地或远程主机的相关IP地址。
例子:设计WinForm应用程序用于获取指定主机名的IP地址。
设计步骤如下:
①新建WinForm项目
新建WinForm项目并命名为“ParseDNS”。
②添加控件并设置属性
在Form1的设计视图中将此窗体调整到适当的大小并将 “Text”属性设置为“获取主机IP地址”。从工具箱中拖曳1个Button、2个Label和2个TextBox控件到窗体中,如图10.1所示布局控件。将label1、label2和button1的Text属性值分别设置为“主机名”、“IP地址:”和“获取”。
③添加命名空间
所要添加的命名空间为“using System.Net;”。
④添加事件及代码
双击“获取”按钮,其事件代码如下所示:
private void button1_Click(object sender, EventArgs e)
{
textBox2.Text = "";
try
{
IPHostEntry hostInfo = Dns.GetHostEntry(textBox1.Text.Trim());
textBox2.Text = "主机名:" + Dns.GetHostName() + "\r\n";
foreach(IPAddress ipadd in hostInfo.AddressList)
{
textBox2.Text += ipadd.ToString() + "\r\n";
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
⑤运行程序
按“Ctrl+F5”组合键运行程序,分别输入“www.baidu.com”和“baidu.com”,单击“获取”按钮,结果如图1和图2所示。
图1 图2
3.System.Net.Socket命名空间
TCP/IP的Socket则提供3种类型的套接字。
该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。
套接字处理数据两种基本模式:同步套接字和异步套接字。
同步套接字
其特点是在通过Socket进行连接、接收、发送操作时,客户机或服务器在接收到对方响应前会处于阻塞状态。它适用于数据处理不太多的场合。
异步套接字
在通过Socket进行连接、接收、发送操作时,客户机或服务器不会处于阻塞方式,而是利用callback机制进行连接、接收和发送处理,这样就可以在调用发送或接收的方法后直接返回,并继续执行下面的程序。
IP连接领域有两种通信类型:
面向连接的(connection-oriented) (TCP)
在面向连接的套接字中,使用TCP协议来建立两个IP地址端点之间的会话。一旦建立了这种连接,就可以在设备之间可靠的传输数据。
无连接的(connectionless) (UDP)
为了建立面向连接的套接字,服务器和客户端必须分别进行编程。 对于服务器端程序,建立的套接字必须绑定到用于TCP通信的本地IP地址和端口上。
网络流
流(stream)是对串行传输的数据的一种抽象表示,底层的设备可以是文件、外部设备、主存、网络套接字等。
C#在System.Net.Sockets名称空间中提供了一个专门的NetworkStream类,用于通过网络套接字发送和接收数据。NetworkStream类支持对网络数据的同步或异步访问,它可被视为在数据来源端和接收端之间架设了一个数据通道。
1) Socket类
.NET框架的System.NET.Sockets命名空间为需要严密控制网络访问的开发人员提供了WinSock接口的托管实现。
Socket类用于实现Berkeley套接字接口。
①Socket类的构造函数
Socket类的构造函数原型如下:
public Socket(
AddressFamily addressFamily,
SocketType socketType,
ProtocolType protocolType
);
构造函数使用3个参数来定义创建的Socket实例。AddressFamily用来指定网络类型;SocketType用来指定套接字类型(即数据连接方式);ProtocolType用来指定网络协议。3个参数均是在命名空间System.Net.Sockets中定义的枚举类型。但它们并不能任意组合,不当的组合反而会导致无效套接字。如对于常规的IP通信网络,AddressFamily只能使用AddressFamily.InterNetwork,此时可用的SocketType、ProtocolType组合如表1所示。
SocketType值
ProtocolType值
描 述
Stream
Tcp
面向连接套接字
Dgram
Udp
无连接套接字
Raw
Icmp
网际消息控制协议套接字
Raw
Raw
基础传输协议套接字
表1
2) TcpClient类
TcpClient类为TCP网络服务提供客户端连接,它构建于Socket类之上,以提供较高级别的TCP服务,即提供了通过网络连接、发送和接收数据的简单方法。用于在同步阻止模式下通过网络来连接、发送和接收流数据。另外,通过与NetworkStream对象的关联,使得用户可以通过流操作方式实现对网络连接状态下数据的发送和接收。 通过TcpClient类实现与TCP主机的通信流程如图3所示。
图3 TcpClient类与TCP主机的通信流程
1.创建TcpClient实例
TcpClient类有4种构造函数的重载形式,分别对应4种创建实例的方法。
①TcpClient( ),这种不带任何参数的构造函数将使用本机默认的IP地址并将使用默认的通信端口号0。当然,如果本机不止一个IP地址时将无法选择使用。
②TcpClient(AddressFamily),使用指定的地址族初始化TcpClient类的新实例。
③TcpClient(IPEndPoint),即使用本机IPEndPoint创建TcpClient的实例。其中IPEndPoint将网络端点表示为IP地址和端口号,用于指定在建立远程主机连接时所使用的本地网络接口IP地址和端口号。
④TcpClient (String, Int32),初始化 TcpClient 类的新实例并连接到指定主机上的指定端口。
因此,在TcpClient的构造函数中,如果没有指定远程主机名和端口号,它只是用来实例化TcpClient,同时实现与本地IP地址和Port端口的绑定。
2.与远程主机建立连接
如果在TcpClient的实例化过程中没有实现与远程主机的连接,则可以通过Connect方法来实现与指定远程主机的连接。Connect方法使用指定的主机名和端口号将客户端连接到远程主机,其使用方法如下。
①Connect(IPEndPoint),使用指定的远程网络终结点将客户端连接到远程TCP主机。
②Connect(IPAddress),使用指定的IP地址和端口号将客户端连接到远程TCP主机。
③Connect (IPAddress[],Int32),使用指定的IP地址和端口号将客户端连接到远程TCP主机。
④Connect(String, Int32),使用指定的主机名和端口号将客户端连接到指定主机上的指定端口。
如下代码段描述了TcpClient实例的创建以及与指定远程主机的连接过程。
m_client = new TcpClient( );
m_client.Connect(m_servername, m_port);
3.利用NetworkStream实例发送和接收数据
TcpClient类创建在Socket之上,提供了更高层次的TCP服务抽象,特别是在网络数据的发送和接收方面,TcpClient使用标准的Stream流处理技术,通过使用NetworkStream实例的读写操作来实现网络数据的接收和发送,因此更加方便直观。但NetworkStream与普通流Stream有所不同,NetworkStream没有当前位置的概念,不支持查找和对数据流的随机访问。
该方法首先通过TcpClient.GetStream来返回NetworkStream实例,进而利用所获取的NetworkStream实例的读写方法Write和Read来发送和接收数据,其实现代码如下所示。
rs = new StreamReader(m_client.GetStream( ));//获取接收数据的网络流实例
ws = m_client.GetStream( ); //获取发送数据的网络流实例
m_returnData = rs.ReadLine( ); //接收网络数据
Console.WriteLine(m_returnData);
ws.Write(data, 0, data.Length); //向网络发送数据
4.关闭TCP套接字
在与服务器完成通信后,应该调用Close( )方法释放所有的资源。
m_client.Close( );
3) TcpListener类
TcpClient类实现了客户端编程抽象,因此构建客户端网络应用程序便可以直接使用TcpClient取代Socket,更加方便易用。同样,对于服务器端应用程序的构建,C#提供了TcpListener类。该类也是构建于Socket之上,提供了更高抽象级别的TCP服务,使得程序员能更方便地编写服务器端应用程序。
通常情况下,服务器端应用程序在启动时将首先绑定本地网络接口的IP地址和端口号,然后进入侦听客户请求的状态,以便于客户端应用程序提出显式请求。一旦侦听到有客户端应用程序请求连接侦听端口,服务器端应用将接受请求,并建立一个负责与客户端应用程序通信的信道,即通过创建连接套接字与客户端应用程序建立连接,由连接套接字完成与客户端应用程序的数据传送操作,服务器端应用程序继续侦听更多的客户端连接请求。
TcpListener通过实例创建过程完成与本地网络接口的绑定,并由所创建的实例调用Start方法启动侦听;当侦听到客户端应用程序的连接请求后,根据客户端应用程序的不同请求方式,可以通过AcceptTcpClient方法接受传入的连接请求并创建TcpClient实例以处理请求,或者通过AcceptSocket方法接受传入的连接请求并创建Socket实例以处理请求,并由所创建的TcpClient实例或Socket实例完成与客户端应用程序的网络数据传输。最后,需要使用Stop关闭用于侦听传入连接的Socket,同时也必须关闭从AcceptSocket或AcceptTcpClient返回的任何实例,以释放相关资源。其实现流程如右图4所示。
图4 TcpListener类与客户机的通信流程
1.创建TcpListener实例
TcpListener类提供了3种构造函数的重载形式来创建TcpListener实例。
①TcpListener(port); //指定本机端口
②public TcpListener(IPEndPoint) //指定本机终结点
③public TcpListener(IPAddress,port) //指定本机IP地址及端口
分别根据指定的侦听端口、IPEndPoint对象(包含了IP地址和端口号)、IPAddress对象和端口号来创建TcpListener实例,并且实现与默认端口或指定IP地址和端口的绑定,如:
m_host = IPAddress.Parse(m_serverIP);
m_Listener = new TcpListener(m_host, m_port);
2.侦听
创建TcpListener实例后,便可以调用Start方法启动侦听,即该方法将调用TcpListener实例的基础Socket上的Listen方法,开始侦听客户的连接请求,如:
m_Listener.Start( );
3.接收连接请求
当侦听到有客户连接请求时,可以使用AcceptSocket或AcceptTcpClient接收任何当前在队列中挂起的连接请求。这两种方法分别返回一个Socket或TcpClient实例以接受客户的连接请求,如:
TcpClient m_client = m_Listener.AcceptTcpClient( );
通过返回的Socket或TcpClient实例来实现与提出连接请求的客户的单独网络数据传输。
4.收发数据
如果接收连接请求时返回的是Socket实例,则可以用Send和Receive方法实现与客户的通信。如果返回的是TcpClient实例,则可以通过对NetworkStream的读写来实现与客户的数据通信。由于服务器可以同时与多个客户建立连接并进行数据通信,因此往往会引入多线程技术,为每个客户的连接建立一个线程,在该线程中实现与客户的数据通信。如下代码所示。
//为每个客户连接创建并启动一个线程
TcpClient m_client = m_Listener.AcceptTcpClient( );
ClientHandle m_handle = new ClientHandle( );
m_handle.ClientSocket = m_client;
Thread m_clientthread =
new Thread(new ThreadStart(m_handle.ResponseClient));
m_clientthread.Start( );
//线程处理代码
public void ResponseClient( )
{
if (m_clientsocket != null)
{
StreamReader rs = new StreamReader(m_clientsocket.GetStream( ));
NetworkStream ws = m_clientsocket.GetStream( );
……
while (true)
{
//接收信息
m_returnData = rs.ReadLine( );
……
//回送信息
ws.Write(data, 0, data.Length);
……
}
m_clientsocket.Close( );
}
}
5.关闭连接
与客户程序通信完成之后,最后一步是停止侦听套接字,此时可以调用TcpListener的Stop方法来实现。
4) UdpClient类
与TcpClient和TcpListener类似,UdpClient也是构建于Socket类之上,提供了更高层次的UDP服务抽象,用于在阻止同步模式下发送和接收无连接 UDP 数据报,使用简单直观。
基于UdpClient的网络应用编程首先需要创建一个UdpClient类实例,接着通过调用其Connect方法连接到远程主机。当然,这两步也可以直接由指定远程主机名和端口号的UdpClient类构造函数完成。然后便可以利用Send和Receive方法来发送和接收数据。最后调用Close方法关闭UDP连接,并释放相关资源。其实现流程如图5所示。
图5 基于UdpClient的编程流程
5) NetWorkStream类
NetworkStream 类提供在阻止模式下通过 Stream 套接字发送和接收数据的方法。
转自:http://blog.csdn.net/yuzhongchun/article/details/11990571