﻿<?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/yanzhou/category/14798.html</link><description>喂马, 劈柴, 周游世界</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 14:57:42 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 14:57:42 GMT</pubDate><ttl>60</ttl><item><title>几种证书格式说明及Keytool命令</title><link>http://www.blogjava.net/yanzhou/archive/2006/12/12/87208.html</link><dc:creator>周游世界</dc:creator><author>周游世界</author><pubDate>Tue, 12 Dec 2006 04:50:00 GMT</pubDate><guid>http://www.blogjava.net/yanzhou/archive/2006/12/12/87208.html</guid><wfw:comment>http://www.blogjava.net/yanzhou/comments/87208.html</wfw:comment><comments>http://www.blogjava.net/yanzhou/archive/2006/12/12/87208.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yanzhou/comments/commentRss/87208.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yanzhou/services/trackbacks/87208.html</trackback:ping><description><![CDATA[.cer 包含证书主体的信息及证书的公钥，不包括私钥，可以公开。<br />.keystore 证书库，包含用户的公钥、私钥和证书。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080"> 1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">            FileInputStream in </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> FileInputStream(Path </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">RGCA.keystore</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080"> 2</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            KeyStore ks </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> KeyStore.getInstance(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">JKS</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080"> 3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            ks.load(in, pwd.toCharArray());<br /></span><span style="COLOR: #008080"> 4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            Certificate certificate </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> ks.getCertificate(alias);<br /></span><span style="COLOR: #008080"> 5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            System.out.println(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">从证书库中取得:</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">RadiusUtil.getHexString(certificate.getEncoded()));<br /></span><span style="COLOR: #008080"> 6</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            System.out.println(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">从证书库中取得PublicKey：</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">RadiusUtil.getHexString(certificate.getPublicKey().getEncoded()));<br /></span><span style="COLOR: #008080"> 7</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            X509Certificate x </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (X509Certificate)certificate;<br /></span><span style="COLOR: #008080"> 8</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            System.out.println(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">从证书库中取得Signature：</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">RadiusUtil.getHexString(x.getSignature()));<br /></span><span style="COLOR: #008080"> 9</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            PrivateKey caprk </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (PrivateKey)ks.getKey(alias, pwd.toCharArray());<br /></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            System.out.println(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">私钥:</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">RadiusUtil.getHexString(caprk.getEncoded()));</span></div><img src ="http://www.blogjava.net/yanzhou/aggbug/87208.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yanzhou/" target="_blank">周游世界</a> 2006-12-12 12:50 <a href="http://www.blogjava.net/yanzhou/archive/2006/12/12/87208.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZZ]认证方式探讨 EAP-MSCHAPV2</title><link>http://www.blogjava.net/yanzhou/archive/2006/11/12/80703.html</link><dc:creator>周游世界</dc:creator><author>周游世界</author><pubDate>Sun, 12 Nov 2006 07:24:00 GMT</pubDate><guid>http://www.blogjava.net/yanzhou/archive/2006/11/12/80703.html</guid><wfw:comment>http://www.blogjava.net/yanzhou/comments/80703.html</wfw:comment><comments>http://www.blogjava.net/yanzhou/archive/2006/11/12/80703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yanzhou/comments/commentRss/80703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yanzhou/services/trackbacks/80703.html</trackback:ping><description><![CDATA[
		<p align="center">
				<strong>
						<font size="5">认证方式探讨 EAP-MSCHAPV2</font>
				</strong>
				<br />
				<br />
		</p>
		<p>MSCHAP方式是,首先服务器发一个challenge给用户,用户向RADIUS发一个用MD4加密的(password,challenge)给RADIUS(叫response),radius的MSCHAP模块向LDAP询问NTPASSWORD,然后自己再用challenge和NTPASSWORD,来计算一个response,两个response相比较完成验证.如果LDAP无法给出NTPASSWORD或送出SHA加密的NTPASSWORD,MS-CHAP就无法验证了.唯一可行的办法是把LDAP的SCHEMA中加入NTPASSWORD域,并明文存放,才能满足MS-CHAP的要求.</p>
		<p>
				<br />PEAP-MSCHAPV2流程： <br />  1、创建一个连接后，AP发送一个EAP-Request/Identity消息给客户端。<br />  2、客户端回复一个EAP-Response/Identity消息，包含客户端的标识，通常是名字。<br />  3、AP把这个消息传递给Radius服务器。从现在开始，逻辑通信就从Radius服务器到无线客户端了，AP,AC是一个中介设备。<br />  4、Radius服务器发送一个EAP-Request/Start PEAP消息给客户端。<br />  5、无线客户端和Radius服务器发送一系列的TLS消息通过协商建立的隧道。Raiuds服务器发送一个证书链让客户端认证。最后，Radius服务器已经认证了无线客户端。两端都决定使用的加密信息。<br />  在PEAP TLS隧道创建后，采用MS-CHAPV2认证。<br />  6、Radius服务器发送一个EAP-Request/Identity消息。<br />  7、无线客户端发送一个EAP-Response/Identity 消息，消息包用户名。<br />  8、Radius服务器发送一个EAP-Request/EAP-MS-CHAP-V2挑战消息，包含挑战字符串。<br />  9、无线客户端回复一个EAP-Response/EAP-MS-CHAPV2回复消息，包含对这个挑战的应答和一个自己的挑战。<br />  10、Radius服务器发送一个EAP-Request/EAP-MS-CHAPV2成功的消息，指出无线客户端的回应是正确的，且包含无线客户端的挑战字符串。<br />  11、无线客户端回应一个EAP-Response/EAP-MS-CHAPV2的ACK消息，指示Radius服务器的回应消息是正确的。<br />  12、Radius服务器发送一个EAP-Success消息。</p>
		<p>EAP -TLS是一个IETF标准。TLS即传输层安全（Transport Layer Security），也称为SSL。它原本是一种传输层的安全协议，主要实现两个功能：身份鉴别与信息加密。TLS可实现基于证书的单向身份鉴别（只鉴别服务器）和双向身份鉴别（同时鉴别客户端与服务器）。TLS在完成身份鉴别的同时，还交换密钥信息，通过密钥信息可导出会话密钥用于信息加密。<br />需要指出的是，在这里TLS并不是作为一个安全传输层协议跑在TCP/IP层之上，而是将TLS的Handshake Record直接嵌套在EAP数据包中，作为EAP Request/Response的数据来传送，通过TLS的Handshake Record完成单向或双向的身份鉴别。EAP－TLS只利用了TLS的身份鉴别功能，并没有利用TLS建立的加密通道。<br />为了能够进一步利用 TLS建立的安全通道交换EAP身份鉴别信息，IETF随后出台了PEAP（Protected EAP Protocol）标准草案。PEAP不但通过EAP Request/Response数据包传送TLS的Handshake Record完成身份鉴别，并且完成身份鉴别后进一步通过TLS的Data Record再传送EAP身份鉴别协议。</p>
		<p>对于密钥：<br />der  “专有编码规则”文件。.der 文件包含证书的二进制表示，包含其公共密钥，但不包含其专用密钥。它与 .arm 文件非常相似，除了表示是二进制的，而非 ASCII。 <br />.p12  "PKCS 12" 文件，其中 PKCS 代表“公共密钥密码术标准 (Public-Key CryptographyStandards)”。.p12 文件包含证书的二进制表示，包含其公共密钥和专用密钥。一个 .p12 文件中也可能包含多个证书；例如，证书、发出证书的 CA 的证书、CA 证书的发出者以及他的发出者等等。因为 .p12 文件包含专用密钥，它是受口令保护的。<br /></p>
<img src ="http://www.blogjava.net/yanzhou/aggbug/80703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yanzhou/" target="_blank">周游世界</a> 2006-11-12 15:24 <a href="http://www.blogjava.net/yanzhou/archive/2006/11/12/80703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA教程 第八讲 Java网络编程(三)</title><link>http://www.blogjava.net/yanzhou/archive/2006/11/05/79186.html</link><dc:creator>周游世界</dc:creator><author>周游世界</author><pubDate>Sun, 05 Nov 2006 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/yanzhou/archive/2006/11/05/79186.html</guid><wfw:comment>http://www.blogjava.net/yanzhou/comments/79186.html</wfw:comment><comments>http://www.blogjava.net/yanzhou/archive/2006/11/05/79186.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yanzhou/comments/commentRss/79186.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yanzhou/services/trackbacks/79186.html</trackback:ping><description><![CDATA[
		<span id="BlogViewId">
				<div>8.3.10 据报Datagram通讯 <br /><br />　　前面在介绍TCP/IP协议的时候，我们已经提到，在TCP/IP协议的传输层除了TCP协议之外还有一个UDP协议，相比而言UDP的应用不如TCP广泛，几个标准的应用层协议 HTTP，FTP，SMTP…使用的都是TCP协议。但是，随着计算机网络的发展，UDP协议正越来越来显示出其威力，尤其是在需要很强的实时交互性的场合，如<a href="http://www.it.com.cn/games/net/"><u><font color="#0000ff">网络</font></u></a><a href="http://www.it.com.cn/games/"><u><font color="#0000ff">游戏</font></u></a>，视频会议等，UDP更是显示出极强的威力，下面我们就介绍一下Java环境下如何实现UDP网络传输。 <br /><br />　　8.3.11 什么是Datagram <br /><br />　　所谓数据报（Datagram）就跟日常生活中的邮件系统一样，是不能保证可靠的寄到的，而面向链接的TCP就好比电话，双方能肯定对方接受到了信息。在本章前面，我们已经对UDP和TCP进行了比较，在这里再稍作小节： <br /><br />　　TCP，可靠，传输大小无限制，但是需要连接建立时间，差错控制开销大。 <br />　　UDP，不可靠，差错控制开销较小，传输大小限制在64K以下，不需要建立连接。 <br /><br />　　总之，这两种协议各有特点，应用的场合也不同，是完全互补的两个协议，在TCP/IP协议中占有同样重要的地位，要学好网络编程，两者缺一不可。 <br /><br />　　8.3.12 Datagram通讯的表示方法：DatagramSocket；DatagramPacket <br /><br />　　包java.net中提供了两个类DatagramSocket和DatagramPacket用来支持数据报通信，DatagramSocket用于在程序之间建立传送数据报的通信连接， DatagramPacket则用来表示一个数据报。先来看一下DatagramSocket的构造方法： <br />　　　DatagramSocket（）； <br />　　　DatagramSocket（int prot）; <br />　　　DatagramSocket(int port, InetAddress laddr) <br />　　 <br />　　其中，port指明socket所使用的端口号，如果未指明端口号，则把socket连接到本地主机上一个可用的端口。laddr指明一个可用的本地地址。给出端口号时要保证不发生端口冲突，否则会生成SocketException类例外。注意：上述的两个构造方法都声明抛弃非运行时例外 SocketException，程序中必须进行处理，或者捕获、或者声明抛弃。 <br /><br />　　用数据报方式编写client/server程序时，无论在客户方还是服务方，首先都要建立一个DatagramSocket对象，用来接收或发送数据报，然后使用DatagramPacket类对象作为传输数据的载体。下面看一下DatagramPacket的构造方法 ： <br />　　　DatagramPacket（byte buf[],int length）； <br />　　　DatagramPacket(byte buf[], int length, InetAddress addr, int port); <br />　　　DatagramPacket(byte[] buf, int offset, int length)； <br />　　　DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)； <br /><br />　　其中，buf中存放数据报数据，length为数据报中数据的长度，addr和port旨明目的地址，offset指明了数据报的位移量。 <br /><br />　　在接收数据前，应该采用上面的第一种方法生成一个DatagramPacket对象，给出接收数据的缓冲区及其长度。然后调用DatagramSocket 的方法receive()等待数据报的到来，receive()将一直等待，直到收到一个数据报为止。 <br />　　DatagramPacket packet=new DatagramPacket(buf, 256); <br />　　Socket.receive (packet); <br /><br />　　发送数据前，也要先生成一个新的DatagramPacket对象，这时要使用上面的第二种构造方法，在给出存放发送数据的缓冲区的同时，还要给出完整的目的地址，包括IP地址和端口号。发送数据是通过DatagramSocket的方法send()实现的，send()根据数据报的目的地址来寻径，以传递数据报。 <br />　　DatagramPacket packet=new DatagramPacket(buf, length, address, port); <br />　　Socket.send(packet)； <br /><br />　　在构造数据报时，要给出InetAddress类参数。类InetAddress在包java.net中定义，用来表示一个Internet地址，我们可以通过它提供的类方法getByName（）从一个表示主机名的字符串获取该主机的IP地址，然后再获取相应的地址信息。 <br /><br />　　8.3.13 基于UDP的简单的Client/Server程序设计 <br /><br />　　有了上面的知识，我们就可以来构件一个基于UDP的C/S 网络传输模型 <br /><br />　　1. 客户方程序 QuoteClient.java <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　import java.util.*; <br />　　public class QuoteClient { <br />　　　public static void main(String[] args) throws IOException <br />　　　{ <br />　　　　if(args.length!=1) { <br />　　　　//如果启动的时候没有给出Server的名字，那么出错退出 <br />　　　　　System.out.println("Usage:java QuoteClient "); <br />　　　　　//打印出错信息 <br />　　　　　return; //返回 <br />　　　　} <br /><br />　　　　DatagramSocket socket=new DatagramSocklet(); <br />　　　　//创建数据报套接字 <br /><br />　　　　Byte[] buf=new byte[256]; //创建缓冲区 <br />　　　　InetAddress address=InetAddress.getByName(args [0]); <br />　　//由命令行给出的第一个参数默认为Server的名字，通过它得到Server的IP信息 <br />　　　　DatagramPacket packet=new DatagramPacket (buf, buf.length, address, 4445); <br />　　　　//创建DatagramPacket对象 <br />　　　　socket.send(packet); //发送 <br />　　　　packet=new DatagramPacket(buf,buf.length); <br />　　　　//创建新的DatagramPacket对象，用来接收数据报 <br />　　　　socket.receive(packet); //接收 <br />　　　　String received=new String(packet.getData()); <br />　　　　//根据接收到的字节数组生成相应的字符串 <br />　　　　System.out.println("Quote of the Moment:"+received ); <br />　　　　//打印生成的字符串 <br /><br />　　　　socket.close(); //关闭套接口 <br />　　　} <br />　　} <br /><br />　　2. <a href="http://www.it.com.cn/server/"><u><font color="#0000ff">服务器</font></u></a>方程序:QuoteServer.java <br /><br />　　public class QuoteServer{ <br />　　　public static void main(String args[]) throws java.io.IOException <br />　　　{ <br />　　　　new QuoteServerThread().start(); <br />　　　　//启动一个QuoteServerThread线程 <br />　　　} <br />　　} <br /><br />　　3. 程序QuoteServerThread.java <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　import java.util.*; <br />　　//服务器线程 <br />　　public class QuoteServerThread extends Thread <br />　　{ <br />　　protected DatagramSocket socket=null; <br />　　//记录和本对象相关联的DatagramSocket对象 <br />　　protected BufferedReader in=null; <br />　　//用来读文件的一个Reader <br />　　protected boolean moreQuotes=true; <br />　　//标志变量，是否继续操作 <br /><br />　　public QuoteServerThread() throws IOException { <br />　　//无参数的构造函数 <br />　　　　this("QuoteServerThread"); <br />　　　　//以QuoteServerThread为默认值调用带参数的构造函数 <br />　　} <br />　　public QuoteServerThread(String name) throws IOException { <br />　　　　super(name); //调用父类的构造函数 <br />　　　　socket=new DatagramSocket(4445); <br />　　　　//在端口4445创建数据报套接字 <br />　　　　try{ <br />　　　　　　in= new BufferedReader(new FileReader(" one-liners.txt")); <br />　　　　　　//打开一个文件，构造相应的BufferReader对象 <br />　　　　}catch(FileNotFoundException e) { //异常处理 <br />　　　　　　System.err.println("Could not open quote file. Serving time instead."); <br />　　　　　　　//打印出错信息 <br />　　　　} <br />　　} <br />　　public void run() //线程主体 <br />　　{ <br />　　　　while(moreQuotes) { <br />　　　　　try{ <br />　　　　　　　byte[] buf=new byte[256]; //创建缓冲区 <br />　　　　　　　DatagramPacket packet=new DatagramPacket(buf,buf.length); <br />　　　　　　　//由缓冲区构造DatagramPacket对象 <br />　　　　　　　socket.receive(packet); //接收数据报 <br />　　　　　　　String dString=null; <br />　　　　　　　if(in= =null) dString=new Date().toString(); <br />　　　　　　　//如果初始化的时候打开文件失败了， <br />　　　　　　　//则使用日期作为要传送的字符串 <br />　　　　　　　else dString=getNextQuote(); <br />　　　　　　　//否则调用成员函数从文件中读出字符串 <br />　　　　　　　buf=dString.getByte(); <br />　　　　　　　//把String转换成字节数组，以便传送 <br /><br />　　　　　　　InetAddress address=packet.getAddress(); <br />　　　　　　　//从Client端传来的Packet中得到Client地址 <br />　　　　　　　int port=packet.getPort(); //和端口号 <br />　　　　　　　packet=new DatagramPacket(buf,buf.length,address,port); <br />　　　　　　　//根据客户端信息构建DatagramPacket <br />　　　　　　　socket.send(packet); //发送数据报 <br />　　　　　　}catch(IOException e) { //异常处理 <br />　　　　　　　e.printStackTrace(); //打印错误栈 <br />　　　　　　　moreQuotes=false; //标志变量置false，以结束循环 <br />　　　　　　} <br />　　　　} <br />　　　　socket.close(); //关闭数据报套接字 <br />　　} <br /><br />　　protected String getNextQuotes(){ <br />　　//成员函数，从文件中读数据 <br />　　　　String returnValue=null; <br />　　　　try { <br />　　　　　　　if((returnValue=in.readLine())= =null) { <br />　　　　　　　//从文件中读一行，如果读到了文件尾 <br />　　　　　　　in.close( ); //关闭输入流 <br />　　　　　　　moreQuotes=false; <br />　　　　　　　//标志变量置false，以结束循环 <br />　　　　　　　returnValue="No more quotes. Goodbye."; <br />　　　　　　　//置返回值 <br />　　　　　　　} //否则返回字符串即为从文件读出的字符串 <br />　　　　}catch(IOEception e) { //异常处理 <br />　　　　　　　returnValue="IOException occurred in server"; <br />　　　　　　　//置异常返回值 <br />　　　　} <br />　　　　return returnValue; //返回字符串 <br />　　} <br />　　} <br /></div>可以看出使用UDP和使用TCP在程序上还是有很大的区别的。一个比较明显的区别是，UDP的Socket编程是不提供监听功能的，也就是说通信双方更为平等，面对的接口是完全一样的。但是为了用UDP实现C/S结构，在使用UDP时可以使用DatagramSocket.receive()来实现类似于监听的功能。因为receive()是阻塞的函数，当它返回时，缓冲区里已经填满了接受到的一个数据报，并且可以从该数据报得到发送方的各种信息，这一点跟 accept()是很相象的，因而可以根据读入的数据报来决定下一步的动作，这就达到了跟网络监听相似的效果。 <br /><br />　　 <br /><br />　　8.3.14 用数据报进行广播通讯 <br /><br />　　DatagramSocket只允许数据报发送一个目的地址，java.net包中提供了一个类MulticastSocket，允许数据报以广播方式发送到该端口的所有客户。MulticastSocket用在客户端，监听服务器广播来的数据。 <br /><br />　　我们对上面的程序作一些修改，利用MulticastSocket实现广播通信。新程序完成的功能是使同时运行的多个客户程序能够接收到服务器发送来的相同的信息，显示在各自的屏幕上。 <br /><br />　　1. 客户方程序:MulticastClient.java <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　import java.util.*; <br />　　public class MulticastClient { <br />　　　　public static void main(String args[]) throws IOException <br />　　　　{ <br />　　　　　MulticastSocket socket=new MulticastSocket(4446); <br />　　　　　//创建4446端口的广播套接字 <br />　　　　　InetAddress address=InetAddress.getByName("230.0.0.1"); <br />　　　　　//得到230.0.0.1的地址信息 <br />　　　　　socket.joinGroup(address); <br />　　　　　//使用joinGroup()将广播套接字绑定到地址上 <br />　　　　　DatagramPacket packet; <br /><br />　　　　　for(int i=0;i&lt;5;i++) { <br />　　　　　　　byte[] buf=new byte[256]; <br />　　　　　　　//创建缓冲区 <br />　　　　　　　packet=new DatagramPacket(buf,buf.length); <br />　　　　　　　//创建接收数据报 <br />　　　　　　　socket.receive(packet); //接收 <br />　　　　　　　String received=new String(packet.getData()); <br />　　　　　　　//由接收到的数据报得到字节数组， <br />　　　　　　　//并由此构造一个String对象 <br />　　　　　　　System.out.println("Quote of theMoment:"+received); <br />　　　　　　　//打印得到的字符串 <br />　　　　　} //循环5次 <br />　　　　　socket.leaveGroup(address); <br />　　　　　//把广播套接字从地址上解除绑定 <br />　　　　　socket.close(); //关闭广播套接字 <br />　　　} <br />　　} <br /><br />　　2. 服务器方程序:MulticastServer.java <br /><br />　　public class MulticastServer{ <br />　　　　public static void main(String args[]) throws java.io.IOException <br />　　　　{ <br />　　　　　　new MulticastServerThread().start(); <br />　　　　　　//启动一个服务器线程 <br />　　　　} <br />　　} <br /><br />　　3. 程序MulticastServerThread.java <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　import java.util.*; <br />　　public class MulticastServerThread extends QuoteServerThread <br />　　//从QuoteServerThread继承得到新的服务器线程类MulticastServerThread <br />　　{ <br />　　　　Private long FIVE_SECOND=5000; //定义常量，5秒钟 <br />　　　　public MulticastServerThread(String name) throws IOException <br />　　　　{ <br />　　　　　　super("MulticastServerThread"); <br />　　　　　　//调用父类，也就是QuoteServerThread的构造函数 <br />　　　　} <br /><br />　　　　public void run() //重写父类的线程主体 <br />　　　　{ <br />　　　　　while(moreQuotes) { <br />　　　　　//根据标志变量判断是否继续循环 <br />　　　　　　try{ <br />　　　　　　　　byte[] buf=new byte[256]; <br />　　　　　　　　//创建缓冲区 <br />　　　　　　　　String dString=null; <br />　　　　　　　　if(in==null) dString=new Date().toString(); <br />　　　　　　　　//如果初始化的时候打开文件失败了， <br />　　　　　　　　//则使用日期作为要传送的字符串 <br />　　　　　　　　else dString=getNextQuote(); <br />　　　　　　　　//否则调用成员函数从文件中读出字符串 <br />　　　　　　　　buf=dString.getByte(); <br />　　　　　　　　//把String转换成字节数组，以便传送send it <br />　　　　　　　　InetAddress group=InetAddress.getByName("230.0.0.1"); <br />　　　　　　　　//得到230.0.0.1的地址信息 <br />　　　　　　　　DatagramPacket packet=new DatagramPacket(buf,buf.length,group,4446); <br />　　　　　　　　//根据缓冲区，广播地址，和端口号创建DatagramPacket对象 <br />　　　　　　　　socket.send(packet); //发送该Packet <br />　　　　　　　　try{ <br />　　　　　　　　　　sleep((long)(Math.random()*FIVE_SECONDS)); <br />　　　　　　　　　　//随机等待一段时间，0～5秒之间 <br />　　　　　　　　}catch(InterruptedException e) { } //异常处理 <br />　　　　　　}catch(IOException e){ //异常处理 <br />　　　　　　　　e.printStackTrace( ); //打印错误栈 <br /><br />　　　　　　　　moreQuotes=false; //置结束循环标志 <br />　　　　　　} <br />　　　　} <br />　　　　socket.close( ); //关闭广播套接口 <br />　　　} <br />　　} <br /><br />　　至此，Java网络编程这一章已经讲解完毕。读者通过学习，应该对网络编程有了一个清晰的认识，可能对某些概念还不是十分的清楚，还是需要更多的实践来进一步掌握。编程语言的学习不同于一般的学习，及其强调实践的重要性。读者应该对URL网络编程，Socket中的TCP，UDP编程进行大量的练习才能更好的掌握本章中所提到的一些概念，才能真正学到Java网络编程的精髓！ <br /><br />　　最后几个小节所举的例子，读者务必要亲自试验一下，如果遇到问题，想办法解决之。最好能根据自己的意图加以改进。这样才能更好的理解这几个程序，理解其中所包含的编程思想。 <br /><br />　　<span id="BlogViewId">【</span>本讲小结】 <br /><br />　　本讲主要讲解了Java环境下的网络编程。因为TCP/IP协议是Java网络编程的基础知识，本讲开篇重点介绍了TCP/IP协议中的一些概念， TCP/IP协议本身是一个十分庞大的系统，用几个小节是不可能讲清楚的。所以我们只是联系实际，讲解了一些最基本的概念，帮助学生理解后面的相关内容。重点有一下几个概念：主机名，IP，端口，服务类型，TCP，UDP。 <br /><br />　　后续的内容分为两大块，一块是以URL为主线，讲解如何通过URL类和URLConnection类访问WWW网络资源，由于使用URL十分方便直观，尽管功能不是很强，还是值得推荐的一种网络编程方法，尤其是对于初学者特别容易接受。本质上讲，URL网络编程在传输层使用的还是TCP协议。 <br /><br />　　另一块是以Socket接口和C/S网络编程模型为主线，依次讲解了如何用Java实现基于TCP的C/S结构，主要用到的类有Socket，ServerSocket。以及如何用Java实现基于 UDP的C/S结构，还讨论了一种特殊的传输方式，广播方式，这种方式是UDP所特有的，主要用到的类有DatagramSocket , DatagramPacket, MulticastSocket。这一块在Java网络编程中相对而言是最难的（尽管Java在网络编程这方面已经做的够"傻瓜"了，但是网络编程在其他环境下的却是一件极为头痛的事情，再"傻瓜"还是有一定的难度），也是功能最为强大的一部分,读者应该好好研究，领悟其中的思想。 <br /><br />　　最后要强调的是要学好Java网络编程，Java语言，最重要的还是在于多多练习！ </span>
<img src ="http://www.blogjava.net/yanzhou/aggbug/79186.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yanzhou/" target="_blank">周游世界</a> 2006-11-05 12:36 <a href="http://www.blogjava.net/yanzhou/archive/2006/11/05/79186.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA教程 第八讲 Java网络编程(二)</title><link>http://www.blogjava.net/yanzhou/archive/2006/11/05/79180.html</link><dc:creator>周游世界</dc:creator><author>周游世界</author><pubDate>Sun, 05 Nov 2006 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/yanzhou/archive/2006/11/05/79180.html</guid><wfw:comment>http://www.blogjava.net/yanzhou/comments/79180.html</wfw:comment><comments>http://www.blogjava.net/yanzhou/archive/2006/11/05/79180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yanzhou/comments/commentRss/79180.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yanzhou/services/trackbacks/79180.html</trackback:ping><description><![CDATA[
		<span id="BlogViewId">8.3 基于Socket（套接字）的低层次Java网络编程 <br /><br />　　8.3.1 Socket通讯 <br /><br />　　网络上的两个程序通过一个双向的通讯连接实现数据的交换，这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面，一个Socket由一个IP地址和一个端口号唯一确定。 <br /><br />　　在传统的UNIX环境下可以操作TCP/IP协议的接口不止Socket一个，Socket所支持的协议种类也不光TCP/IP一种，因此两者之间是没有必然联系的。在Java环境下，Socket编程主要是指基于TCP/IP协议的网络编程。 <br /><br />　　说Socket编程是低层次网络编程并不等于它功能不强大，恰恰相反，正因为层次低，Socket编程比基于URL的网络编程提供了更强大的功能和更灵活的控制，但是却要更复杂一些。由于Java本身的特殊性，Socket编程在Java中可能已经是层次最低的网络编程接口，在Java中要直接操作协议中更低的层次，需要使用Java的本地方法调用（JNI），在这里就不予讨论了。 <br /><br />　　8.3.2 Socket通讯的一般过 <br /><br />　　前面已经提到Socket通常用来实现C/S结构。 <br /><br />　　使用Socket进行Client/Server程序设计的一般连接过程是这样的：Server端Listen(监听)某个端口是否有连接请求， Client端向Server端发出Connect(连接)请求，Server端向Client端发回Accept（接受）消息。一个连接就建立起来了。 Server端和Client端都可以通过Send，Write等方法与对方通信。 <br /><br />　　对于一个功能齐全的Socket，都要包含以下基本结构，其工作过程包含以下四个基本的步骤： <br />　　（1） 创建Socket； <br />　　（2） 打开连接到Socket的输入/出流； <br />　　（3） 按照一定的协议对Socket进行读/写操作； <br />　　（4） 关闭Socket. <br /><br />　　第三步是程序员用来调用Socket和实现程序功能的关键步骤，其他三步在各种程序中基本相同。 <br /><br />　　以上4个步骤是针对TCP传输而言的，使用UDP进行传输时略有不同，在后面会有具体讲解。 <br /><br />　　8.3.3 创建Socket <br /><br />　　java在包java.net中提供了两个类Socket和ServerSocket，分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类，使用很方便。其构造方法如下： <br />　　Socket(InetAddress address, int port); <br />　　Socket(InetAddress address, int port, boolean stream); <br />　　Socket(String host, int prot); <br />　　Socket(String host, int prot, boolean stream); <br />　　Socket(SocketImpl impl) <br />　　Socket(String host, int port, InetAddress localAddr, int localPort) <br />　　Socket(InetAddress address, int port, InetAddress localAddr, int localPort) <br />　　ServerSocket(int port); <br />　　ServerSocket(int port, int backlog); <br />　　ServerSocket(int port, int backlog, InetAddress bindAddr) <br /><br />　　其中address、host和port分别是双向连接中另一方的IP地址、主机名和端口号，stream指明socket是流socket还是数据报 socket，localPort表示本地主机的端口号，localAddr和bindAddr是本地机器的地址（ServerSocket的主机地址），impl是socket的父类，既可以用来创建serverSocket又可以用来创建Socket。count则表示服务端所能支持的最大连接数。例如： <br />　　Socket client = new Socket("127.0.01.", 80); <br />　　ServerSocket server = new ServerSocket(80); <br /><br />　　注意，在选择端口时，必须小心。每一个端口提供一种特定的服务，只有给出正确的端口，才能获得相应的服务。0~1023的端口号为系统所保留，例如 http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 所以我们在选择端口号时，最好选择一个大于1023的数以防止发生冲突。 <br /><br />　　在创建socket时如果发生错误，将产生IOException，在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。 <br /><br />　　8.3.4 客户端的Socket <br /><br />　　下面是一个典型的创建客户端Socket的过程。 <br />　　　try{ <br />　　　　　Socket socket=new Socket("127.0.0.1",4700); <br />　　　　　//127.0.0.1是TCP/IP协议中默认的本机地址 <br />　　　}catch(IOException e){ <br />　　　　　System.out.println("Error:"+e); <br />　　　} <br /><br />　　这是最简单的在客户端创建一个Socket的一个小程序段，也是使用Socket进行网络通讯的第一步，程序相当简单，在这里不作过多解释了。在后面的程序中会用到该小程序段。 <br /><br /><br />　　8.3.5 <a href="http://www.it.com.cn/server/"><u><font color="#0000ff">服务器</font></u></a>端的ServerSocket <br /><br />　　下面是一个典型的创建Server端ServerSocket的过程。 <br />　　ServerSocket server=null; <br />　　try { <br />　　　　　server=new ServerSocket(4700); <br />　　　　　//创建一个ServerSocket在端口4700监听客户请求 <br />　　}catch(IOException e){ <br />　　　　　System.out.println("can not listen to :"+e); <br />　　} <br />　　Socket socket=null; <br />　　try { <br />　　　　socket=server.accept(); <br />　　　　//accept()是一个阻塞的方法，一旦有客户请求，它就会返回一个Socket对象用于同客户进行交互 <br />　　}catch(IOException e){ <br />　　　　System.out.println("Error:"+e); <br />　　} <br /><br />　　以上的程序是Server的典型工作模式，只不过在这里Server只能接收一个请求，接受完后Server就退出了。实际的应用中总是让它不停的循环接收，一旦有客户请求，Server总是会创建一个服务线程来服务新来的客户，而自己继续监听。程序中accept()是一个阻塞函数，所谓阻塞性方法就是说该方法被调用后，将等待客户的请求，直到有一个客户启动并请求连接到相同的端口，然后accept()返回一个对应于客户的socket。这时，客户方和服务方都建立了用于通信的socket，接下来就是由各个socket分别打开各自的输入/输出流。 <br /><br />　　8.3.6 打开输入/出流 <br /><br />　　类Socket提供了方法getInputStream ()和getOutStream()来得到对应的输入/输出流以进行读/写操作，这两个方法分别返回InputStream和OutputSteam类对象。为了便于读/写数据，我们可以在返回的输入/输出流对象上建立过滤流，如DataInputStream、DataOutputStream或 PrintStream类对象，对于文本方式流对象，可以采用InputStreamReader和OutputStreamWriter、 PrintWirter等处理。 <br /><br />　　例如： <br />　　PrintStream os=new PrintStream(new BufferedOutputStreem(socket.getOutputStream())); <br />　　DataInputStream is=new DataInputStream(socket.getInputStream()); <br />　　PrintWriter out=new PrintWriter(socket.getOutStream(),true); <br />　　BufferedReader in=new ButfferedReader(new InputSteramReader(Socket.getInputStream())); <br /><br />　　输入输出流是网络编程的实质性部分，具体如何构造所需要的过滤流，要根据需要而定，能否运用自如主要看读者对Java中输入输出部分掌握如何。 <br /><br />　　8.3.7 关闭Socket <br /><br />　　每一个Socket存在时，都将占用一定的资源，在Socket对象使用完毕时，要其关闭。关闭Socket可以调用Socket的Close（）方法。在关闭Socket之前，应将与Socket相关的所有的输入/输出流全部关闭，以释放所有的资源。而且要注意关闭的顺序，与Socket相关的所有的输入/输出该首先关闭，然后再关闭Socket。 <br />　　os.close(); <br />　　is.close(); <br />　　socket.close(); <br /><br />　　尽管Java有自动回收机制，网络资源最终是会被释放的。但是为了有效的利用资源，建议读者按照合理的顺序主动释放资源。 <br /><br />　　8.3.8 简单的Client/Server程序设计 <br /><br />　　下面我们给出一个用Socket实现的客户和服务器交互的典型的C/S结构的演示程序，读者通过仔细阅读该程序，会对前面所讨论的各个概念有更深刻的认识。程序的意义请参考注释。 <br /><br />　　1. 客户端程序 <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　public class TalkClient { <br />　　　　public static void main(String args[]) { <br />　　　　　　try{ <br />　　　　　　　　Socket socket=new Socket("127.0.0.1",4700); <br />　　　　　　　　//向本机的4700端口发出客户请求 <br />　　　　　　　　BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); <br />　　　　　　　　//由系统标准输入设备构造BufferedReader对象 <br />　　　　　　　　PrintWriter os=new PrintWriter(socket.getOutputStream()); <br />　　　　　　　　//由Socket对象得到输出流，并构造PrintWriter对象 <br />　　　　　　　　BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); <br />　　　　　　　　//由Socket对象得到输入流，并构造相应的BufferedReader对象 <br />　　　　　　　　String readline; <br />　　　　　　　　readline=sin.readLine(); //从系统标准输入读入一字符串 <br />　　　　　　　　while(!readline.equals("bye")){ <br />　　　　　　　　//若从标准输入读入的字符串为 "bye"则停止循环 <br />　　　　　　　　　　os.println(readline); <br />　　　　　　　　　　//将从系统标准输入读入的字符串输出到Server <br />　　　　　　　　　　os.flush(); <br />　　　　　　　　　　//刷新输出流，使Server马上收到该字符串 <br />　　　　　　　　　　System.out.println("Client:"+readline); <br />　　　　　　　　　　//在系统标准输出上打印读入的字符串 <br />　　　　　　　　　　System.out.println("Server:"+is.readLine()); <br />　　　　　　　　　　//从Server读入一字符串，并打印到标准输出上 <br />　　　　　　　　　　readline=sin.readLine(); //从系统标准输入读入一字符串 <br />　　　　　　　　} //继续循环 <br />　　　　　　　　os.close(); //关闭Socket输出流 <br />　　　　　　　　is.close(); //关闭Socket输入流 <br />　　　　　　　　socket.close(); //关闭Socket <br />　　　　　　}catch(Exception e) { <br />　　　　　　　　System.out.println("Error"+e); //出错，则打印出错信息 <br />　　　　　　} <br />　　} <br />　　} 2. 服务器端程序 <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　import java.applet.Applet; <br />　　public class TalkServer{ <br />　　　　public static void main(String args[]) { <br />　　　　　　try{ <br />　　　　　　　　ServerSocket server=null; <br />　　　　　　　　try{ <br />　　　　　　　　　　server=new ServerSocket(4700); <br />　　　　　　　　//创建一个ServerSocket在端口4700监听客户请求 <br />　　　　　　　　}catch(Exception e) { <br />　　　　　　　　　　System.out.println("can not listen to:"+e); <br />　　　　　　　　//出错，打印出错信息 <br />　　　　　　　　} <br /><br />　　　　　　　　Socket socket=null; <br />　　　　　　　　try{ <br />　　　　　　　　　　socket=server.accept(); <br />　　　　　　　　　　//使用accept()阻塞等待客户请求，有客户 <br />　　　　　　　　　　//请求到来则产生一个Socket对象，并继续执行 <br />　　　　　　　　}catch(Exception e) { <br />　　　　　　　　　　System.out.println("Error."+e); <br />　　　　　　　　　　//出错，打印出错信息 <br />　　　　　　　　} <br />　　　　　　　　String line; <br />　　　　　　　　BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); <br />　　　　　　　　　//由Socket对象得到输入流，并构造相应的BufferedReader对象 <br />　　　　　　　　PrintWriter os=newPrintWriter(socket.getOutputStream()); <br />　　　　　　　　　//由Socket对象得到输出流，并构造PrintWriter对象 <br />　　　　　　　　BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); <br />　　　　　　　　　//由系统标准输入设备构造BufferedReader对象 <br /><br />　　　　　　　　System.out.println("Client:"+is.readLine()); <br />　　　　　　　　//在标准输出上打印从客户端读入的字符串 <br />　　　　　　　　line=sin.readLine(); <br />　　　　　　　　//从标准输入读入一字符串 <br />　　　　　　　　while(!line.equals("bye")){ <br />　　　　　　　　//如果该字符串为 "bye"，则停止循环 <br />　　　　　　　　　　os.println(line); <br />　　　　　　　　　　//向客户端输出该字符串 <br />　　　　　　　　　　os.flush(); <br />　　　　　　　　　　//刷新输出流，使Client马上收到该字符串 <br />　　　　　　　　　　System.out.println("Server:"+line); <br />　　　　　　　　　　//在系统标准输出上打印读入的字符串 <br />　　　　　　　　　　System.out.println("Client:"+is.readLine()); <br />　　　　　　　　　　//从Client读入一字符串，并打印到标准输出上 <br />　　　　　　　　　　line=sin.readLine(); <br />　　　　　　　　　　//从系统标准输入读入一字符串 <br />　　　　　　　　} 　//继续循环 <br />　　　　　　　　os.close(); //关闭Socket输出流 <br />　　　　　　　　is.close(); //关闭Socket输入流 <br />　　　　　　　　socket.close(); //关闭Socket <br />　　　　　　　　server.close(); //关闭ServerSocket <br />　　　　　　}catch(Exception e){ <br />　　　　　　　　System.out.println("Error:"+e); <br />　　　　　　　　//出错，打印出错信息 <br />　　　　　　} <br />　　　　} <br />　　} <br /><br />　　从上面的两个程序中我们可以看到，socket四个步骤的使用过程。读者可以分别将Socket使用的四个步骤的对应程序段选择出来，这样便于读者对socket的使用有进一步的了解。 <br /><br />　　读者可以在单机上试验该程序，最好是能在真正的网络环境下试验该程序，这样更容易分辨输出的内容和客户机，服务器的对应关系。同时也可以修改该程序，提供更为强大的功能，或更加满足读者的意图。 <br /><br />　　 <br /><br />　　8.3.9 支持多客户的client/server程序设计 <br /><br />　　前面提供的Client/Server程序只能实现Server和一个客户的对话。在实际应用中，往往是在服务器上运行一个永久的程序，它可以接收来自其他多个客户端的请求，提供相应的服务。为了实现在服务器方给多个客户提供服务的功能，需要对上面的程序进行改造，利用多线程实现多客户机制。服务器总是在指定的端口上监听是否有客户请求，一旦监听到客户请求，服务器就会启动一个专门的服务线程来响应该客户的请求，而服务器本身在启动完线程之后马上又进入监听状态，等待下一个客户的到来。 <br /><br />　　客户端的程序和上面程序是完全一样的，读者如果仔细阅读过上面的程序，可以跳过不读，把主要精力集中在Server端的程序上。 <br /><br />　　2. 服务器端程序: MultiTalkServer.java <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　import ServerThread; <br />　　public class MultiTalkServer{ <br />　　　static int clientnum=0; //静态成员变量，记录当前客户的个数 <br />　　　public static void main(String args[]) throws IOException { <br />　　　　ServerSocket serverSocket=null; <br />　　　　boolean listening=true; <br />　　　　try{ <br />　　　　　　serverSocket=new ServerSocket(4700); <br />　　　　　　//创建一个ServerSocket在端口4700监听客户请求 <br />　　　　}catch(IOException e) { <br />　　　　　　System.out.println("Could not listen on port:4700."); <br />　　　　　　//出错，打印出错信息 <br />　　　　　　System.exit(-1); //退出 <br />　　　　} <br />　　　　while(listening){ //永远循环监听 <br />　　　　　　new ServerThread(serverSocket.accept(),clientnum).start(); <br />　　　　　　//监听到客户请求，根据得到的Socket对象和 <br />　　　　　　　客户计数创建服务线程，并启动之 <br />　　　　　　clientnum++; //增加客户计数 <br />　　　　} <br />　　　　serverSocket.close(); //关闭ServerSocket <br />　　} <br />　　} <br /><br />　　3. 程序ServerThread.java <br /><br />　　import java.io.*; <br />　　import java.net.*; <br />　　public class ServerThread extends Thread{ <br />　　　Socket socket=null; //保存与本线程相关的Socket对象 <br />　　　int clientnum; //保存本进程的客户计数 <br />　　　public ServerThread(Socket socket,int num) { //构造函数 <br />　　　　this.socket=socket; //初始化socket变量 <br />　　　　clientnum=num+1; //初始化clientnum变量 <br />　　　} <br />　　　public void run() { //线程主体 <br />　　　　try{ <br />　　　　　　String line; <br />　　　　　　BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); <br />　　//由Socket对象得到输入流，并构造相应的BufferedReader对象 <br />　　　　　　PrintWriter os=newPrintWriter(socket.getOutputStream()); <br />　　　　　　//由Socket对象得到输出流，并构造PrintWriter对象 <br />　　　　　　BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); <br />　　　　　　//由系统标准输入设备构造BufferedReader对象 <br />　　　　　　System.out.println("Client:"+ clientnum +is.readLine()); <br />　　　　　　//在标准输出上打印从客户端读入的字符串 <br />　　　　　　line=sin.readLine(); <br />　　　　　　//从标准输入读入一字符串 <br />　　　　　　while(!line.equals("bye")){ <br />　　　　　　//如果该字符串为 "bye"，则停止循环 <br />　　　　　　　　os.println(line); <br />　　　　　　　　//向客户端输出该字符串 <br />　　　　　　　　os.flush(); <br />　　　　　　　　//刷新输出流，使Client马上收到该字符串 <br />　　　　　　　　System.out.println("Server:"+line); <br />　　　　　　　　//在系统标准输出上打印该字符串 <br />　　　　　　　　System.out.println("Client:"+ clientnum +is.readLine()); <br />　　　　　　　　//从Client读入一字符串，并打印到标准输出上 <br />　　　　　　　　line=sin.readLine(); <br />　　　　　　　　//从系统标准输入读入一字符串 <br />　　　　　　} //继续循环 <br />　　　　　　os.close(); //关闭Socket输出流 <br />　　　　　　is.close(); //关闭Socket输入流 <br />　　　　　　socket.close(); //关闭Socket <br />　　　　　　server.close(); //关闭ServerSocket <br />　　　　　}catch(Exception e){ <br />　　　　　　System.out.println("Error:"+e); <br />　　　　　　//出错，打印出错信息 <br />　　　　　} <br />　　　} <br />　　} <br /><br />　　通过以上的学习，读者应该对Java的面向流的网络编程有了一个比较全面的认识，这些都是基于TCP的应用，后面我们将介绍基于UDP的Socket编程</span>
<img src ="http://www.blogjava.net/yanzhou/aggbug/79180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yanzhou/" target="_blank">周游世界</a> 2006-11-05 11:42 <a href="http://www.blogjava.net/yanzhou/archive/2006/11/05/79180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PPP介绍</title><link>http://www.blogjava.net/yanzhou/archive/2006/10/12/PPP?????.html</link><dc:creator>周游世界</dc:creator><author>周游世界</author><pubDate>Thu, 12 Oct 2006 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/yanzhou/archive/2006/10/12/PPP?????.html</guid><wfw:comment>http://www.blogjava.net/yanzhou/comments/74780.html</wfw:comment><comments>http://www.blogjava.net/yanzhou/archive/2006/10/12/PPP?????.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yanzhou/comments/commentRss/74780.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yanzhou/services/trackbacks/74780.html</trackback:ping><description><![CDATA[
		<b>一、介绍</b>
		<br />
		<br />
 PPP（Point-to-Point
Protocol点到点协议）是为在同等单元之间传输数据包这样的简单链路设计的链路层协议。这种链路提供全双工操作，并按照顺序传递数据包。设计目的主
要是用来通过拨号或专线方式建立点对点连接发送数据，使其成为各种主机、网桥和路由器之间简单连接的一种共通的解决方案。
<br /><br /><b>  二、PPP链路建立过程
</b><br /><br />

PPP协议中提供了一整套方案来解决链路建立、维护、拆除、上层协议协商、认证等问题。PPP协议包含这样几个部分：<br /><br />
    链路控制协议LCP（Link
Control Protocol）<br />
    网络控制协议NCP（Network Control
Protocol）<br />
    认证协议<br />
    <br />LCP负责创建，维护或终止一次物理连接。NCP是一族协议，负责解决物理连接上运行什么网络协议，以及解决上层网络协议发生的问题。
最常用的认证协议包括口令验证协议PAP（Password Authentication
Protocol）和挑战握手验证协议CHAP（Challenge-Handshake Authentication Protocol）。<br /><br />
  下面介绍PPP链路建立的过程：
<br /><br />
  PPP链路状态机如图1所示。 <br /><div align="center"><img src="http://www.net130.com/Fsmanage/RoUpimages/20041091593.gif" /><br /><div align="left">一个典型的链路建立过程分为三个阶段：创建阶段、认证阶段和网络协商阶段。<br /></div></div><br /><b>
  阶段1</b>：创建PPP链路
<br /><br />
 LCP负责创建链路。在这个阶段，将对基本的通讯方式进行选择。链路两端设备通过LCP向对方发送配置信息报文（Configure
Packets）。一旦一个配置成功信息包（Configure-Ack packet）被发送且被接收，就完成了交换，进入了LCP开启状态。
<br /><br />
  应当注意，在链路创建阶段，只是对验证协议进行选择，用户验证将在第2阶段实现。
<br /><br /><b>
  阶段2</b>：用户验证
<br /><br />
  在这个阶段，客户端会将自己的身份发送给远端的接入服务器。该阶段使用一种安全验证方式避免第三方窃取数据或冒充远程客户接管与客户端的连接。在认证完成之前，禁止从认证阶段前进到网络层协议阶段。如果认证失败，认证者应该跃迁到链路终止阶段。
<br /><br />
  在这一阶段里，只有链路控制协议、认证协议，和链路质量监视协议的packets是被允许的。在该阶段里接收到的其他的packets必须被静静的丢弃。
<br /><br />
  最常用的认证协议有口令验证协议（PAP）和挑战握手验证协议（CHAP）。 认证方式介绍在第三部分中介绍。 
<br /><b><br />

  阶段3</b>：调用网络层协议
<br /><br />
  认证阶段完成之后，PPP将调用在链路创建阶段（阶段1）选定的各种网络控制协议（NCP）。选定的NCP解决PPP链路之上的高层协议问题，例如，在该阶段IP控制协议（IPCP）可以向拨入用户分配动态地址。
<br /><br />
  这样，经过三个阶段以后，一条完整的PPP链路就建立起来了。
<br /><br /><b>
  三、 认证方式</b><br /><br />
  1）口令验证协议（PAP） 
<br /><br />
 PAP是一种简单的明文验证方式。NAS（网络接入服务器，Network Access
Server）要求用户提供用户名和口令，PAP以明文方式返回用户信息。很明显，这种验证方式的安全性较差，第三方可以很容易的获取被传送的用户名和口
令，并利用这些信息与NAS建立连接获取NAS提供的所有资源。所以，一旦用户密码被第三方窃取，PAP无法提供避免受到第三方攻击的保障措施。
<br /><br />
  2）挑战-握手验证协议（CHAP） 
<br /><br />

CHAP是一种加密的验证方式，能够避免建立连接时传送用户的真实密码。NAS向远程用户发送一个挑战口令（challenge），其中包括会话ID和一
个任意生成的挑战字串（arbitrary challengestring）。远程客户必须使用MD5单向哈希算法（one-way hashing
algorithm）返回用户名和加密的挑战口令，会话ID以及用户口令，其中用户名以非哈希方式发送。
<br /><br />

CHAP对PAP进行了改进，不再直接通过链路发送明文口令，而是使用挑战口令以哈希算法对口令进行加密。因为服务器端存有客户的明文口令，所以服务器可
以重复客户端进行的操作，并将结果与用户返回的口令进行对照。CHAP为每一次验证任意生成一个挑战字串来防止受到再现攻击（replay
attack）。在整个连接过程中，CHAP将不定时的向客户端重复发送挑战口令，从而避免第3方冒充远程客户（remote client
impersonation）进行攻击。
<br /><br /><b>
  四、PPP协议的应用
</b><br /><br />
  PPP协议是目前广域网上应用最广泛的协议之一，它的优点在于简单、具备用户验证能力、可以解决IP分配等。 
<br /><br />
 家庭拨号上网就是通过PPP在用户端和运营商的接入服务器之间建立通信链路。
目前，宽带接入正在成为取代拨号上网的趋势，在宽带接入技术日新月异的今天，PPP也衍生出新的应用。典型的应用是在ADSL（非对称数据用户环线，
Asymmetrical Digital Subscriber
Loop）接入方式当中，PPP与其他的协议共同派生出了符合宽带接入要求的新的协议，如PPPoE（PPP over
Ethernet），PPPoA（PPP over ATM）。 <br /><br />
  利用以太网（Ethernet）资源，在以太网上运行PPP来进行用户认证接入的方式称为PPPoE。PPPoE即保护了用户方的以太网资源，又完成了ADSL的接入要求，是目前ADSL接入方式中应用最广泛的技术标准。 
<br /><br />
 同样，在ATM（异步传输模式，Asynchronous Transfer
Mode）网络上运行PPP协议来管理用户认证的方式称为PPPoA。它与PPPoE的原理相同，作用相同；不同的是它是在ATM网络上，而PPPoE是
在以太网网络上运行，所以要分别适应ATM标准和以太网标准。 <br /><br />
  PPP协议的简单完整使它得到了广泛的应用，相信在未来的网络技术发展中，它还可以发挥更大的作用。<img src ="http://www.blogjava.net/yanzhou/aggbug/74780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yanzhou/" target="_blank">周游世界</a> 2006-10-12 14:16 <a href="http://www.blogjava.net/yanzhou/archive/2006/10/12/PPP?????.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>