www.9778.com 1

Socket网络通讯

网络编程

应用程序可以通过 TCPClient、TCPListener 和 UDPClient 类使用传输控制协议
(TCP) 和用户数据文报协议 (UDP) 服务。这些协议类建立在
System.Net.Sockets.Socket
类的基础之上,负责数据传送的细节。(也就是说TCPClient、TCPListener 和
UDPClient 类是用来简化Socket)

Microsoft.Net Framework为应用程序访问Internet提供了分层的、可扩展的以及受管辖的网络服务,其名字空间System.Net和System.Net.Sockets包含丰富的类可以开发多种网络应用程序。.Net类采用的分层结构允许应用程序在不同的控制级别上访问网络,开发人员可以根据需要选择针对不同的级别编制程序,这些级别几乎囊括了Internet的所有需要–从socket套接字到普通的请求/响应,更重要的是,这种分层是可以扩展的,能够适应Internet不断扩展的需要。 
   
  抛开ISO/OSI模型的7层构架,单从TCP/IP模型上的逻辑层面上看,.Net类可以视为包含3个层次:请求/响应层、应用协议层、传输层。WebReqeust和WebResponse 代表了请求/响应层,支持Http、Tcp和Udp的类组成了应用协议层,而Socket类处于传输层。  
   
  传输层位于这个结构的最底层,当其上面的应用协议层和请求/响应层不能满足应用程序的特殊需要时,就需要使用这一层进行Socket套接字编程。 
   
  而在.Net中,System.Net.Sockets 命名空间为需要严密控制网络访问的开发人员提供了 Windows Sockets (Winsock) 接口的托管实现。System.Net 命名空间中的所有其他网络访问类都建立在该套接字Socket实现之上,如TCPClient、TCPListener 和 UDPClient 类封装有关创建到 Internet 的 TCP 和 UDP 连接的详细信息;NetworkStream类则提供用于网络访问的基础数据流等,常见的许多Internet服务都可以见到Socket的踪影,如Telnet、Http、Email、Echo等,这些服务尽管通讯协议Protocol的定义不同,但是其基础的传输都是采用的Socket。 
   
  其实,Socket可以象流Stream一样被视为一个数据通道,这个通道架设在应用程序端(客户端)和远程服务器端之间,而后,数据的读取(接收)和写入(发送)均针对这个通道来进行。 
   
  可见,在应用程序端或者服务器端创建了Socket对象之后,就可以使用Send/SentTo方法将数据发送到连接的Socket,或者使用Receive/ReceiveFrom方法接收来自连接Socket的数据; 
   
  针对Socket编程,.NET 框架的 Socket 类是 Winsock32 API 提供的套接字服务的托管代码版本。其中为实现网络编程提供了大量的方法,大多数情况下,Socket 类方法只是将数据封送到它们的本机 Win32 副本中并处理任何必要的安全检查。如果你熟悉Winsock API函数,那么用Socket类编写网络程序会非常容易,当然,如果你不曾接触过,也不会太困难,跟随下面的解说,你会发觉使用Socket类开发windows 网络应用程序原来有规可寻,它们在大多数情况下遵循大致相同的步骤。 
   
  在使用之前,你需要首先创建Socket对象的实例,这可以通过Socket类的构造方法来实现: 

       
使用C#进行网络编程时,通常都需要用到System.Net命名空间、System.Net.Sockets命名空间和System.Net.Mail命名空间;

    TcpClient 和 TcpListener 使用 NetworkStream
类表示网络。使用 GetStream 方法返回网络流,然后调用该流的 Read 和 Write
方法。NetworkStream
不拥有协议类的基础套接字,因此关闭它并不影响套接字。

public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);

1.
System.Net命名空间:
为当前网络上使用的多种协议提供了简单的编程接口。

    UdpClient 类使用字节数组保存 UDP 数据文报。使用 Send
方法向网络发送数据,使用 Receive 方法接收传入的数据文报。

  其中,addressFamily 参数指定 Socket 使用的寻址方案,socketType 参数指定 Socket 的类型,protocolType 参数指定 Socket 使用的协议。 
   
  下面的示例语句创建一个 Socket,它可用于在基于 TCP/IP 的网络(如 Internet)上通讯。 

  1. DNS类:DNS是一个静态类,它从Internet域名系统(DNS)检索关于特定主机的信息,在IPHostEntry类的实例中返回来自DNS查询的主机信息。(GetHostName()找到本地系统的主机名,然后再用GetHostByName()找到主机的IP地址)
  2. IPAddress类:包含计算机在IP网络上的地址,主要用来提供网际协议(IP)地址。
  3. IPEndPoint类包含应用程序连接到主机上的服务所需要的主机和本地或远程端口信息。主要用来将网络端点表示为IP地址和端口号。
  4. WebClient类:提供向URL标识的任何本地、Intranet或Internet资源发送数据以及从这些资源接收数据的公共方法。
  5. WebRequest类:.Net
    Framework的请求/响应模型的抽象基类,用于访问Internet数据。使用该请求/响应模型的应用程序可以用协议不可知的方式从Internet请求数据。

1.TcpClient     TcpClient 类提供了一些简单的方法,用于在同步阻止模式下通过网络来连接、发送和接收流数据。为使
TcpClient 连接并交换数据,使用 TCP
ProtocolType
创建的
TcpListener

Socket
必须侦听是否有传入的连接请求。可以使用下面两种方法之一连接到该侦听器:
   (1)创建一个 TcpClient,并调用三个可用的
Connect
方法之一。    (2)使用远程主机的主机名和端口号创建
TcpClient。此构造函数将自动尝试一个连接。    
给继承者的说明要发送和接收数据,请使用
GetStream
方法来获取一个
NetworkStream。调用
NetworkStream 的
Write

Read
方法与远程主机之间发送和接收数据。使用
Close
方法释放与 TcpClient 关联的所有资源。
    下面的例子给出怎么利用TcpClient连接到服务器:

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

2. System.Net.Sockets命名空间

using System;

  若要使用 UDP 而不是 TCP,需要更改协议类型,如下面的示例所示: 

       
主要提供制作Sockets网络应用程序的相关类,其中Socket类,TcpClient类、TcpListener类和UdpClient类较为常用。在.NET框架下开发时,直接使用System.Net.Sockets名称空间中的Socket类编程较为复杂,而应用层的类TcpClient、TcpListener
和 UdpClient为 Socket
通信提供了更简单、对用户更友好的接口。它们和Socket类之间的这种层次关系如图

using
System.Collections.Generic;

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 

www.9778.com 1

using System.Text;

 一旦创建 Socket,在客户端,你将可以通过Connect方法连接到指定的服务器,并通过Send/SendTo方法向远程服务器发送数据,而后可以通过Receive/ReceiveFrom从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完 Socket 后,记住使用 Shutdown 方法禁用 Socket,并使用 Close 方法关闭 Socket。其间用到的方法/函数有: 

(1)Socket类:主要用于管理连接(将应用程序与端口连接起来,端口是一台计算机的数据都通过此连接网络,
Socket是基于流套接字协议(TCP协议)/基于数据报套接字协议(UDP协议)最为通用的API。),实现Berkeley通信端套接字接口,同时它还定义了绑定、连接网络端点及传输数据所需的各种方法。

using
System.Net.Sockets;

   
  Socket.Connect方法:建立到远程设备的连接 
  public void Connect(EndPoint remoteEP)(有重载方法) 
  Socket.Send 方法:从数据中的指示位置开始将数据发送到连接的 Socket。 
  public int Send(byte[], int, SocketFlags);(有重载方法) 
  Socket.SendTo 方法 将数据发送到特定终结点。 
  public int SendTo(byte[], EndPoint);(有重载方法) 
  Socket.Receive方法:将数据从连接的 Socket 接收到接收缓冲区的特定位置。 
  public int Receive(byte[],int,SocketFlags); 
  Socket.ReceiveFrom方法:接收数据缓冲区中特定位置的数据并存储终结点。 
  public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint); 
  Socket.Bind 方法:使 Socket 与一个本地终结点相关联: 
  public void Bind( EndPoint localEP ); 
  Socket.Listen方法:将 Socket 置于侦听状态。 
  public void Listen( int backlog ); 
  Socket.Accept方法:创建新的 Socket 以处理传入的连接请求。 
  public Socket Accept(); 
  Socket.Shutdown方法:禁用某 Socket 上的发送和接收 
  public void Shutdown( SocketShutdown how ); 
  Socket.Close方法:强制 Socket 连接关闭 
  public void Close(); 
   
   
  可以看出,以上许多方法包含EndPoint类型的参数,在Internet中,TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,在 .NET 框架中正是由 EndPoint 类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号,IPEndPoint 类形成到服务的连接点。 
   
  用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址,.Net中有两种类可以得到IP地址实例: 
   
  IPAddress类:IPAddress 类包含计算机在 IP 网络上的地址。其Parse方法可将 IP 地址字符串转换为 IPAddress 实例。下面的语句创建一个 IPAddress 实例: 

    1. void Bind(IPEndPoint
      localEP):绑定地址,使Socket与一个本地终节点相关联。
    2. Void Connect(IPEndPoint ip):建立连接
    3. Void Listen(int backlog):将Socket置于侦听状态,
      backlog最多可连接数。
    4. Int Receive(byte[] buffer):接收数据
    5. Int Receive (byte[] buffer,ref IPEndPoint
      ip):从指定地址接收数据
    6. Int Send(byte[] buffer):发送数据
    7. Int Send To(byte[] buffer,ref IPEndPoint
      remoteIP):向指定地址发送数据
    8. Void Shutdown(SocketShutdown
      how):关闭套接字,how指定不在允许执行的操作

using System.Net;

IPAddress myIP = IPAddress.Parse("192.168.1.2"); 

注:使用accept函数建立新的连接时,并不是使用原来的Socket进行通信,而是返回一个新的Socket套接字进行连接通信。原来的Socket继续进入监听状态,等待他人的连接要求。

 

  Dns 类:向使用 TCP/IP Internet 服务的应用程序提供域名服务。其Resolve 方法查询 DNS 服务器以将用户友好的域名(如”host.contoso.com”)映射到数字形式的 Internet 地址(如 192.168.1.1)。Resolve方法 返回一个 IPHostEnty 实例,该实例包含所请求名称的地址和别名的列表。大多数情况下,可以使用 AddressList 数组中返回的第一个地址。下面的代码获取一个 IPAddress 实例,该实例包含服务器 host.contoso.com 的 IP 地址。 

(2)TcpClient类:基于Socket类构建,用于在同步阻止模式下通过网络来连接,发送,接收数据。

namespace tcpclient

 IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com"); 
  IPAddress ipAddress = ipHostInfo.AddressList[0]; 

       
这是它能够以更高的抽象程度提供TCP服务的基础。体现在网络数据的发送和接受方面,是TcpClient使用NetworkStream网络流处理技术,使得它读写数据更加方便直观。TcpClient类专为客户端设计,它为
TCP 网络服务提供客户端连接。

{

你也可以使用GetHostName方法得到IPHostEntry实例: 

(3)NetworkStream网络流:可以被视为一个数据通道,架设在数据来源端(客户Client)和接收端(服务Server)之间,通过TcpClient.GetStream方法,返回用于发送和接收数据的网络流NetworkStream。

    class Program

 IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com"); 

       
注:要创建NetworkStream必须提供连接的Socket.默认情况下关闭NetworkStream并不会关闭所提供的Socket.如果要关闭Socket权限,则必须将ownsSocket构造函数参数的值指定为true.而后的数据读取及写入均针对这个通道来进行。不支持对网络流的随机访问。

    {

在使用以上方法时,你将可能需要处理以下几种异常: 

示例如下:通过以下方法得到NetworkStream网络流之后,就可以使用标准流读写方法Write和Read来发送和接受数据了。

        private static int
portNum = 11000;

   
  SocketException异常:访问Socket时操作系统发生错误引发 
   
  ArgumentNullException异常:参数为空引用引发 
   
  ObjectDisposedException异常:Socket已经关闭引发 
   
  在掌握上面得知识后,下面的代码将该服务器主机( host.contoso.com的 IP 地址与端口号组合,以便为连接创建远程终结点: 

1 TcpClient tcpClient = new TcpClient();             //创建TcpClient对象实例
2 tcpClient.Connect("www.baidu.com",4088);         //尝试与远程主机相连
3 NetworkStream stream=tcpClient.GetStream();      //获取网络传输流

        private static string hostName = Dns.GetHostName().ToString();

 IPEndPoint ipe = new IPEndPoint(ipAddress,11000);
  1. BeginRead():从NetworkStream开始一步读取
  2. BeginWrite():开始向流异步写入
  3. Close():关闭NetworkStream
  4. EndRead():处理异步读取结束
  5. EndWrite():处理异步写入结束
  6. Flush():刷新流中的数据
  7. Read():从流中读取
  8. ReadByte():从流中读取一个字节,并将流内的位置向前推进一个字节。到达末尾,返回-1。
  9. Write():将数据写入NetworkStream
  10. WriteByte():将一个字节写入流内的当前位置,并将流内的位置向前推进一个字节。

        public static void Main(String[] args)

 
 确定了远程设备的地址并选择了用于连接的端口后,应用程序可以尝试建立与远程设备的连接。下面的示例使用现有的 IPEndPoint 实例与远程设备连接,并捕获可能引发的异常: 

Server:获取基础网络Socket

        {

www.9778.com 2

  1. AcceptSocket/AcceptTcpClient:接受挂起的连接请求
  2. BeginAcceptSocket/BeginAcceptTcpClient:开始一个异步操作来接受一个传入的连接尝试
  3. Start:开始侦听传入的连接请求
  4. Stop:关闭侦听

            try

try { 
   s.Connect(ipe);//尝试连接 
  } 
  //处理参数为空引用异常 
   catch(ArgumentNullException ae) { 
   Console.WriteLine("ArgumentNullException : {0}", ae.ToString()); 
  } 
  //处理操作系统异常 
   catch(SocketException se) { 
   Console.WriteLine("SocketException : {0}", se.ToString()); 
  } 
   catch(Exception e) { 
   Console.WriteLine("Unexpected exception : {0}", e.ToString()); 
  } 

Client客户端连接侦听器的两种方法:

            {

www.9778.com 3

(1)创建一个TcpClient,并调用3个可用Connect方法之一。

               
Console.WriteLine(“主机名字:”+ Dns.GetHostName());

Socket网络通讯。 需要知道的是:Socket 类支持两种基本模式:同步和异步。其区别在于:在同步模式中,对执行网络操作的函数(如 Send 和 Receive)的调用一直等到操作完成后才将控制返回给调用程序。在异步模式中,这些调用立即返回。 

(2)使用远程主机的主机名和端口号创建TcpClient,此构造函数将自动尝试一个连接。

               
Console.WriteLine(“主机IP地址:”+ Dns.GetHostAddresses(Dns.GetHostName())[0]);

   
  另外,很多时候,Socket编程视情况不同需要在客户端和服务器端分别予以实现,在客户端编制应用程序向服务端指定端口发送请求,同时编制服务端应用程序处理该请求,这个过程在上面的阐述中已经提及;当然,并非所有的Socket编程都需要你严格编写这两端程序;视应用情况不同,你可以在客户端构造出请求字符串,服务器相应端口捕获这个请求,交由其公用服务程序进行处理。以下事例语句中的字符串就向远程主机提出页面请求: 
   
  string Get = “GET / HTTP/1.1rnHost: ” + server + “rnConnection: Closernrn”; 
   
  远程主机指定端口接受到这一请求后,就可利用其公用服务程序进行处理而不需要另行编制服务器端应用程序。 
   
  综合运用以上阐述的使用Visual C#进行Socket网络程序开发的知识,下面的程序段完整地实现了Web页面下载功能。用户只需在窗体上输入远程主机名(Dns 主机名或以点分隔的四部分表示法格式的 IP 地址)和预保存的本地文件名,并利用专门提供Http服务的80端口,就可以获取远程主机页面并保存在本地机指定文件中。如果保存格式是.htm格式,你就可以在Internet浏览器中打开该页面。适当添加代码,你甚至可以实现一个简单的浏览器程序。 
   
  实现此功能的主要源代码如下: 

  1. Client:获取或设置基础Socket
  2. ReceiveBufferSize:获取或设置接收缓冲区的大小
  3. SendBufferSize:获取或设置发送缓冲区的大小
  4. BeginConnect方法:开始一个对远程主机连接的异步请求
  5. Close:释放TcpClient 实例,不关闭基础连接
  6. Connect:使用指定的主机名和端口号将客户端连接到TCP主机
  7. GetStream:返回用于发送和接收数据的NetworkStream

                TcpClient client = new TcpClient(hostName, portNum);

www.9778.com 4

创建连接TCPClient连接方法:

               
NetworkStream ns =
client.GetStream();

   //"开始"按钮事件 
  private void button1_Click(object sender, System.EventArgs e) { 
   //取得预保存的文件名 
   string fileName=textBox3.Text.Trim(); 
   //远程主机 
   string hostName=textBox1.Text.Trim(); 
   //端口 
   int port=Int32.Parse(textBox2.Text.Trim()); 
   //得到主机信息 
   IPHostEntry ipInfo=Dns.GetHostByName(hostName); 
   //取得IPAddress[] 
   IPAddress[] ipAddr=ipInfo.AddressList; 
   //得到ip 
   IPAddress ip=ipAddr[0]; 
   //组合出远程终结点 
   IPEndPoint hostEP=new IPEndPoint(ip,port); 
   //创建Socket 实例 
   Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 
   try 
   { 
   //尝试连接 
   socket.Connect(hostEP); 
   } 
   catch(Exception se) 
   { 
   MessageBox.Show("连接错误"+se.Message,"提示信息 
   ,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); 
  } 
  //发送给远程主机的请求内容串 
  string sendStr="GET / HTTP/1.1rnHost: " + hostName + 
  "rnConnection: Closernrn"; 
   //创建bytes字节数组以转换发送串 
   byte[] bytesSendStr=new byte[1024]; 
   //将发送内容字符串转换成字节byte数组 
   bytesSendStr=Encoding.ASCII.GetBytes(sendStr); 
  try 
  { 
  //向主机发送请求 
  socket.Send(bytesSendStr,bytesSendStr.Length,0); 
  } 
  catch(Exception ce) 
   { 
   MessageBox.Show("发送错误:"+ce.Message,"提示信息 
   ,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); 
   } 
   //声明接收返回内容的字符串 
   string recvStr=""; 
   //声明字节数组,一次接收数据的长度为1024字节 
   byte[] recvBytes=new byte[1024]; 
   //返回实际接收内容的字节数 
   int bytes=0; 
  //循环读取,直到接收完所有数据 
  while(true) 
  { 
  bytes=socket.Receive(recvBytes,recvBytes.Length,0); 
  //读取完成后退出循环 
  if(bytes〈=0) 
  break; 
  //将读取的字节数转换为字符串 
  recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes); 
  } 
  //将所读取的字符串转换为字节数组 
  byte[] content=Encoding.ASCII.GetBytes(recvStr); 
   try 
   { 
   //创建文件流对象实例 
   FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite); 
  //写入文件 
  fs.Write(content,0,content.Length); 
  } 
  catch(Exception fe) 
   { 
   MessageBox.Show("文件创建/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); 
   } 
   //禁用Socket 
   socket.Shutdown(SocketShutdown.Both); 
   //关闭Socket 
   socket.Close(); 
   } 
   } 

(1)创建一个TcpClient,并调用三个可用的Connect()方法之一。

               
byte[] bytes = new byte[1024];

www.9778.com 5

  1. void
    Connect(IPEndPoint):使用指定的远程网络节点将客户端连接到远程TCP主机。

    1 IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList(0);//获取IP地址
    2 IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 60000);//设置端口
    3 TcpClient tcpClientA = new TcpClient(ipLocalEndPoint);//创建客户端
    

               
int bytesRead = ns.Read(bytes, 0,
bytes.Length);

 程序在WindowsXP中文版、.Net Frameworkd 中文正式版、Visual Studio.Net中文正式版下调试通过 

 

               
//将字节流解码为字符串

   
  关于作者 
   
  宋华,96年毕业于承德石油学院电子与电气系计算机应用专业,同年进入中国石油天然气集团公司吐哈油田工作,一直从事网络规划与建设、网站架构与设计,现专门从事Internet应用程序开发及Windows应用程序开发。

 2. void
Connect(IPAddress,int):使用指定的IP地址和端口号将客户端连接到TcpClient主机。

               
Console.WriteLine(Encoding.ASCII.GetString(bytes, 0,
bytesRead));

Visual C#.Net网络程序开发-Tcp篇

 3. void Connect(string,int):将客户端连接到指定主机上的指定端口。

               
client.Close();

前一篇《Visual C#.Net网络程序开发-Socket篇》中说到:支持Http、Tcp和Udp的类组成了TCP/IP三层模型(请求响应层、应用协议层、传输层)的中间层-应用协议层,该层的类比位于最底层的Socket类提供了更高层次的抽象,它们封装 TCP 和 UDP 套接字的创建,不需要处理连接的细节,这使得我们在编写套接字级别的协议时,可以更多地尝试使用 TCPClient 、 UDPClient和TcpListener,而不是直接向 Socket 中写。它们之间的这种层次关系示意如下: 
   
  可见, TcpClient 类基于 Socket 类构建,这是它能够以更高的抽象程度提供 TCP 服务的基础。正因为这样,许多应用层上的通讯协议,比如FTP(File Transfers Protocol)文件传输协议、HTTP(Hypertext Transfers Protocol)超文本传输协议等都直接创建在TcpClient等类之上。 
   
  TCPClient 类使用 TCP 从 Internet 资源请求数据。TCP 协议建立与远程终结点的连接,然后使用此连接发送和接收数据包。TCP 负责确保将数据包发送到终结点并在数据包到达时以正确的顺序对其进行组合。 
   
  从名字上就可以看出,TcpClient类专为客户端设计,它为 TCP 网络服务提供客户端连接。TcpClient 提供了通过网络连接、发送和接收数据的简单方法。 
   
  若要建立 TCP 连接,必须知道承载所需服务的网络设备的地址(IPAddress)以及该服务用于通讯的 TCP 端口 (Port)。Internet 分配号码机构 (Internet Assigned Numbers Authority, IANA) 定义公共服务的端口号(你可以访问 获得这方面更详细的资料)。IANA 列表中所没有的服务可使用 1,024 到 65,535 这一范围中的端口号。要创建这种连接,你可以选用TcpClient类的三种构造函数之一: 
   
  1、public TcpClient()当使用这种不带任何参数的构造函数时,将使用本机默认的ip地址并将使用默认的通信端口号0。这样情况下,如果本机不止一个ip地址,将无法选择使用。以下语句示例了如何使用默认构造函数来创建新的 TcpClient: 
   
  TcpClient tcpClientC = new TcpClient(); 
   
   
  2、public TcpClient(IPEndPoint)使用本机IPEndPoint创建TcpClient的实例对象。上一篇介绍过了,IPEndPoint将网络端点表示为IP地址和端口号,在这里它用于指定在建立远程主机连接时所使用的本地网络接口(IP 地址)和端口号,这个构造方法为使用本机IPAddress和Port提供了选择余地。下面的语句示例了如何使用本地终结点创建 TcpClient 类的实例: 
   
  IPHostEntry ipInfo=Dns.GetHostByName(“www.tuha.net”);//主机信息 
   IPAddressList[] ipList=ipInfo.AddressList;//IP地址数组 
   IPAddress ip=ipList[0];//多IP地址时一般用第一个 
   IPEndPoint ipEP=new IPEndPoint(ip,4088);//得到网络终结点 
   try{ 
   TcpClient tcpClientA = new TcpClient(ipLocalEndPoint); 
   } 
  catch (Exception e ) { 
   Console.WriteLine(e.ToString()); 
   } 
   
   
  到这里,你可能会感到困惑,客户端要和服务端创建连接,所指定的IP地址及通信端口号应该是远程服务器的呀!事实上的确如此,使用以上两种构造函数,你所实现的只是TcpClient实例对象与IP地址和Port端口的绑定,要完成连接,你还需要显式指定与远程主机的连接,这可以通过TcpClient类的Connect方法来实现, Connet方法使用指定的主机名和端口号将客户端连接到 远程主机: 
   
  1)、public void Connect(IPEndPoint); 使用指定的远程网络终结点将客户端连接到远程 TCP 主机。 
   
  public void Connect(IPAddress, int); 使用指定的 IP 地址和端口号将客户端连接到 TCP 主机。 
   
  public void Connect(string, int); 将客户端连接到指定主机上的指定端口。 
   
  需要指出的是,Connect方法的所有重载形式中的参数IPEndPoint网络终 
   
  结点、IPAddress以及表现为string的Dns主机名和int指出的Port端口均指的是远程服务器。 
   
  以下示例语句使用主机默认IP和Port端口号0与远程主机建立连接: 
   
  TcpClient tcpClient = new TcpClient();//创建TcpClient对象实例 
   try{ 
   tcpClient.Connect(“www.contoso.com”,11002);//建立连接 
   } 
   catch (Exception e ){ 
   Console.WriteLine(e.ToString()); 
   } 
   
   
  3、public TcpClient(string, int);初始化 TcpClient 类的新实例并连接到指定主机上的指定端口。与前两个构造函数不一样,这个构造函数将自动建立连接,你不再需要额外调用Connect方法,其中string类型的参数表示远程主机的Dns名,如:www.tuha.net。 
   
  以下示例语句调用这一方法实现与指定主机名和端口号的主机相连: 
   
  try{ 
   TcpClient tcpClientB = new TcpClient(“www.tuha.net”, 4088); 
   } 
   catch (Exception e ) { 
   Console.WriteLine(e.ToString()); 
   } 
  前面我们说,TcpClient类创建在Socket之上,在Tcp服务方面提供了更高层次的抽象,体现在网络数据的发送和接受方面,是TcpClient使用标准的Stream流处理技术,使得它读写数据更加方便直观,同时,.Net框架负责提供更丰富的结构来处理流,贯穿于整个.Net框架中的流具有更广泛的兼容性,构建在更一般化的流操作上的通用方法使我们不再需要困惑于文件的实际内容(HTML、XML 或其他任何内容),应用程序都将使用一致的方法(Stream.Write、Stream.Read) 发送和接收数据。另外,流在数据从 Internet 下载的过程中提供对数据的即时访问,可以在部分数据到达时立即开始处理,而不需要等待应用程序下载完整个数据集。.Net中通过NetworkStream类实现了这些处理技术。 
   
  NetworkStream 类包含在.Net框架的System.Net.Sockets 命名空间里,该类专门提供用于网络访问的基础数据流。NetworkStream 实现通过网络套接字发送和接收数据的标准.Net 框架流机制。NetworkStream 支持对网络数据流的同步和异步访问。NetworkStream 从 Stream 继承,后者提供了一组丰富的用于方便网络通讯的方法和属性。 
   
  同其它继承自抽象基类Stream的所有流一样,NetworkStream网络流也可以被视为一个数据通道,架设在数据来源端(客户Client)和接收端(服务Server)之间,而后的数据读取及写入均针对这个通道来进行。 
   
  .Net框架中,NetworkStream流支持两方面的操作: 
   
  1、 写入流。写入是从数据结构到流的数据传输。 
   
  2、读取流。读取是从流到数据结构(如字节数组)的数据传输。 
   
  与普通流Stream不同的是,网络流没有当前位置的统一概念,因此不支持查找和对数据流的随机访问。相应属性CanSeek 始终返回 false,而 Seek 和 Position 方法也将引发 NotSupportedException。 
   
  基于Socket上的应用协议方面,你可以通过以下两种方式获取NetworkStream网络数据流: 
   
  1、使用NetworkStream构造函数:public NetworkStream(Socket, FileAccess, bool);(有重载方法),它用指定的访问权限和指定的 Socket 所属权为指定的 Socket 创建 NetworkStream 类的新实例,使用前你需要创建Socket对象实例,并通过Socket.Connect方法建立与远程服务端的连接,而后才可以使用该方法得到网络传输流。示例如下: 
   
  Socket s=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//创建客户端Socket对象实例 
   try{ 
   s.Connect(“www.tuha.net”,4088);//建立与远程主机的连接 
   } 
   catch(Exception e){ 
   MessageBox.show(“连接错误:” +e.Message); 
   } 
   try{ 
   NetworkStream stream=new NetworkStream(s,FileAccess.ReadWrite,false);//取得网络传输流 
   } 
   
   
  2、通过TcpClient.GetStream方法:public NetworkStream etStream();它返回用于发送和接收数据的基础网络流NetworkStream。GetStream 通过将基础 Socket 用作它的构造函数参数来创建 NetworkStream 类的实例。使用前你需要先创TcpClient对象实例并建立与远程主机的连接,示例如下: 
   
  TcpClient tcpClient = new TcpClient();//创建TcpClient对象实例 
   Try{ 
   tcpClient.Connect(“www.tuha.net”,4088);//尝试与远程主机相连 
   } 
   catch(Exception e){ 
   MessageBox.Show(“连接错误:”+e.Message); 
   } 
   try{ 
   NetworkStream stream=tcpClient.GetStream();//获取网络传输流 
   } 
   catch(Exception e) 
   { 
   MessageBox.Show(“TcpClient错误:”+e.Message); 
   } 
   
   
  通过以上方法得到NetworkStream网络流之后,你就可以使用标准流读写方法Write和Read来发送和接受数据了。 
   
  以上是.Net下使用TcpClient类实现客户端编程的技术资料,为了向客户端提供这些服务,我们还需要编制相应的服务端程序,前一篇《Visual C#.Net网络程序开发-Socket篇》上曾经提到, Socket作为其他网络协议的基础,既可以面向客户端开发,也可以面向服务端开发,在传输层面上使用较多,而在应用协议层面上,客户端我们采用构建于Socket类之上的TcpClient取代Socket;相应地,构建于Socket之上的TcpListener提供了更高理念级别的 TCP 服务,使得我们能更方便地编写服务端应用程序。正是因为这样的原因,像FTP 和 HTTP 这样的应用层协议都是在 TcpListener 类的基础上建立的。 
   
  .Net中的TCPListener 用于监视TCP 端口上的传入请求,通过绑定本机IP地址和相应端口(这两者应与客户端的请求一致)创建TcpListener对象实例,并由Start方法启动侦听;当TcpListener侦听到用户端的连接后,视客户端的不同请求方式,通过AcceptTcpClient 方法接受传入的连接请求并创建 TcpClient 以处理请求,或者通过AcceptSocket 方法接受传入的连接请求并创建 Socket 以处理请求。最后,你需要使用 Stop 关闭用于侦听传入连接的 Socket,你必须也关闭从 AcceptSocket 或 AcceptTcpClient 返回的任何实例。这个过程详细解说如下: 
   
  首先,创建TcpListener对象实例,这通过TcpListener类的构造方法来实现: 
   
  public TcpListener(port);//指定本机端口 
  public TcpListener(IPEndPoint)//指定本机终结点 
  public TcpListener(IPAddress,port)//指定本机IP地址及端口 
   
   
  以上方法中的参数在前面多次提到,这里不再细述,唯一需要提醒的是,这些参数均针对服务端主机。下面的示例演示创建 TcpListener 类的实例: 
   
  IPHostEntry ipInfo=Dns.Resolve(“127.0.0.1”);//主机信息 
   IPAddressList[] ipList=ipInfo.IPAddressList;//IP数组 
   IPAddress ip=ipList[0];//IP 
   try{ 
   TcpListener tcpListener = new TcpListener(ipAddress, 4088);//创建TcpListener对象实例以侦听用户端连接 
   } 
   catch ( Exception e){ 
   MessageBox.Show(“TcpListener错误:”+e.Message); 
   } 
   
   
  随后,你需要调用Start方法启动侦听: 
   
  public void Start(); 
   
   
  其次,当侦听到有用户端连接时,需要接受挂起的连接请求,这通过调用以下两方法之一来完成连接: 
   
  public Socket AcceptSocket(); 
  public TcpClient AcceptTcpClient(); 
   
   
  前一个方法返回代表客户端的Socket对象,随后可以通过Socket 类的 Send 和 Receive 方法与远程计算机通讯;后一个方法返回代表客户端的TcpClient对象,随后使用上面介绍的 TcpClient.GetStream 方法获取 TcpClient 的基础网络流 NetworkStream,并使用流读写Read/Write方法与远程计算机通讯。 
   
  最后,请记住关闭侦听器:public void Stop(); 
   
  同时关闭其他连接实例:public void Close(); 
   
  下面的示例完整体现了上面的过程: 
   
  bool done = false; 
   TcpListener listener = new TcpListener(13);// 创建TcpListener对象实例(13号端口提供时间服务) 
   listener.Start();//启动侦听 
   while (!done) {//进入无限循环以侦听用户连接 
   TcpClient client = listener.AcceptTcpClient();//侦听到连接后创建客户端连接TcpClient 
   NetworkStream ns = client.GetStream();//得到网络传输流 
   byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());//预发送的内容(此为服务端时间)转换为字节数组以便写入流 
   try { 
   ns.Write(byteTime, 0, byteTime.Length);//写入流 
   ns.Close();//关闭流 
   client.Close();//关闭客户端连接 
   } 
  catch (Exception e) { 
   MessageBox.Show(“流错误:”+e.Message) 
   } 
        综合运用上面的知识,下面的实例实现了简单的网络通讯-双机互连,针对客户端和服务端分别编制了应用程序。客户端创建到服务端的连接,向远程主机发送连接请求连接信号,并发送交谈内容;远程主机端接收来自客户的连接,向客户端发回确认连接的信号,同时接收并显示客户端的交谈内容。在这个基础上,发挥你的创造力,你完全可以开发出一个基于程序语言(C#)级的聊天室! 
   
  客户端主要源代码:  

 1
TcpClient tcpClientB = new
TcpClient(“www.baidu.com”, 8888);//创建客户端 

            }

www.9778.com 6

(2)  使用远程主机的主机名和端口号创建TcpClient。

            catch (Exception e)

public void SendMeg()//发送信息 
   { 
  try 
  { 


  int port=Int32.Parse(textBox3.Text.ToString());//远程主机端口 
   try 
   { 
   tcpClient=new TcpClient(textBox1.Text,port);//创建TcpClient对象实例 } 
   catch(Exception le) 
   { 
   MessageBox.Show("TcpClient Error:"+le.Message); 
   } 
  string strDateLine=DateTime.Now.ToShortDateString()+" "+DateTime.Now.ToLongTimeString();//得到发送时客户端时间 
   netStream=tcpClient.GetStream();//得到网络流 
   sw=new StreamWriter(netStream);//创建TextWriter,向流中写字符 
   string words=textBox4.Text;//待发送的话 
   string content=strDateLine+words;//待发送内容 
   sw.Write(content);//写入流 
   sw.Close();//关闭流写入器 
   netStream.Close();//关闭网络流 
   tcpClient.Close();//关闭客户端连接 
  } 
  catch(Exception ex) 
   { 
   MessageBox.Show("Sending Message Failed!"+ex.Message); 
   } 
   textBox4.Text="";//清空 
   } 
1 TcpClient tcpClient = new TcpClient();//创建TcpClient对象实例
2 tcpClient.Connect("www.baidu.com",8080);//建立连接

            {

www.9778.com 7

       
注:要发送和接受数据,先使用GetStream()方法来获取一个NetworkStream,再调用NetworkStream的Write()和Read()方法与远程主机之间发送和接收数据。最后使用Close()方法释放与TcpClient()关联的所有资源。

               
Console.WriteLine(e.ToString());

  服务器端主要源代码: 

TcpListner:用于阻止同步模式下侦听和接受传入的连接请求。

            }

www.9778.com 8

       
可使用TcpClient类或Socket类来连接TcpListener,并且可以使用IPEndPoint、本地IP地址及端口号来创建TcpListener实例对象。

    

public void StartListen()//侦听特定端口的用户请求 
   { 
  //ReceiveMeg(); 
  isLinked=false; //连接标志 
   try 
   { 
   int port=Int32.Parse(textBox1.Text.ToString());//本地待侦听端口 
   serverListener=new TcpListener(port);//创建TcpListener对象实例 
   serverListener.Start(); //启动侦听 
   } 
   catch(Exception ex) 
   { 
   MessageBox.Show("Can‘t Start Server"+ex.Message); 
   return; 
   } 
   isLinked=true; 
   while(true)//进入无限循环等待用户端连接 
   { 
   try 
   { 
   tcpClient=serverListener.AcceptTcpClient();//创建客户端连接对象 
   netStream=tcpClient.GetStream();//得到网络流 
   sr=new StreamReader(netStream);//流读写器 
   } 
   catch(Exception re) 
   { 
   MessageBox.Show(re.Message); 
   } 
   string buffer=""; 
  string received=""; 
   received+=sr.ReadLine();//读流中一行 
   while(received.Length!=0) 
   { 
   buffer+=received; 
   buffer+="rn"; 
   //received=""; 
   received=sr.ReadLine(); 
   } 
  listBox1.Items.Add(buffer);//显示 
  //关闭 
  sr.Close(); 
  netStream.Close(); 
  tcpClient.Close(); 
  } 
  }  

       
.Net中的TcpListener主要作用是监视TCP端口上客户端的请求,通过绑定本机IP地址和相应端口创建TcpListener对象实例,并由Start方法启动侦听;当TcpListener侦听到用户端的连接后,通过AcceptTcpClient方法接受传入的连接请求并创建TcpClient以处理请求,或者通过AcceptSocket方法接受传入的连接请求并创建Socket以处理请求。

        }

www.9778.com 9

(1)创建服务器端:

    }

 

 1 //建立TCP监听器TcpListener对象。
 2  TcpListener tl=new TcpListener(端口号);
 3 //启动监听器
 4 tl.Start();
 5 //用监听器获取连接进来的套接字(Socket)
 6 Socket s=myList.AcceptSocket();
 7 //通过Socket的Receive方法获取客户端发送的数据
 8 byte [] result=new byte[1024];
 9 int k=s.Receive(result);
10 //通过Socket的Send方法向客户端发送数据
11 byte[] st=System.Text.Encoding.Default.GetBytes(“text”);
12 s.Send(st);
13 //在通讯结束后,需要释放资源结束监听
14 s.Close();
15 tl.Stop();

}

Socket建立服务器:初始化监听Socket   接受新的客户端连接   收发数据  
关闭连接

2.TcpListener    TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求。可使用
TcpClient

Socket
来连接 TcpListener。可使用
IPEndPoint、本地
IP 地址及端口号或者仅使用端口号,来创建 TcpListener。可以将本地 IP
地址指定为
Any,将本地端口号指定为
0(如果希望基础服务提供程序为您分配这些值)。如果您选择这样做,可在连接套接字后使用
LocalEndpoint
属性来标识已指定的信息。

1 socketServer = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//创建Socket 客户端
2 //Socket绑定本地端口监听客户端连接;
3 Socket.Bind(端口号);
4 Socket.Listen();
5 socket.Receive();//创建连接的客户端的Socket并开启线程接收数据;
6 socket.Send();//发送数据
7 socket.Close();//关闭连接

   
Start
方法用来开始侦听传入的连接请求。Start
将对传入连接进行排队,直至您调用
Stop
方法或它已经完成 MaxConnections 排队为止。可使用
AcceptSocket

AcceptTcpClient
从传入连接请求队列提取连接。这两种方法将阻止。如果要避免阻止,可首先使用
Pending
(注:TcpListener类才有)方法来确定队列中是否有可用的连接请求。

TcpClient创建客户端:

调用 Stop 方法来关闭
TcpListener。

 1 //建立TCP客户端TcpClient对象。
 2 TcpClient tcpclnt = new TcpClient();
 3 //连接服务器
 4 tcpclnt.Connect(IP地址字符串,端口号);
 5 //获得客户端网络传输 流
 6 Stream stm =tcpclnt.GetStream();
 7 //通过Stream的Write方法向服务器端发送的数据
 8 //通过Stream的Read方法读取服务器段发来的数据
 9 //在通讯结束后,需要释放资源,结束和服务器的连接
10 tcpclnt.Close();

下面的例子给出怎么利用TcpListener监听客户端的请求: using System;

TCP与UDP的区别

using
System.Collections.Generic;

  1. TCP是面向连接的服务、UDP是面向无连接服务
  2. TCP是具有差错控制的,而UDP没有缺乏可靠性
  3. TCP的传输是有序的,UDP是无序的
  4. UDP的实时性更好,有简单,快速、占用资源少的优点。
  5. UDP传输限定在64KB之内,Tcp一旦建立连接,就可以按统一的格式传输大量的数据。

using System.Text;

使用UdpClient类实现UDP协议编程

using
System.Net.Sockets;

       
 由于UDP协议并不需要进行确定的连接,程序中可以不需要考虑连接和一些异常的捕获工作。在有些对数据安全性要求不是很高的情况下采用UDP协议。

using System.Net;

       
在System.Net.Sockets命名空间下的UdpClient类,提供更直观的易于使用的属性和方法,从而降低UDP编程的难度。使用UdpClient时,连接的客户端需要先发送一个信息给服务器,服务器才能和客户端通讯。

namespace tcpclient

UdpClient类的构造函数有以下几种格式:

{

1 UdpClient();
2 UdpClient(int port);
3 UdpClient(IPEndPoint iep);
4 UdpClient(string remoteHost,int port);

    class Program

利用Socket编写UdpClient

    {

1 Socket udpSocket;//创建Socket
2 udpSocket.Bind(IPAddress,IPEndPoint);//把Socket绑定本地IP和端口号
3 //开启线程接收信息:先保存接到信息的端口号,使用ReceiveFrom发送信息
4 EndPoint point = new IPEndPoint(IPAddress.Any, 0);//用来保存发送方的ip和端口号
5 EndPoint point = (EndPoint)IPEndPoint;
6 //发送信息:使用EndPoint创建发送目标的IP和端口号;
7 //关闭线程和Socket

        private const int
portNum = 11000;

利用UDPClient编程

        static void Main(string[] args)

 1 //建立UDP客户端UdpClient对象。
 2 UdpClient uc=new UdpClient(端口号);
 3 //连接对方远程主机
 4 uc.Connect(对方IP地址,对方远程主机的端口号);
 5 //开启线程,通过uc的Receive方法获取远程主机发送来的数据
 6 IPEndPoint ip=new IPEndPoint(IPAddress.Any,0);
 7 byte[] b=uc.Receive(ref ip);
 8 //通过uc的Send方法向远程主机发送数据
 9 byte[] st=System.Text.Encoding.Default.GetBytes(“text”);
10 uc.Send(st);
11 //在通讯结束后,需要释放资源
12 uc.Close();

        {

 

            bool done = false;

            //TcpListener listener = new TcpListener(portNum);
//根据VS2005
MSDN 此方法已经过时,不再使用

            // IPEndPoint类将网络标识为IP地址和端口号

            TcpListener listener = new TcpListener(new IPEndPoint(IPAddress.Any, portNum));

           
listener.Start();

            while (!done)

            {

               
Console.Write(“Waiting for connection…”);

               
TcpClient client =
listener.AcceptTcpClient();

               
Console.WriteLine(“Connection accepted.”);

               
NetworkStream ns =
client.GetStream();

               
byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());

               
try

        
       {

                   
ns.Write(byteTime, 0, byteTime.Length);

                   
ns.Close();

                   
client.Close();

               
}

               
catch (Exception e)

               
{

                   
Console.WriteLine(e.ToString());

               
}

            }

           
listener.Stop();

         }

    }

}

 

3.UdpClient    UdpClient 类提供了一些简单的方法,用于在阻止同步模式下发送和接收无连接
UDP 数据报。因为 UDP
是无连接传输协议,所以不需要在发送和接收数据前建立远程主机连接。但您可以选择使用下面两种方法之一来建立默认远程主机:

·        
使用远程主机名和端口号作为参数创建 UdpClient
类的实例。

·        
创建 UdpClient
类的实例,然后调用
Connect
方法。

   可以使用在 UdpClient
中提供的任何一种发送方法将数据发送到远程设备。使用
Receive
方法可以从远程主机接收数据。    UdpClient
方法还允许发送和接收多路广播数据报。使用
JoinMulticastGroup
方法可以将 UdpClient 预订给多路广播组。使用
DropMulticastGroup
方法可以从多路广播组中取消对 UdpClient 的预订。

   下面的例子演示同一主机不同端口之间的UDP通信:

监听端: using System;

using
System.Net.Sockets;

using System.Text;

using System.Net;

using System.Threading;

namespace Udpclient2

{

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

               
UdpClient udpClient = new UdpClient(12000);

               
string returnData = “client_end”;

               
do

               
{

                   
Console.WriteLine(“服务器端接收数据:………………………..”);

                   
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

                   
// 此处通过引用传值,获得客户端的IP地址及端口号

                   
Byte[] receiveBytes =
udpClient.Receive(ref
RemoteIpEndPoint);

                   
//此处获得客户端的数据

                   
returnData = Encoding.UTF8.GetString(receiveBytes);

                   
//Encoding.ASCII.GetString(receiveBytes);
此处若用ASCII,不能正确处理中文

                   
Console.WriteLine(“This is the message server received: ” +
returnData.ToString());

www.9778.com, 

                   
Thread.Sleep(3000);

                

                   
Console.WriteLine(“向客户端发送数据:………………………..”);

                   
udpClient.Connect(Dns.GetHostName().ToString(), 11000);

     
              // Sends a message to the host
to which you have connected.

                   
string sendStr = “我来自服务器端:” + DateTime.Now.ToString();

                   
Byte[] sendBytes = Encoding.UTF8.GetBytes(sendStr);

                   
//Byte[] sendBytes =
Encoding.ASCII.GetBytes(sendStr); 此处若用ASCII,不能正确处理中文

                   
udpClient.Send(sendBytes, sendBytes.Length);

                   
Console.WriteLine(“This is the message server send: ” +
sendStr);

 

                 }
while (returnData != “client_end”);

               

            }

            catch (Exception e)

            {

               
Console.WriteLine(e.ToString());

            }

        }

    }

}

 

客户端: using System;

using
System.Net.Sockets;

using System.Text;

using System.Net;

namespace Udpclient

{

    class Program

    {

        static void Main(string[] args)

        {

           try

            {

               UdpClient udpClient = new UdpClient(11000);

              

               //向服务器发送数据

              
udpClient.Connect(Dns.GetHostName().ToString(), 12000);

               // Sends a message to the host to which you have
connected.

               string sendStr = “我来自客户端:” + DateTime.Now.ToString();

               Byte[] sendBytes = Encoding.UTF8.GetBytes(sendStr);

               //Byte[] sendBytes =
Encoding.ASCII.GetBytes(sendStr); 此处若用ASCII,不能正确处理中文

              
udpClient.Send(sendBytes, sendBytes.Length);

               Console.WriteLine(“This is the message client send: ” +
sendStr);

               

              

               //等待服务器的答复,收到后显示答复,并结束对话

               IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

               // 此处通过引用传值,获得客户端的IP地址及端口号

               Byte[] receiveBytes =
udpClient.Receive(ref
RemoteIpEndPoint);

               //此处获得服务器端的数据

               string returnData = Encoding.UTF8.GetString(receiveBytes);

               //Encoding.ASCII.GetString(receiveBytes);
此处若用ASCII,不能正确处理中文

               Console.WriteLine(“This is the message come from server: ” +
returnData.ToString());

              
udpClient.Close();

            }

            catch (Exception e)

            {

               
Console.WriteLine(e.ToString());

            }

        }

    }

}