﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-灵魂-放水-随笔分类-网络编程</title><link>http://www.blogjava.net/zqli/category/15616.html</link><description>为学日益，为道日损。</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 10:28:55 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 10:28:55 GMT</pubDate><ttl>60</ttl><item><title>[转]NET System.Sockes类套接字,实现点对点文件传输。</title><link>http://www.blogjava.net/zqli/archive/2007/01/20/95081.html</link><dc:creator>放水老倌</dc:creator><author>放水老倌</author><pubDate>Sat, 20 Jan 2007 12:56:00 GMT</pubDate><guid>http://www.blogjava.net/zqli/archive/2007/01/20/95081.html</guid><wfw:comment>http://www.blogjava.net/zqli/comments/95081.html</wfw:comment><comments>http://www.blogjava.net/zqli/archive/2007/01/20/95081.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zqli/comments/commentRss/95081.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zqli/services/trackbacks/95081.html</trackback:ping><description><![CDATA[
		<p>System.Sockes命名空间了实现 Berkeley 套接字接口。通过这个类，我们可以实现网络计算机之间的消息传输和发送.而在我下面要讨论的这个议题里,我们将讨论的是用套节子实现文件的传输.这种方法有别于FTP协议实现的的文件传输方法,利用ftp的方法需要一个专门的服务器和客户端,无疑于我们要实现的点对点的文件传输太为复杂了一些。在这里，我们实现一个轻量级的方法来实现点对点的文件传输，这样就达到了intenet上任何两个计算机的文件共享。</p>
		<p>在两台计算机传输文件之前，必需得先有一台计算机建立套节子连接并绑定一个固定得端口，并在这个端口侦听另外一台计算机的连接请求。</p>
		<p>socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);<br />socket.Blocking = true ;<br />IPEndPoint computernode1 = new IPEndPoint(serverIpadress, 8080);</p>
		<p>socket.Bind(computernode1);</p>
		<p>socket.Listen(-1);</p>
		<p>当有其他的计算机发出连接请求的时候，被请求的计算机将对每一个连接请求分配一个线程，用于处理文件传输和其他服务。</p>
		<p>while ( true ) </p>
		<p>  {</p>
		<p>    clientsock = socket.Accept();</p>
		<p>    if ( clientsock.Connected ) </p>
		<p>    {</p>
		<p>       Thread tc = new Thread(new ThreadStart(listenclient));</p>
		<p>      tc.Start();</p>
		<p>    }</p>
		<p>  }</p>
		<p> </p>
		<p>下面的代码展示了listenclient方法是如何处理另外一台计算机发送过来的请求。首先并对发送过来的请求字符串作出判断，看看是何种请求，然后决定相应的处理方法。</p>
		<p>void listenclient()<br />{<br />  Socket sock = clientsock ;<br />  try<br />  {<br />    while ( sock != null ) <br />    {<br />      byte[] recs = new byte[32767];<br />      int rcount = sock.Receive(recs,recs.Length,0) ;<br />      string message = System.Text.Encoding.ASCII.GetString(recs) ;<br />     //对message作出处理，解析处请求字符和参数存储在cmdList 中<br />          execmd＝cmdList[0];<br />      sender = null ;<br />      sender = new Byte[32767];<br />  <br />      string parm1 = "";<br />//目录列举     <br />if ( execmd == "LISTING" ) <br />      {<br />        ListFiles(message);<br />        continue ;<br />      } <br />//文件传输<br />      if ( execmd == "GETOK" )<br />      {<br />        cmd = "BEGINSEND "  + filepath + " " + filesize ;<br />        sender = new Byte[1024];<br />        sender = Encoding.ASCII.GetBytes(cmd);<br />        sock.Send(sender, sender.Length , 0 );<br />               //转到文件下载处理<br />        DownloadingFile(sock);<br />        continue ;<br />      }   <br />    }<br />  }<br />  catch(Exception Se)<br />  {<br />    string s = Se.Message;<br />    Console.WriteLine(s);<br />  }<br />}<br /> <br />至此，基本的工作已经完成了，下面我们看看如何处理文件传输的。<br />while(rdby &lt; total &amp;&amp; nfs.CanWrite)<br />  {<br />//从要传输的文件读取指定长度的数据<br />len =fin.Read(buffed,0,buffed.Length) ;<br />    //将读取的数据发送到对应的计算机<br />    nfs.Write(buffed, 0,len);<br />    //增加已经发送的长度<br />    rdby=rdby+len ;          <br />  }<br />从上面的代码可以看出是完成文件转换成FileStream 流，然后通过NetworkStream绑定对应的套节子，最后调用他的write方法发送到对应的计算机。<br />我们再看看接受端是如何接受传输过来的流，并且转换成文件的：<br />NetworkStream nfs = new NetworkStream(sock) ;<br />try<br />{<br />        //一直循环直到指定的文件长度<br />        while(rby &lt; size)<br />  {<br />      byte[] buffer = new byte[1024] ;<br />      //读取发送过来的文件流<br />      int i = nfs.Read(buffer,0,buffer.Length) ;<br />      fout.Write(buffer,0,(int)i) ;<br />      rby=rby+i ;<br />    }  <br />  fout.Close() ;<br /> <br />从上面可以看出接受与发送恰好是互为相反的过程，非常简单。<br />至此，单方向的文件传输就完成了，只需要在每个对等的节点上同时实现上面的发送和接受的处理代码就可以做到互相传输文件了。</p>
		<p> </p>
		<p> </p>
		<p>=============================</p>
		<p> </p>
		<p>Microsoft.Net Framework为应用程序访问Internet提供了分层的、可扩展的以及受管辖的网络服务，其名字空间System.Net和System.Net.Sockets包含丰富的类可以开发多种网络应用程序。.Net类采用的分层结构允许应用程序在不同的控制级别上访问网络，开发人员可以根据需要选择针对不同的级别编制程序，这些级别几乎囊括了Internet的所有需要--从socket套接字到普通的请求/响应，更重要的是，这种分层是可以扩展的，能够适应Internet不断扩展的需要。 <br />   <br />  抛开ISO/OSI模型的7层构架，单从TCP/IP模型上的逻辑层面上看，.Net类可以视为包含3个层次：请求/响应层、应用协议层、传输层。WebReqeust和WebResponse 代表了请求/响应层，支持Http、Tcp和Udp的类组成了应用协议层，而Socket类处于传输层。  <br />   <br />  传输层位于这个结构的最底层，当其上面的应用协议层和请求/响应层不能满足应用程序的特殊需要时，就需要使用这一层进行Socket套接字编程。 <br />   <br />  而在.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。 <br />   <br />  其实，Socket可以象流Stream一样被视为一个数据通道，这个通道架设在应用程序端（客户端）和远程服务器端之间，而后，数据的读取（接收）和写入（发送）均针对这个通道来进行。 <br />   <br />  可见，在应用程序端或者服务器端创建了Socket对象之后，就可以使用Send/SentTo方法将数据发送到连接的Socket,或者使用Receive/ReceiveFrom方法接收来自连接Socket的数据； <br />   <br />  针对Socket编程，.NET 框架的 Socket 类是 Winsock32 API 提供的套接字服务的托管代码版本。其中为实现网络编程提供了大量的方法，大多数情况下，Socket 类方法只是将数据封送到它们的本机 Win32 副本中并处理任何必要的安全检查。如果你熟悉Winsock API函数，那么用Socket类编写网络程序会非常容易，当然，如果你不曾接触过，也不会太困难，跟随下面的解说，你会发觉使用Socket类开发windows 网络应用程序原来有规可寻，它们在大多数情况下遵循大致相同的步骤。 <br />   <br />  在使用之前，你需要首先创建Socket对象的实例，这可以通过Socket类的构造方法来实现： <br />   <br />  public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType); <br />   <br />   <br />  其中，addressFamily 参数指定 Socket 使用的寻址方案，socketType 参数指定 Socket 的类型，protocolType 参数指定 Socket 使用的协议。 <br />   <br />  下面的示例语句创建一个 Socket，它可用于在基于 TCP/IP 的网络（如 Internet）上通讯。 <br />   <br />  Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <br />   <br />   <br />  若要使用 UDP 而不是 TCP，需要更改协议类型，如下面的示例所示： <br />   <br />  Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); <br />   <br />   <br />  一旦创建 Socket，在客户端，你将可以通过Connect方法连接到指定的服务器，并通过Send/SendTo方法向远程服务器发送数据，而后可以通过Receive/ReceiveFrom从服务端接收数据；而在服务器端，你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联，并通过Listen方法侦听该接口上的请求，当侦听到用户端的连接时，调用Accept完成连接的操作，创建新的Socket以处理传入的连接请求。使用完 Socket 后，记住使用 Shutdown 方法禁用 Socket，并使用 Close 方法关闭 Socket。其间用到的方法/函数有： <br />   <br />  Socket.Connect方法:建立到远程设备的连接 <br />  public void Connect(EndPoint remoteEP)（有重载方法） <br />  Socket.Send 方法:从数据中的指示位置开始将数据发送到连接的 Socket。 <br />  public int Send(byte[], int, SocketFlags);(有重载方法) <br />  Socket.SendTo 方法 将数据发送到特定终结点。 <br />  public int SendTo(byte[], EndPoint);（有重载方法） <br />  Socket.Receive方法:将数据从连接的 Socket 接收到接收缓冲区的特定位置。 <br />  public int Receive(byte[],int,SocketFlags); <br />  Socket.ReceiveFrom方法：接收数据缓冲区中特定位置的数据并存储终结点。 <br />  public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint); <br />  Socket.Bind 方法：使 Socket 与一个本地终结点相关联： <br />  public void Bind( EndPoint localEP ); <br />  Socket.Listen方法：将 Socket 置于侦听状态。 <br />  public void Listen( int backlog ); <br />  Socket.Accept方法:创建新的 Socket 以处理传入的连接请求。 <br />  public Socket Accept(); <br />  Socket.Shutdown方法:禁用某 Socket 上的发送和接收 <br />  public void Shutdown( SocketShutdown how ); <br />  Socket.Close方法:强制 Socket 连接关闭 <br />  public void Close(); <br />   <br />   <br />  可以看出，以上许多方法包含EndPoint类型的参数，在Internet中，TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备；端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点，在 .NET 框架中正是由 EndPoint 类表示这个终结点，它提供表示网络资源或服务的抽象，用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代；对于 IP 地址族，该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息，通过组合服务的主机IP地址和端口号，IPEndPoint 类形成到服务的连接点。 <br />   <br />  用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址，.Net中有两种类可以得到IP地址实例： <br />   <br />  IPAddress类：IPAddress 类包含计算机在 IP 网络上的地址。其Parse方法可将 IP 地址字符串转换为 IPAddress 实例。下面的语句创建一个 IPAddress 实例： <br />   <br />  IPAddress myIP = IPAddress.Parse("192.168.1.2"); <br />   <br />   <br />  Dns 类：向使用 TCP/IP Internet 服务的应用程序提供域名服务。其Resolve 方法查询 DNS 服务器以将用户友好的域名（如"host.contoso.com"）映射到数字形式的 Internet 地址（如 192.168.1.1）。Resolve方法 返回一个 IPHostEnty 实例，该实例包含所请求名称的地址和别名的列表。大多数情况下，可以使用 AddressList 数组中返回的第一个地址。下面的代码获取一个 IPAddress 实例，该实例包含服务器 host.contoso.com 的 IP 地址。 <br />   <br />  IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com"); <br />  IPAddress ipAddress = ipHostInfo.AddressList[0]; <br />   <br />   <br />  你也可以使用GetHostName方法得到IPHostEntry实例： <br />   <br />  IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com") <br />   <br />   <br />  在使用以上方法时，你将可能需要处理以下几种异常： <br />   <br />  SocketException异常：访问Socket时操作系统发生错误引发 <br />   <br />  ArgumentNullException异常：参数为空引用引发 <br />   <br />  ObjectDisposedException异常：Socket已经关闭引发 <br />   <br />  在掌握上面得知识后，下面的代码将该服务器主机（ host.contoso.com的 IP 地址与端口号组合，以便为连接创建远程终结点： <br />   <br />  IPEndPoint ipe = new IPEndPoint(ipAddress,11000); <br />   <br />   <br />  确定了远程设备的地址并选择了用于连接的端口后，应用程序可以尝试建立与远程设备的连接。下面的示例使用现有的 IPEndPoint 实例与远程设备连接，并捕获可能引发的异常： <br />   <br />  try { <br />   s.Connect(ipe);//尝试连接 <br />  } <br />  //处理参数为空引用异常 <br />   catch(ArgumentNullException ae) { <br />   Console.WriteLine("ArgumentNullException : {0}", ae.ToString()); <br />  } <br />  //处理操作系统异常 <br />   catch(SocketException se) { <br />   Console.WriteLine("SocketException : {0}", se.ToString()); <br />  } <br />   catch(Exception e) { <br />   Console.WriteLine("Unexpected exception : {0}", e.ToString()); <br />  } <br />   <br />   <br />  需要知道的是：Socket 类支持两种基本模式：同步和异步。其区别在于：在同步模式中，对执行网络操作的函数（如 Send 和 Receive）的调用一直等到操作完成后才将控制返回给调用程序。在异步模式中，这些调用立即返回。 <br />   <br />  另外，很多时候，Socket编程视情况不同需要在客户端和服务器端分别予以实现，在客户端编制应用程序向服务端指定端口发送请求，同时编制服务端应用程序处理该请求，这个过程在上面的阐述中已经提及；当然，并非所有的Socket编程都需要你严格编写这两端程序；视应用情况不同，你可以在客户端构造出请求字符串，服务器相应端口捕获这个请求，交由其公用服务程序进行处理。以下事例语句中的字符串就向远程主机提出页面请求： <br />   <br />  string Get = "GET / HTTP/1.1\r\nHost: " + server + "\r\nConnection: Close\r\n\r\n"; <br />   <br />   <br />  远程主机指定端口接受到这一请求后，就可利用其公用服务程序进行处理而不需要另行编制服务器端应用程序。 <br />   <br />  综合运用以上阐述的使用Visual C#进行Socket网络程序开发的知识，下面的程序段完整地实现了Web页面下载功能。用户只需在窗体上输入远程主机名（Dns 主机名或以点分隔的四部分表示法格式的 IP 地址）和预保存的本地文件名，并利用专门提供Http服务的80端口，就可以获取远程主机页面并保存在本地机指定文件中。如果保存格式是.htm格式，你就可以在Internet浏览器中打开该页面。适当添加代码，你甚至可以实现一个简单的浏览器程序。 <br />   <br />   <br />  实现此功能的主要源代码如下： <br />   <br />  //"开始"按钮事件 <br />  private void button1_Click(object sender, System.EventArgs e) { <br />   //取得预保存的文件名 <br />   string fileName=textBox3.Text.Trim(); <br />   //远程主机 <br />   string hostName=textBox1.Text.Trim(); <br />   //端口 <br />   int port=Int32.Parse(textBox2.Text.Trim()); <br />   //得到主机信息 <br />   IPHostEntry ipInfo=Dns.GetHostByName(hostName); <br />   //取得IPAddress[] <br />   IPAddress[] ipAddr=ipInfo.AddressList; <br />   //得到ip <br />   IPAddress ip=ipAddr[0]; <br />   //组合出远程终结点 <br />   IPEndPoint hostEP=new IPEndPoint(ip,port); <br />   //创建Socket 实例 <br />   Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); <br />   try <br />   { <br />   //尝试连接 <br />   socket.Connect(hostEP); <br />   } <br />   catch(Exception se) <br />   { <br />   MessageBox.Show("连接错误"+se.Message,"提示信息 <br />   ,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); <br />  } <br />  //发送给远程主机的请求内容串 <br />  string sendStr="GET / HTTP/1.1\r\nHost: " + hostName + <br />  "\r\nConnection: Close\r\n\r\n"; <br />   //创建bytes字节数组以转换发送串 <br />   byte[] bytesSendStr=new byte[1024]; <br />   //将发送内容字符串转换成字节byte数组 <br />   bytesSendStr=Encoding.ASCII.GetBytes(sendStr); <br />  try <br />  { <br />  //向主机发送请求 <br />  socket.Send(bytesSendStr,bytesSendStr.Length,0); <br />  } <br />  catch(Exception ce) <br />   { <br />   MessageBox.Show("发送错误:"+ce.Message,"提示信息 <br />   ,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); <br />   } <br />   //声明接收返回内容的字符串 <br />   string recvStr=""; <br />   //声明字节数组，一次接收数据的长度为1024字节 <br />   byte[] recvBytes=new byte[1024]; <br />   //返回实际接收内容的字节数 <br />   int bytes=0; <br />  //循环读取，直到接收完所有数据 <br />  while(true) <br />  { <br />  bytes=socket.Receive(recvBytes,recvBytes.Length,0); <br />  //读取完成后退出循环 <br />  if(bytes〈=0) <br />  break; <br />  //将读取的字节数转换为字符串 <br />  recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes); <br />  } <br />  //将所读取的字符串转换为字节数组 <br />  byte[] content=Encoding.ASCII.GetBytes(recvStr); <br />   try <br />   { <br />   //创建文件流对象实例 <br />   FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite); <br />  //写入文件 <br />  fs.Write(content,0,content.Length); <br />  } <br />  catch(Exception fe) <br />   { <br />   MessageBox.Show("文件创建/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); <br />   } <br />   //禁用Socket <br />   socket.Shutdown(SocketShutdown.Both); <br />   //关闭Socket <br />   socket.Close(); <br />   } <br />   } </p>
		<p> </p>
		<p>
				<br />=============================================</p>
		<p> </p>
		<p>Socket基本编程</p>
		<p>服务端：</p>
		<p> </p>
		<p>using System.Net;</p>
		<p> </p>
		<p>using System.Net.Sockets;</p>
		<p> </p>
		<p>using System.Text;</p>
		<p> </p>
		<p>using System.Threading;</p>
		<p> </p>
		<p> </p>
		<p>
				<br />         </p>
		<p> </p>
		<p>         Thread mythread ;</p>
		<p> </p>
		<p>         Socket socket;</p>
		<p> </p>
		<p> </p>
		<p>
				<br />// 清理所有正在使用的资源。</p>
		<p> </p>
		<p>         protected override void Dispose( bool disposing )</p>
		<p> </p>
		<p>         {</p>
		<p> </p>
		<p>              try </p>
		<p> </p>
		<p>　            { 　　             </p>
		<p> </p>
		<p>　　          socket.Close();//释放资源 </p>
		<p> </p>
		<p>　　          mythread.Abort ( ) ;//中止线程 </p>
		<p> </p>
		<p>　            } </p>
		<p> </p>
		<p>　            catch{ } </p>
		<p> </p>
		<p>
				<br /> </p>
		<p>
				<br />              if( disposing )</p>
		<p> </p>
		<p>              {</p>
		<p> </p>
		<p>                   if (components != null) </p>
		<p> </p>
		<p>                   {</p>
		<p> </p>
		<p>                       components.Dispose();</p>
		<p> </p>
		<p>                   }</p>
		<p> </p>
		<p>              }</p>
		<p> </p>
		<p>              base.Dispose( disposing );</p>
		<p> </p>
		<p>         }        </p>
		<p> </p>
		<p>         public static IPAddress GetServerIP()</p>
		<p> </p>
		<p>         {</p>
		<p> </p>
		<p>              IPHostEntry ieh=Dns.GetHostByName(Dns.GetHostName());</p>
		<p> </p>
		<p>              return ieh.AddressList[0];</p>
		<p> </p>
		<p>         }</p>
		<p> </p>
		<p>         private void BeginListen()</p>
		<p> </p>
		<p>         {</p>
		<p> </p>
		<p>              IPAddress ServerIp=GetServerIP();</p>
		<p> </p>
		<p>              IPEndPoint iep=new IPEndPoint(ServerIp,8000);</p>
		<p> </p>
		<p>              socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);</p>
		<p> </p>
		<p>              </p>
		<p> </p>
		<p>              byte[] byteMessage=new byte[100];  </p>
		<p> </p>
		<p>              this.label1.Text=iep.ToString();</p>
		<p> </p>
		<p>              socket.Bind(iep);  </p>
		<p> </p>
		<p>//            do</p>
		<p> </p>
		<p>              while(true)</p>
		<p> </p>
		<p>              {</p>
		<p> </p>
		<p>                   try</p>
		<p> </p>
		<p>                   {</p>
		<p> </p>
		<p>                       socket.Listen(5);</p>
		<p> </p>
		<p>                       Socket newSocket=socket.Accept();</p>
		<p> </p>
		<p>                       newSocket.Receive(byteMessage);</p>
		<p> </p>
		<p>
				<br /> </p>
		<p>
				<br />                       string sTime = DateTime.Now.ToShortTimeString ( ) ;</p>
		<p> </p>
		<p>                       string msg=sTime+":"+"Message from:";</p>
		<p> </p>
		<p>                       msg+=newSocket.RemoteEndPoint.ToString()+Encoding.Default.GetString(byteMessage);</p>
		<p> </p>
		<p>                       this.listBox1.Items.Add(msg);</p>
		<p> </p>
		<p>                       </p>
		<p> </p>
		<p>                   }</p>
		<p> </p>
		<p>                   catch(SocketException ex)</p>
		<p> </p>
		<p>                   {</p>
		<p> </p>
		<p>                       this.label1.Text+=ex.ToString();</p>
		<p> </p>
		<p>                   }</p>
		<p> </p>
		<p>              }</p>
		<p> </p>
		<p>//            while(byteMessage!=null);</p>
		<p> </p>
		<p>         }</p>
		<p> </p>
		<p>         //开始监听</p>
		<p> </p>
		<p>         private void button1_Click(object sender, System.EventArgs e)</p>
		<p> </p>
		<p>         {</p>
		<p> </p>
		<p>              try</p>
		<p> </p>
		<p>              {</p>
		<p> </p>
		<p>                   mythread = new Thread(new ThreadStart(BeginListen));</p>
		<p> </p>
		<p>                   mythread.Start();</p>
		<p> </p>
		<p>
				<br /> </p>
		<p>
				<br />              }</p>
		<p> </p>
		<p>              catch(System.Exception er)</p>
		<p> </p>
		<p>              {</p>
		<p> </p>
		<p>                   MessageBox.Show(er.Message,"完成",MessageBoxButtons.OK,MessageBoxIcon.Stop);</p>
		<p> </p>
		<p>              }            </p>
		<p> </p>
		<p>         }</p>
		<p> </p>
		<p>
				<br /> </p>
		<p> </p>
		<p> </p>
		<p>
				<br />客户端：</p>
		<p> </p>
		<p>
				<br /> </p>
		<p>
				<br />using System.Net;</p>
		<p> </p>
		<p>using System.Net.Sockets;</p>
		<p> </p>
		<p>using System.Text;</p>
		<p> </p>
		<p>
				<br /> </p>
		<p>
				<br />         private void button1_Click(object sender, System.EventArgs e)</p>
		<p> </p>
		<p>         {</p>
		<p> </p>
		<p>              BeginSend();       </p>
		<p> </p>
		<p>         }</p>
		<p> </p>
		<p>         private void BeginSend()</p>
		<p> </p>
		<p>         {             </p>
		<p> </p>
		<p>              string ip=this.txtip.Text;</p>
		<p> </p>
		<p>              string port=this.txtport.Text;</p>
		<p> </p>
		<p>
				<br /> </p>
		<p>
				<br />              IPAddress serverIp=IPAddress.Parse(ip);            </p>
		<p> </p>
		<p>              int serverPort=Convert.ToInt32(port);</p>
		<p> </p>
		<p>              IPEndPoint iep=new IPEndPoint(serverIp,serverPort);  </p>
		<p> </p>
		<p>              byte[] byteMessage;  </p>
		<p> </p>
		<p>//            do</p>
		<p> </p>
		<p>//            {</p>
		<p> </p>
		<p>                   Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);</p>
		<p> </p>
		<p>                   socket.Connect(iep);</p>
		<p> </p>
		<p>              </p>
		<p> </p>
		<p>                   byteMessage=Encoding.ASCII.GetBytes(textBox1.Text);</p>
		<p> </p>
		<p>                   socket.Send(byteMessage);</p>
		<p> </p>
		<p>                   socket.Shutdown(SocketShutdown.Both);</p>
		<p> </p>
		<p>                   socket.Close();</p>
		<p> </p>
		<p>//            }</p>
		<p> </p>
		<p>//            while(byteMessage!=null);</p>
		<p> </p>
		<p>         } </p>
		<br />
		<br />
		<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1487041</p>
<img src ="http://www.blogjava.net/zqli/aggbug/95081.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zqli/" target="_blank">放水老倌</a> 2007-01-20 20:56 <a href="http://www.blogjava.net/zqli/archive/2007/01/20/95081.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]RADIUS 协议</title><link>http://www.blogjava.net/zqli/archive/2006/10/29/77925.html</link><dc:creator>放水老倌</dc:creator><author>放水老倌</author><pubDate>Sun, 29 Oct 2006 12:29:00 GMT</pubDate><guid>http://www.blogjava.net/zqli/archive/2006/10/29/77925.html</guid><wfw:comment>http://www.blogjava.net/zqli/comments/77925.html</wfw:comment><comments>http://www.blogjava.net/zqli/archive/2006/10/29/77925.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zqli/comments/commentRss/77925.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zqli/services/trackbacks/77925.html</trackback:ping><description><![CDATA[
		<h2>RADIUS 协议</h2>
		<p>远程身份验证拨入用户服务 (RADIUS) 是 RFC 2865“远程身份验证拨入用户服务 (RADIUS)”和 RFC 2866“RADIUS 记帐”中描述的业界标准协议。RADIUS 用于提供身份验证、授权和记帐服务。RADIUS 客户端（通常为拨号服务器、VPN 服务器或无线访问点）以 RADIUS 消息的形式向 RADIUS 服务器发送用户凭据和连接参数信息。RADIUS 服务器对 RADIUS 客户端请求进行身份验证和授权，并发回 RADIUS 消息响应。RADIUS 客户端也向 RADIUS 服务器发送 RADIUS 记帐消息。另外，RADIUS 标准支持使用 RADIUS 代理。RADIUS 代理是在启用 RADIUS 的计算机之间转发 RADIUS 消息的计算机。</p>
		<p>RADIUS 消息作为用户数据报协议 (UDP) 消息被发送。UDP 端口 1812 用于发送 RADIUS 身份验证消息，UDP 端口 1813 用于发送 RADIUS 记帐消息。有些网络访问服务器可能会使用 UDP 端口 1645 发送 RADIUS 身份验证消息，而使用 UDP 端口 1646 发送 RADIUS 记帐消息。默认情况下，IAS 支持接收发送到这两个 UDP 端口的 RADIUS 消息。有关更改 IAS 所使用的 UDP 端口的信息，请参阅<a href="http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/ServerHelp/cd8b2cb5-9bbd-4e93-8d98-faf5f6f9957c.mspx">配置 IAS 端口信息</a>.RADIUS 数据包的 UDP 负载中只包含一则 RADIUS 消息。</p>
		<p>RFCs 2865 和 2866 定义了以下 RADIUS 消息类型：</p>
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>访问 - 请求 </p>
										<p>由 RADIUS 客户端发送请求对连接尝试进行身份验证和授权。 </p>
								</td>
						</tr>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>访问 - 接收 </p>
										<p>由 RADIUS 服务器发送，以响应“访问 - 请求”消息。此消息通知 RADIUS 客户端已对连接尝试进行身份验证和授权。 </p>
								</td>
						</tr>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>访问 - 拒绝 </p>
										<p>由 RADIUS 服务器发送，以响应“访问 - 请求”消息。此消息通知 RADIUS 客户端连接尝试被拒绝。如果凭据未被验证或连接尝试未被授权，RADIUS 服务器将发送此消息。 </p>
								</td>
						</tr>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>访问 - 质询 </p>
										<p>由 RADIUS 服务器发送，以响应“访问 - 请求”消息。此消息是对需要响应的 RADIUS 客户端的质询。 </p>
								</td>
						</tr>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>记帐 - 请求 </p>
										<p>由 RADIUS 客户端发送，为接受的连接指定记帐信息。 </p>
								</td>
						</tr>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>记帐 - 响应 </p>
										<p>由 RADIUS 服务器发送，以响应“记帐 - 请求”消息。此消息确认对记帐请求消息的成功接受和处理。 </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>RADIUS 消息由一个 RADIUS 头和零或多个 RADIUS 属性组成。每个 RADIUS 属性指定一则有关连接尝试的信息。例如，存在用户名称、用户密码、用户请求的服务类型和访问服务器的 IP 地址的 RADIUS 属性。RADIUS 属性用于传送 RADIUS 客户端、RADIUS 代理和 RADIUS 服务器之间的信息。例如，“访问 - 请求”消息中的属性列表包含有关用户凭据和连接尝试的参数的信息。相反，“访问 - 接受”消息包含有关可创建的连接类型、连接限制和特定供应商属性 (VSA) 的信息。</p>
		<p>
				<b>注意</b>
		</p>
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td class="listBullet" valign="top">•</td>
								<td class="listItem">
										<p>您可以在 Windows Server 2003 Standard Edition 中配置 IAS，最多配置 50 个 RADIUS 客户端和 2 个远程 RADIUS 服务器组。您可以采用完全合格的域名或 IP 地址定义 RADIUS 客户端，但不能通过指定 IP 地址范围定义 RADIUS 客户端组。如果将 RADIUS 客户端的完全合格的域名解析为多个 IP 地址，则 IAS 服务器采用 DNS 查询中返回的第一个 IP 地址。使用 Windows Server 2003 Enterprise Edition 和 Windows Server 2003 Datacenter Edition 中的 IAS，可以配置无限多个 RADIUS 客户端和远程 RADIUS 服务器组。另外，您可以通过指定 IP 地址范围来配置 RADIUS 客户端。 </p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/zqli/aggbug/77925.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zqli/" target="_blank">放水老倌</a> 2006-10-29 20:29 <a href="http://www.blogjava.net/zqli/archive/2006/10/29/77925.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]C#网络编程</title><link>http://www.blogjava.net/zqli/archive/2006/09/24/71537.html</link><dc:creator>放水老倌</dc:creator><author>放水老倌</author><pubDate>Sun, 24 Sep 2006 03:17:00 GMT</pubDate><guid>http://www.blogjava.net/zqli/archive/2006/09/24/71537.html</guid><wfw:comment>http://www.blogjava.net/zqli/comments/71537.html</wfw:comment><comments>http://www.blogjava.net/zqli/archive/2006/09/24/71537.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zqli/comments/commentRss/71537.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zqli/services/trackbacks/71537.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>      C＃网络编程我们知道C＃和C＋＋的差异之一，就是他本身没有类库，所使用的类库是.Net框架中的类库--.Net FrameWork SDK。在.Net FrameWork SDK中为网络编程提供了二个名称空间："System.Net"和"System.Net.Sockets"。C＃就是通过这二个名称空间中封装的类和方法实现网络通讯的。 </p>
				<p>　　首先我们解释一下在网络编程时候，经常遇到的几个概念：同步（synchronous）、异步（asynchronous）、阻塞（Block）和非阻塞（Unblock）： </p>
				<p>　　所谓同步方式，就是发送方发送数据包以后，不等接受方响应，就接着发送下一个数据包。异步方式就是当发送方发送一个数据包以后，一直等到接受方响应后，才接着发送下一个数据包。而阻塞套接字是指执行此套接字的网络调用时，直到调用成功才返回，否则此套节字就一直阻塞在网络调用上，比如调用StreamReader 类的Readlin ( )方法读取网络缓冲区中的数据，如果调用的时候没有数据到达，那么此Readlin ( )方法将一直挂在调用上，直到读到一些数据，此函数调用才返回；而非阻塞套接字是指在执行此套接字的网络调用时，不管是否执行成功，都立即返回。同样调用StreamReader 类的Readlin ( )方法读取网络缓冲区中数据，不管是否读到数据都立即返回，而不会一直挂在此函数调用上。在Windows网络通信软件开发中，最为常用的方法就是异步非阻塞套接字。平常所说的C/S（客户端/服务器）结构的软件采用的方式就是异步非阻塞模式的。 </p>
				<p>　　其实在用C＃进行网络编程中，我们并不需要了解什么同步、异步、阻塞和非阻塞的原理和工作机制，因为在.Net FrameWrok SDK中已经已经把这些机制给封装好了。下面我们就用C＃开一个具体的网络程序来说明一下问题。 </p>
				<p>一．本文中介绍的程序设计及运行环境 </p>
				<p>　　　 （1）.微软视窗2000 服务器版 </p>
				<p>　　　 （2）..Net Framework SDK Beta 2以上版本 </p>
				<p>二．服务器端程序设计的关键步骤以及解决办法： </p>
				<p>　　 在下面接受的程序中，我们采用的是异步阻塞的方式。 </p>
				<p>　　 （1）.首先要要在给定的端口上面创建一个"tcpListener"对象侦听网络上面的请求。当接收到连结请求后通过调用"tcpListener"对象的"AcceptSocket"方法产生一个用于处理接入连接请求的Socket的实例。下面是具体实现代码： </p>
				<p>//创建一个tcpListener对象，此对象主要是对给定端口进行侦听 <br />tcpListener = new TcpListener ( 1234 ) ; <br />//开始侦听 <br />tcpListener.Start ( ) ; <br />//返回可以用以处理连接的Socket实例 <br />socketForClient = tcpListener.AcceptSocket ( ) ; <br />　　 （2）.接受和发送客户端数据： </p>
				<p>　　 此时Socket实例已经产生，如果网络上有请求，在请求通过以后，Socket实例构造一个"NetworkStream"对象，"NetworkStream"对象为网络访问提供了基础数据流。我们通过名称空间"System.IO"中封装的二个类"StreamReader"和"StreamWriter"来实现对"NetworkStream"对象的访问。其中"StreamReader"类中的ReadLine ( )方法就是从"NetworkStream"对象中读取一行字符；"StreamWriter"类中的WriteLine ( )方法就是对"NetworkStream"对象中写入一行字符串。从而实现在网络上面传输字符串，下面是具体的实现代码： </p>
				<p>try <br />{ <br />//如果返回值是"true"，则产生的套节字已经接受来自远方的连接请求 <br />if ( socketForClient.Connected ) <br />{ <br />ListBox1.Items.Add ( "已经和客户端成功连接！" ) ; <br />while ( true ) <br />{ <br />//创建networkStream对象通过网络套节字来接受和发送数据 <br />networkStream = new NetworkStream ( socketForClient ) ; <br />//从当前数据流中读取一行字符，返回值是字符串 <br />streamReader = new StreamReader ( networkStream ) ; <br />string msg = streamReader.ReadLine ( ) ; <br />ListBox1.Items.Add ( "收到客户端信息：" + msg ) ; <br />streamWriter = new StreamWriter ( networkStream ) ; <br />if ( textBox1.Text != "" ) <br />{ <br />ListBox1.Items.Add ( "往客户端反馈信息：" + textBox1.Text ) ; <br />//往当前的数据流中写入一行字符串 <br />streamWriter.WriteLine ( textBox1.Text ) ; <br />//刷新当前数据流中的数据 <br />streamWriter.Flush ( ) ; <br />} <br />} <br />} <br />} <br />catch ( Exception ey ) <br />{ <br />MessageBox.Show ( ey.ToString ( ) ) ; <br />} </p>
				<p>　　 （3）.最后别忘了要关闭所以流，停止侦听网络，关闭套节字，具体如下： </p>
				<p>//关闭线程和流 <br />networkStream.Close ( ) ; <br />streamReader.Close ( ) ; <br />streamWriter.Close ( ) ; <br />_thread1.Abort ( ) ; <br />tcpListener.Stop ( ) ; <br />socketForClient.Shutdown ( SocketShutdown.Both ) ; <br />socketForClient.Close ( ) ; <br />三．C＃网络编程服务器端程序的部分源代码（server.cs） ： </p>
				<p>　　 由于在此次程序中我们采用的结构是异步阻塞方式，所以在实际的程序中，为了不影响服务器端程序的运行速度，我们在程序中设计了一个线程，使得对网络请求侦听，接受和发送数据都在线程中处理，请在下面的代码中注意这一点，下面是server.cs的完整代码： </p>
				<p>using System ; <br />using System.Drawing ; <br />using System.Collections ; <br />using System.ComponentModel ; <br />using System.Windows.Forms ; <br />using System.Data ;</p>
				<p>using System.Net.Sockets ; <br />using System.IO ; <br />using System.Threading ; <br />using System.Net ; <br />//导入程序中使用到的名字空间 <br />public class Form1 : Form <br />{ <br />private ListBox ListBox1 ; <br />private Button button2 ; <br />private Label label1 ; <br />private TextBox textBox1 ; <br />private Button button1 ; <br />private Socket socketForClient ; <br />private NetworkStream networkStream ; <br />private TcpListener tcpListener ; <br />private StreamWriter streamWriter ; <br />private StreamReader streamReader ; <br />private Thread _thread1 ; <br />private System.ComponentModel.Container components = null ; <br />public Form1 ( ) <br />{ <br />InitializeComponent ( ) ; <br />} <br />//清除程序中使用的各种资源 <br />protected override void Dispose ( bool disposing ) <br />{ <br />if ( disposing ) <br />{ <br />if ( components != null ) <br />{ <br />components.Dispose ( ) ; <br />} <br />} <br />base.Dispose ( disposing ) ; <br />} <br />private void InitializeComponent ( ) <br />{ <br />label1 = new Label ( ) ; <br />button2 = new Button ( ) ; <br />button1 = new Button ( ) ; <br />ListBox1 = new ListBox ( ) ; <br />textBox1 = new TextBox ( ) ; <br />SuspendLayout ( ) ; <br />label1.Location = new Point ( 8 , 168 ) ; <br />label1.Name = "label1" ; <br />label1.Size = new Size ( 120 , 23 ) ; <br />label1.TabIndex = 3 ; <br />label1.Text = "往客户端反馈信息：" ; <br />//同样的方式设置其他控件,这里略去 </p>
				<p>this.Controls.Add ( button1 ) ; <br />this.Controls.Add ( textBox1 ) ; <br />this.Controls.Add ( label1 ) ; <br />this.Controls.Add ( button2 ) ; <br />this.Controls.Add ( ListBox1 ) ; <br />this.MaximizeBox = false ; <br />this.MinimizeBox = false ; <br />this.Name = "Form1" ; <br />this.Text = "C＃的网络编程服务器端！" ; <br />this.Closed += new System.EventHandler ( this.Form1_Closed ) ; <br />this.ResumeLayout ( false ) ; </p>
				<p>} <br />private void Listen ( ) <br />{ <br />//创建一个tcpListener对象，此对象主要是对给定端口进行侦听 <br />tcpListener = new TcpListener ( 1234 ) ; <br />//开始侦听 <br />tcpListener.Start ( ) ; <br />//返回可以用以处理连接的Socket实例 <br />socketForClient = tcpListener.AcceptSocket ( ) ; <br />try <br />{ <br />//如果返回值是"true"，则产生的套节字已经接受来自远方的连接请求 <br />if ( socketForClient.Connected ) <br />{ <br />ListBox1.Items.Add ( "已经和客户端成功连接！" ) ; <br />while ( true ) <br />{ <br />//创建networkStream对象通过网络套节字来接受和发送数据 <br />networkStream = new NetworkStream ( socketForClient ) ; <br />//从当前数据流中读取一行字符，返回值是字符串 <br />streamReader = new StreamReader ( networkStream ) ; <br />string msg = streamReader.ReadLine ( ) ; <br />ListBox1.Items.Add ( "收到客户端信息：" + msg ) ; <br />streamWriter = new StreamWriter ( networkStream ) ; <br />if ( textBox1.Text != "" ) <br />{ <br />ListBox1.Items.Add ( "往客户端反馈信息：" + textBox1.Text ) ; <br />//往当前的数据流中写入一行字符串 <br />streamWriter.WriteLine ( textBox1.Text ) ; <br />//刷新当前数据流中的数据 <br />streamWriter.Flush ( ) ; <br />} <br />} <br />} <br />} <br />catch ( Exception ey ) <br />{ <br />MessageBox.Show ( ey.ToString ( ) ) ; <br />} <br />} <br />static void Main ( ) <br />{ <br />Application.Run ( new Form1 ( ) ) ;</p>
				<p>} </p>
				<p>private void button1_Click ( object sender , System.EventArgs e ) <br />{ <br />ListBox1.Items .Add ( "服务已经启动！" ) ; <br />_thread1 = new Thread ( new ThreadStart ( Listen ) ) ; <br />_thread1.Start ( ) ; </p>
				<p>} </p>
				<p>private void button2_Click ( object sender , System.EventArgs e ) <br />{ <br />//关闭线程和流 <br />networkStream.Close ( ) ; <br />streamReader.Close ( ) ; <br />streamWriter.Close ( ) ; <br />_thread1.Abort ( ) ; <br />tcpListener.Stop ( ) ; <br />socketForClient.Shutdown ( SocketShutdown.Both ) ; <br />socketForClient.Close ( ) ; <br />} <br />private void Form1_Closed ( object sender , System.EventArgs e ) <br />{ <br />//关闭线程和流 <br />networkStream.Close ( ) ; <br />streamReader.Close ( ) ; <br />streamWriter.Close ( ) ; <br />_thread1.Abort ( ) ; <br />tcpListener.Stop ( ) ; <br />socketForClient.Shutdown ( SocketShutdown.Both ) ; <br />socketForClient.Close ( ) ; <br />} <br />} </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=622873</p>
		</div>
<img src ="http://www.blogjava.net/zqli/aggbug/71537.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zqli/" target="_blank">放水老倌</a> 2006-09-24 11:17 <a href="http://www.blogjava.net/zqli/archive/2006/09/24/71537.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Visual C#.Net 网络程序开发Socket篇 </title><link>http://www.blogjava.net/zqli/archive/2006/09/24/71536.html</link><dc:creator>放水老倌</dc:creator><author>放水老倌</author><pubDate>Sun, 24 Sep 2006 03:12:00 GMT</pubDate><guid>http://www.blogjava.net/zqli/archive/2006/09/24/71536.html</guid><wfw:comment>http://www.blogjava.net/zqli/comments/71536.html</wfw:comment><comments>http://www.blogjava.net/zqli/archive/2006/09/24/71536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zqli/comments/commentRss/71536.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zqli/services/trackbacks/71536.html</trackback:ping><description><![CDATA[Microsoft.Net Framework为应用程序访问Internet提供分层的、可扩展的以及受管辖的网络服务，其名字空间System.Net和System.Net.Sockets包含丰富的类可以开发多种网络应用程序。
<p>　　.Net类采用的分层结构允许应用程序在不同的控制级别上访问网络，开发人员可以根据需要选择针对不同的级别编制程序，这些级别几乎囊括了Internet的所有需要，从socket套接字到普通的请求/响应，更重要的是，这种分层是可以扩展的，能够适应Internet不断扩展的需要。 <br />　　抛开ISO/OSI模型的7层构架，单从TCP/IP模型上的逻辑层面上看，.Net类可以视为包含3个层次：请求/响应层、应用协议层、传输层。WebReqeust和WebResponse 代表了请求/响应层，支持Http、Tcp和Udp的类组成了应用协议层，而Socket类处于传输层。</p><p>　　可见，传输层位于这个结构的最底层，当其上面的应用协议层和请求/响应层不能满足应用程序的特殊需要时，就需要使用这一层进行Socket套接字编程。 </p><p>　　而在.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。 </p><p>　　其实，Socket可以象流Stream一样被视为一个数据通道，这个通道架设在应用程序端（客户端）和远程服务器端之间。而后，数据的读取（接收）和写入（发送）均针对这个通道来进行。 </p><p>　　可见，在应用程序端或者服务器端创建了Socket对象之后，就可以使用Send/SentTo方法将数据发送到连接的Socket,或者使用Receive/ReceiveFrom方法接收来自连接Socket的数据。</p><p>　　针对Socket编程，.NET 框架的 Socket 类是 Winsock32 API 提供的套接字服务的托管代码版本。其中为实现网络编程提供了大量的方法，大多数情况下，Socket 类方法只是将数据封送到它们的本机Win32 副本中并处理任何必要的安全检查。如果你熟悉Winsock API函数，那么用Socket类编写网络程序会非常容易，当然，如果你不曾接触过，也不会太困难，跟随下面的解说，你会发觉使用Socket类开发windows 网络应用程序原来有规可寻，它们在大多数情况下遵循大致相同的步骤。 </p><p>　　在使用之前，你需要首先创建Socket对象的实例，这可以通过Socket类的构造方法来实现： </p><p>public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType); </p><p>　　其中，addressFamily 参数指定 Socket 使用的寻址方案，socketType 参数指定 Socket 的类型，protocolType 参数指定 Socket 使用的协议。 </p><p>　　下面的示例语句创建一个Socket，它可用于在基于 TCP/IP 的网络（如 Internet）上通讯。 </p><p>Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); </p><p>　　若要使用 UDP 而不是 TCP，需要更改协议类型，如下面的示例所示： </p><p>Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); </p><p>　　一旦创建 Socket，在客户端，你将可以通过Connect方法连接到指定的服务器，并通过Send/SendTo方法向远程服务器发送数据，而后可以通过Receive/ReceiveFrom从服务端接收数据；而在服务器端，你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联，并通过Listen方法侦听该接口上的请求，当侦听到用户端的连接时，调用Accept完成连接的操作，创建新的Socket以处理传入的连接请求。使用完Socket后，记住使用 Shutdown 方法禁用Socket，并使用 Close 方法关闭 Socket。其间用到的方法/函数有： </p><p>Socket.Connect方法:建立到远程设备的连接 <br />public void Connect(EndPoint remoteEP)（有重载方法） <br />Socket.Send 方法:从数据中的指示位置开始将数据发送到连接的 Socket。 <br />public int Send(byte[], int, SocketFlags);(有重载方法) <br />Socket.SendTo 方法 将数据发送到特定终结点。 <br />public int SendTo(byte[], EndPoint);（有重载方法） <br />Socket.Receive方法:将数据从连接的 Socket 接收到接收缓冲区的特定位置。 <br />public int Receive(byte[],int,SocketFlags); <br />Socket.ReceiveFrom方法：接收数据缓冲区中特定位置的数据并存储终结点。 <br />public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint); <br />Socket.Bind 方法：使 Socket 与一个本地终结点相关联： <br />public void Bind( EndPoint localEP ); <br />Socket.Listen方法：将 Socket 置于侦听状态。 <br />public void Listen( int backlog ); <br />Socket.Accept方法:创建新的 Socket 以处理传入的连接请求。 <br />public Socket Accept(); <br />Socket.Shutdown方法:禁用某 Socket 上的发送和接收 <br />public void Shutdown( SocketShutdown how ); <br />Socket.Close方法:强制 Socket 连接关闭 <br />public void Close(); </p><p>　　可以看出，以上许多方法包含EndPoint类型的参。在Internet中，TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备；端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点。</p><p>　　在 .NET 框架中正是由 EndPoint 类表示这个终结点，它提供表示网络资源或服务的抽象，用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代；对于 IP 地址族，该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息，通过组合服务的主机IP地址和端口号，IPEndPoint 类形成到服务的连接点。 </p><p>　　用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址，.Net中有两种类可以得到IP地址实例： <br />　　　IPAddress类：IPAddress 类包含计算机在 IP 网络上的地址。其Parse方法可将 IP 地址字符串转换为 IPAddress 实例。下面的语句创建一个 IPAddress 实例： </p><p>IPAddress myIP = IPAddress.Parse("192.168.1.2"); </p><p><br />Dns 类：向使用 TCP/IP Internet 服务的应用程序提供域名服务。其Resolve 方法查询 DNS 服务器以将用户友好的域名（如"host.contoso.com"）映射到数字形式的 Internet 地址（如 192.168.1.1）。Resolve方法返回一个 IPHostEnty 实例，该实例包含所请求名称的地址和别名的列表。大多数情况下，可以使用 AddressList 数组中返回的第一个地址。下面的代码获取一个 IPAddress 实例，该实例包含服务器 host.contoso.com 的 IP 地址。 </p><p>IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com"); <br />IPAddress ipAddress = ipHostInfo.AddressList[0]; </p><p><br />　　你也可以使用GetHostName方法得到IPHostEntry实例： </p><p>IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com") </p><p><br />　　在使用以上方法时，你将可能需要处理以下几种异常： </p><p>　　SocketException异常：访问Socket时操作系统发生错误引发 </p><p>　　ArgumentNullException异常：参数为空引用引发 </p><p>　　ObjectDisposedException异常：Socket已经关闭引发 </p><p>　　在掌握上面得知识后，下面的代码将该服务器主机（ host.contoso.com的 IP 地址与端口号组合，以便为连接创建远程终结点： </p><p>IPEndPoint ipe = new IPEndPoint(ipAddress,11000); </p><p><br />　　确定了远程设备的地址并选择了用于连接的端口后，应用程序可以尝试建立与远程设备的连接。下面的示例使用现有的 IPEndPoint 实例与远程设备连接，并捕获可能引发的异常： </p><p>try { <br />s.Connect(ipe);//尝试连接 <br />} <br />//处理参数为空引用异常 <br />catch(ArgumentNullException ae) { <br />Console.WriteLine("ArgumentNullException : {0}", ae.ToString()); <br />} <br />//处理操作系统异常 <br />catch(SocketException se) { <br />Console.WriteLine("SocketException : {0}", se.ToString()); <br />} <br />catch(Exception e) { <br />Console.WriteLine("Unexpected exception : {0}", e.ToString()); <br />} </p><p><br />　　需要知道的是：Socket 类支持两种基本模式：同步和异步。其区别在于：在同步模式中，对执行网络操作的函数（如 Send 和 Receive）的调用一直等到操作完成后才将控制返回给调用程序。在异步模式中，这些调用立即返回。 </p><p>　　另外，很多时候，Socket编程视情况不同需要在客户端和服务器端分别予以实现，在客户端编制应用程序向服务端指定端口发送请求，同时编制服务端应用程序处理该请求，这个过程在上面的阐述中已经提及；当然，并非所有的Socket编程都需要你严格编写这两端程序；视应用情况不同，你可以在客户端构造出请求字符串，服务器相应端口捕获这个请求，交由其公用服务程序进行处理。以下事例语句中的字符串就向远程主机提出页面请求： </p><p>string Get = "GET / HTTP/1.1\r\nHost: " + server + "\r\nConnection: Close\r\n\r\n"; </p><p><br />　　远程主机指定端口接受到这一请求后，就可利用其公用服务程序进行处理而不需要另行编制服务器端应用程序。 </p><p>　　综合运用以上阐述的使用Visual C#进行Socket网络程序开发的知识，下面的程序段完整地实现了Web页面下载功能。用户只需在窗体上输入远程主机名（Dns 主机名或以点分隔的四部分表示法格式的 IP 地址）和预保存的本地文件名，并利用专门提供Http服务的80端口，就可以获取远程主机页面并保存在本地机指定文件中。如果保存格式是.htm格式，你就可以在Internet浏览器中打开该页面。适当添加代码，你甚至可以实现一个简单的浏览器程序。 </p><p><br />实现此功能的主要源代码如下： </p><p>//"开始"按钮事件 <br />private void button1_Click(object sender, System.EventArgs e) { <br />//取得预保存的文件名 <br />string fileName=textBox3.Text.Trim(); <br />//远程主机 <br />string hostName=textBox1.Text.Trim(); <br />//端口 <br />int port=Int32.Parse(textBox2.Text.Trim()); <br />//得到主机信息 <br />IPHostEntry ipInfo=Dns.GetHostByName(hostName); <br />//取得IPAddress[] <br />IPAddress[] ipAddr=ipInfo.AddressList; <br />//得到ip <br />IPAddress ip=ipAddr[0]; <br />//组合出远程终结点 <br />IPEndPoint hostEP=new IPEndPoint(ip,port); <br />//创建Socket 实例 <br />Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); <br />try <br />{ <br />//尝试连接 <br />socket.Connect(hostEP); <br />} <br />catch(Exception se) <br />{ <br />MessageBox.Show("连接错误"+se.Message,"提示信息 <br />,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); <br />} <br />//发送给远程主机的请求内容串 <br />string sendStr="GET / HTTP/1.1\r\nHost: " + hostName + <br />"\r\nConnection: Close\r\n\r\n"; <br />//创建bytes字节数组以转换发送串 <br />byte[] bytesSendStr=new byte[1024]; <br />//将发送内容字符串转换成字节byte数组 <br />bytesSendStr=Encoding.ASCII.GetBytes(sendStr); <br />try <br />{ <br />//向主机发送请求 <br />socket.Send(bytesSendStr,bytesSendStr.Length,0); <br />} <br />catch(Exception ce) <br />{ <br />MessageBox.Show("发送错误:"+ce.Message,"提示信息 <br />,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); <br />} <br />//声明接收返回内容的字符串 <br />string recvStr=""; <br />//声明字节数组，一次接收数据的长度为1024字节 <br />byte[] recvBytes=new byte[1024]; <br />//返回实际接收内容的字节数 <br />int bytes=0; <br />//循环读取，直到接收完所有数据 <br />while(true) <br />{ <br />bytes=socket.Receive(recvBytes,recvBytes.Length,0); <br />//读取完成后退出循环 <br />if(bytes&lt;=0) <br />break; <br />//将读取的字节数转换为字符串 <br />recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes); <br />} <br />//将所读取的字符串转换为字节数组 <br />byte[] content=Encoding.ASCII.GetBytes(recvStr); <br />try <br />{ <br />//创建文件流对象实例 <br />FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite); <br />//写入文件 <br />fs.Write(content,0,content.Length); <br />} <br />catch(Exception fe) <br />{ <br />MessageBox.Show("文件创建/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information); <br />} <br />//禁用Socket <br />socket.Shutdown(SocketShutdown.Both); <br />//关闭Socket <br />socket.Close(); <br />} <br />} </p><p><br />　　程序在WindowsXP中文版、.Net Frameworkd 中文正式版、Visual Studio.Net中文正式版下调试通过。<br /> </p><br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=604607</p><img src ="http://www.blogjava.net/zqli/aggbug/71536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zqli/" target="_blank">放水老倌</a> 2006-09-24 11:12 <a href="http://www.blogjava.net/zqli/archive/2006/09/24/71536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]c#网络编程之------------Socket编程基础</title><link>http://www.blogjava.net/zqli/archive/2006/09/24/71533.html</link><dc:creator>放水老倌</dc:creator><author>放水老倌</author><pubDate>Sun, 24 Sep 2006 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/zqli/archive/2006/09/24/71533.html</guid><wfw:comment>http://www.blogjava.net/zqli/comments/71533.html</wfw:comment><comments>http://www.blogjava.net/zqli/archive/2006/09/24/71533.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zqli/comments/commentRss/71533.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zqli/services/trackbacks/71533.html</trackback:ping><description><![CDATA[Socket编程基础<br /><br />本章以Berkeley Socket为主，主要介绍网络编程时常用的调用和程序使用它们的方法及基本结构。网络编程有两种主要的编程接口，一种是Berkeley UNIX（BSD UNIX）的socket编程接口，另一种是AT&amp;T的TLI接口（用于UNIXSYSV）。<br />1 、TCP/IP 基础知识 <br />这里先假定读者对ISO的OSI七层模型已有了一定的了解，下面我们来看看TCP/IP模型。ISO的OSI对服务、接口和协议的概念区别十分明了，但它却没有真正的用户群。TCP/IP模型对服务、接口和协议的概念区别不象OSI模型那样明晰，但很实用。TCP/IP模型分为四层，对应于OSI七层模型如下图所示：图6-1 TCP/IP参考模型与OSI模型的近似对应关系在TCP/IP模型中，互联网层是基于无连接互联网络层的分组交换网络。在这一层中主机可以把报文（Packet）发往任何网络，报文独立地传向目标。互联网层定义了报文的格式和协议，这就是IP协议族（Internet Protocol）。互联网层的功能是将报文发送到目的地，主要的设计问题是报文路由和避免阻塞。互联网层上面是传输层，该层的主要功能和OSI模型的该层一样，主要使源和目的主机之间可以进行会话。该层定义了两个端到端的协议，一个是面向连接的传输控制协议TCP，另一个是无连接的用户数据报协议UDP。TCP/IP协议模型中没有会话层和表示层。传输层之上是应用层，它包含所有的高层协议，如远程虚拟终端协议TELNET、文件传输协议FTP、简单邮件传输协议SMTP等。这些高层协议中常见的如TELNET协议，用来允许用户远程登录到另一台UNIX机器；FTP协议用来传输文件，常见的有WU-FTP（Washington University的FTP服务器端程序，是一个免费程序）；SMTP协议用来传送email，常见的服务器端程序有netscape等公司制作的程序，也有免费使用的sendmail程序；还有域名系统服务DNS协议，新闻组传送协议NNTP，用于WWW的超文本传输协议HTTP等。主机到网络这一层，在TCP/IP模型中没有详细定义，这里不作介绍。<br />2、 Socket一般描述 <br />由于越来越多的计算机厂商，特别是工作站制造商如Sun等公司采用了Berkeley UNIX，socket接口被广泛采用，以至于现在，socket接口被广泛认可并成为了事实上的工业标准。目前的SYSV、BSD、OSF都将socket接口作为系统的一部分。当时设计如何支持TCP/IP协议时，有两种加入函数的方法，一种是直接加入支持TCP/IP协议的调用，另一种是加入支持一般网络协议的函数，而用参数来指定支持TCP/IP协议。Berkeley采用了后者，这样可以支持多协议族，TCP/IP是协议族之一（PF_INET）。<br />2.1 socket 描述符 <br />前面已经提到过，在UNIX中，进程要对文件进行操作，一般使用open调用打开一个文件进行访问，每个进程都有一个文件描述符表，该表中存放打开的文件描述符。用户使用open等调用得到的文件描述符其实是文件描述符在该表中的索引号，该表项的内容是一个指向文件表的指针。应用程序只要使用该描述符就可以对指定文件进行操作。同样，socket接口增加了网络通信操作的抽象定义，与文件操作一样，每个打开的socket都对应一个整数，我们称它为socket描述符，该整数也是socket描述符在文件描述符表中的索引值。但socket描述符在描述符表中的表项并不指向文件表，而是指向一个与该socket有关的数据结构。BSD UNIX中新增加了一个socket调用，应用程序可以调用它来新建一个socket描述符，注意进程用open只能产生文件描述符，而不能产生socket描述符。socket调用只能完成建立通信的部分工作，一旦建立了一个socket，应用程序可以使用其他特定的调用来为它添加其他详细信息，以完成建立通信的过程。 <br />2.2 从概念上理解socket的使用网络编程中最常见的是客户/服务器模式。<br />以该模式编程时，服务端有一个进程（或多个进程）在指定的端口等待客户来连接，服务程序等待客户的连接信息，一旦连接上之后，就可以按设计的数据交换方法和格式进行数据传输。客户端在需要的时刻发出向服务端的连接请求。<br />这里为了便于理解，提到了这些调用及其大致的功能。使用socket调用后，仅产生了一个可以使用的socket描述符，这时还不能进行通信，还要使用其他的调用，以使得socket所指的结构中使用的信息被填写完。在使用TCP协议时，一般服务端进程先使用socket调用得到一个描述符，然后使用bind调用将一个名字与socket描述符连接起来，对于Internet域就是将Internet地址联编到socket。之后，服务端使用listen调用指出等待服务请求队列的长度。然后就可以使用accept调用等待客户端发起连接（一般是阻塞等待连接，后面章节会讲到非阻塞的方式），一旦有客户端发出连接，accept返回客户的地址信息，并返回一个新的socket描述符，该描述符与原先的socket有相同的特性，这时服务端就可以使用这个新的socket进行读写操作了。一般服务端可能在accept返回后创建一个新的进程进行与客户的通信，父进程则再到accept调用处等待另一个连接。客户端进程一般先使用socket调用得到一个socket描述符，然后使用connect向指定的服务器上的指定端口发起连接，一旦连接成功返回，就说明已经建立了与服务器的连接，这时就可以通过socket描述符进行读写操作了。下面是在客户和服务端使用TCP时，客户进程和服务进程使用系统调用的该程。<br />使用TCP的客户和服务端使用系统调用的图示使用无连接的UDP协议时，服务端进程创建一个socket，之后调用recvfrom接收客户端的数据报，然后调用sendto将要返回客户端的消息发送给客户进程。客户端也要先创建一个socket，再使用sendto向服务端进程发出请求，使用recvfrom得到返回的消息。<img src ="http://www.blogjava.net/zqli/aggbug/71533.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zqli/" target="_blank">放水老倌</a> 2006-09-24 10:53 <a href="http://www.blogjava.net/zqli/archive/2006/09/24/71533.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>