分类

  • 软件天地

  • C#.Net 网络程序开发基础之Socket篇‖
    的网络服务,其名字空间Sy
    用程序。.Net类采用的分层
    据需要选择针对不同的级别
    接字到普通的请求/响应,
    的需要。
    ork为应用程序访问Internet提
    stem.Net和System.Net.Sockets
    结构允许应用程序在不同的控制
    编制程序,这些级别几乎囊括了
    更重要的是,这种分层是可以扩

    供了分层的、可扩展的以及受管辖
    包含丰富的类可以开发多种网络应
    级别上访问网络,开发人员可以根
    Internet的所有需要--从socket套
    展的,能够适应Internet不断扩展


      抛开ISO/OSI模型的7层
    个层次:请求/响应层、应
    层,支持Http、Tcp和Udp的
    构架,单从TCP/IP模型上的逻辑
    用协议层、传输层。WebReqeust
    类组成了应用协议层,而Socket
    层面上看,.Net类可以视为包含3
    和WebResponse 代表了请求/响应
    类处于传输层。

      传输层位于这个结构的
    的特殊需要时,就需要使用
    最底层,当其上面的应用协议层
    这一层进行Socket套接字编程。
    和请求/响应层不能满足应用程序


      而在.Net中,System.Net.Sockets
    Windows Sockets (Winsock) 接口的托
    问类都建立在该套接字Socket实现之上,
    关创建到 Internet 的 TCP 和 UDP 连接
    的基础数据流等,常见的许多Internet服
    Email、Echo等,这些服务尽管通讯协议P
    Socket。
    命名空间为需要严密控制网络访问的开发人员提供了
    管实现。System.Net 命名空间械乃衅渌绶?br>如TCPClient、TCPListener 和 UDPClient 类封装有
    的详细信息;NetworkStream类则提供用于网络访问
    务都可以见到Socket的踪影,如Telnet、Http、
    rotocol的定义不同,但是其基础的传输都是采用的


      其实,Socket可以象流Stream一样被
    户端)和远程服务器端之间,而后,数据
    行。
    视为一个数据通道,这个通道架设在应用程序端(客
    的读取(接收)和写入(发送)均针对这个通道来进


      可见,在应用程序端或
    将数据发送到连接的Socket
    者服务器端创建了Socket对象之
    ,或者使用Receive/ReceiveFrom
    后,就可以使用Send/SentTo方法
    方法接收来自连接Socket的数据;

      针对Socket编程,.NET 框架的 Sock
    码版本。其中为实现网络编程提供了大量
    封送到它们的本机 Win32 副本中并处理
    ,那么用Socket类编写网络程序会非常容
    下面的解说,你会发觉使用Socket类开发
    情况下遵循大致相同的步骤。
    et 类是 Winsock32 API 提供的套接字服务的托管代
    的方法,大多数情况下,Socket 类方法只是将数据
    任何必要的安全检查。如果你熟悉Winsock API函数
    易,当然,如果你不曾接触过,也不会太困难,跟随
    windows 网络应用程序原来有规可寻,它们在大多数


      在使用之前,你需要首

    先创建Socket对象的实例,这可

    以通过Socket类的构造方法来实现


      public Socket(Addres
    protocolType);
    sFamily addressFamily,Socket

    Type socketType,ProtocolType



      其中,addressFamily
    Socket 的类型,protocolT
    参数指定 Socket 使用的寻址方
    ype 参数指定 Socket 使用的协
    案,socketType 参数指定
    议。

      下面的示例语句创建一个 Socket,
    通讯。
    它可用于在基于 TCP/IP 的网络(如 Internet)上


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



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

      Socket s = new Socke
    ProtocolType.Udp);
    t(AddressFamily.InterNetwork

    , SocketType.Dgram,



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

      Socket.Connect方法:建立到远程设备的连接                        
      public void Connect(EndPoint rem
    oteEP)(有重载方法)
      Socket.Send 方法:从
    数据中的指示位置开始将数据发
    送到连接的 Socket。
      public int Send(byte
    [], int, SocketFlags);(有重
    载方法)
      Socket.SendTo 方法 将数据发送到特定终结点。                    
      public int SendTo(byte[], EndPoi
    nt);(有重载方法)
      Socket.Receive方法:
    将数据从连接的 Socket 接收到
    接收缓冲区的特定位置。
      public int Receive(byte[],int,So
    cketFlags);
      Socket.ReceiveFrom方
    法:接收数据缓冲区中特定位置
    的数据并存储终结点。
      public int ReceiveFr
    om(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( SocketShut
    down how );
      Socket.Close方法:强制 Socket 连接关闭                    
      public void Close();                                      


      可以看出,以上许多方
    络地址和一个服务端口号来
    接到的该设备上的特定服务
    EndPoint 类表示这个终结
    。.Net同时也为每个受支持
    IPEndPoint。IPEndPoint
    组合服务的主机IP地址和端
    法包含EndPoint类型的参数,在
    唯一标识设备。网络地址标识网
    。网络地址和服务端口的组合称
    点,它提供表示网络资源或服务
    的地址族定义了 EndPoint 的子
    类包含应用程序连接到主机上的
    口号,IPEndPoint 类形成到服
    Internet中,TCP/IP 使用一个网
    络上的特定设备;端口号标识要连
    为终结点,在 .NET 框架中正是由
    的抽象,用以标志网络地址等信息
    代;对于 IP 地址族,该类为
    服务所需的主机和端口信息,通过
    务的连接点。

      用到IPEndPoint类的时候就不可避免
    地址实例:
    地涉及到计算机IP地址,.Net中有两种类可以得到IP


      IPAddress类:IPAddress 类包含计
    址字符串转换为 IPAddress 实例。下面
    算机在 IP 网络上的地址。其Parse方法可将 IP 地
    的语句创建一个 IPAddress 实例:


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


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

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


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

      IPHosntEntry hostInf
    o=Dns.GetHostByName("host.co
    ntoso.com")


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

      SocketException异常:访问Socket时操作系统发生错误引发    

      ArgumentNullException异常:参数为空引用引发              

      ObjectDisposedException异常:Socket已经关闭引发  

      在掌握上面得知识后,
    口号组合,以便为连接创建
    下面的代码将该服务器主机( h
    远程终结点:
    ost.contoso.com的 IP 地址与端


      IPEndPoint ipe = new
    IPEndPoint(ipAddress,11000)
    ;


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

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


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


      另外,很多时候,Socket编程视情况
    端编制应用程序向服务端指定端口发送请
    在上面的阐述中已经提及;当然,并非所
    用情况不同,你可以在客户端构造出请求
    服务程序进行处理。以下事例语句中的字
    不同需要在客户端和服务器端分别予以实现,在客户
    求,同时编制服务端应用程序处理该请求,这个过程
    有的Socket编程都需要你严格编写这两端程序;视应
    字符衿飨嘤Χ丝诓痘裾飧銮肭螅挥善涔?br>符串就向远程主机提出页面请求:

      string Get = "GET /
    Closernrn";
    HTTP/1.1rnHost: " + server

    + "rnConnection:



      远程主机指定端口接受到这一请求后
    制服务器端应用程序。
    ,就可利用其公用服务程序进行处理而不需要另行编


      综合运用以上阐述的使
    地实现了Web页面下载功能
    部分表示法格式的 IP 地址
    可以获取远程主机页面并保
    Internet浏览器中打开该页
    用Visual C#进行Socket网络程
    。用户只需在窗体上输入远程主
    )和预保存的本地文件名,并利
    存在本地机指定文件中。如果保
    面。适当添加代码,你甚至可以
    序开发的知识,下面的程序段完整
    机名(Dns 主机名或以点分隔的四
    用专门提供Http服务的80端口,就
    存格式是.htm格式,你就可以在
    实现一个简单的浏览器程序。


      实现此功能的主要源代码如下:                                                  

      //"开始"按钮事件                                                          
      private void button1
    _Click(object sender, System
    .EventArgs e) {
      //取得预保存的文件名                                                        
      string fileName=textBox3.Text.Trim();    
      //远程主机                                                                  
      string hostName=textBox1.Text.Trim();    
      //端口                                                                      
      int port=Int32.Parse(textBox2.Te
    xt.Trim());
      //得到主机信息                                                              

      IPHostEntry ipInfo=D
    ns.GetHostByName(hostName);
      //取得IPAddress[]                                                
      IPAddress[] ipAddr=ipInfo.AddressList;  
      //得到ip                                                                  
      IPAddress ip=ipAddr[0];                                
      //组合出远程终结点                                                          
      IPEndPoint hostEP=new IPEndPoint
    (ip,port);
      //创建Socket 实例                                                    
      Socket socket=new Socket(Address
    etType.Stream,ProtocolType.Tcp);
    Family.InterNetwork,Sock

      try                                                                        
      {                                                                            
      //尝试连接                                                                  
      socket.Connect(hostEP);                                
      }                                                                            
      catch(Exception se)                                        
      {                                                                            
      MessageBox.Show("连接错误"+se.Message,"提示信息
      ,MessageBoxButtons.R
    etryCancel,MessageBoxIcon.In
    formation);
      }                                                                            
      //发送给远程主机的请求内容串                                                
      string sendStr="GET / HTTP/1.1r
    nHost: " + hostName +
      "rnConnection: Closernrn";              
      //创建bytes字节数组以转换发送串                                        
      byte[] bytesSendStr=new byte[1024];        
      //将发送内容字符串转换成字节byte数组                                    
      bytesSendStr=Encoding.ASCII.GetB
    ytes(sendStr);
      try                                                                        
      {                                                                            
      //向主机发送请求                                                            
      socket.Send(bytesSendStr,bytesSe
    ndStr.Length,0);
      }                                                                            
      catch(Exception ce)                                        
      {                                                                            
      MessageBox.Show("发送错误:"+ce.M
    essage,"提示信息
      ,MessageBoxButtons.RetryCancel,M
    essageBoxIcon.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.AS
    CII.GetString(recvBytes,0,by
    tes);
      }                                                                            
      //将所读取的字符串转换为字节数组                                            
      byte[] content=Encoding.ASCII.Ge
    tBytes(recvStr);
      try                                                                        
      {                                                                            
      //创建文件流对象实例                                                        
      FileStream fs=new FileStream(fil
    ate,FileAccess.ReadWrite);
    eName,FileMode.OpenOrCre

      //写入文件                                                                  
      fs.Write(content,0,content.Length);        
      }                                                                            
      catch(Exception fe)                                        
      {                                                                            
      MessageBox.Show("文件创建/写入错
    ",MessageBoxButtons.RetryCancel,Mess
    误:"+fe.Message,"提示信息
    ageBoxIcon.Information);
      }                                                                            
      //禁用Socket                                                          
      socket.Shutdown(SocketShutdown.Both);    
      //关闭Socket                                                          
      socket.Close();                                                
      }                                                                            
      }                                                                            

    上一页 下一页




    map