第九章
网络编程
本章目录
9.1 IP地址与网络指针
9.2 Internet通信
9.1 IP地址与网络指针
一、InetAddress类
InetAddress类是获取和处理网络地址信息的类,表示互联网协议地址即IP地址。有两个子类:Inet4Address类
表示互联网协议第4版地址,Inet6Address类表示互联网协议第6版地址。
实际工作中经常利用InetAddress类及其方法成员进行IP地址和域名的信息处理以获取网络信息。
InetAddress类中的以下几个方法成员适合于初始化InetAddress类对象实例:
getByName(String host) //在给定主机名的情况下确定主机的IP地址
getAllByName(String host) //在给定主机名的情况下,根据系统上配置的名称服务返回其所有IP地址
getLocalHost() //返回本地主机
getByAddress(byte[] addr) //给定原始IP地址返回InetAddress
getByAddress(String host, byte[] addr)
//给定主机名和IP地址创建 InetAddress
另外该类中的以下几个方法成员经常被用来处理对象实例从而获得相关的网络信息:
getAddress() //返回此InetAddress对象的原始IP地址
getCanonicalHostName() //获取此IP地址的完全限定域名
getHostName() //获取此IP地址的主机名
//Example 9 of Chapter 9
import java.io.*;
import java.net.*;
public class NetIpAddressDatagramClientDemo
{
private static DatagramSocket socket;
public static void main( String args[] )
{
try{
socket = new DatagramSocket();
}
catch( SocketException socketException )
{
socketException.printStackTrace();
System.exit( 1 );
}
try{
byte data[] = new byte[ 100 ];
DatagramPacket sendPacket = new DatagramPacket( data,
data.length, InetAddress.getLocalHost(), 1000 );
socket.send( sendPacket );
}
catch ( IOException ioException )
{
ioException.printStackTrace();
}
while ( true )
{
try{
byte data[] = new byte[ 100 ];
DatagramPacket receivePacket = new DatagramPacket( data, data.length );
socket.receive( receivePacket );
}
catch( IOException ioException )
{
ioException.printStackTrace();
}
}
}
}
//Example 8 of Chapter 9
import java.io.*;
import java.net.*;
public class NetIpAddressDatagramServerDemo
{
private static DatagramSocket socket;
public static void main( String args[] )
{
try {
socket = new DatagramSocket( 1000 );
}
catch( SocketException socketException )
{
socketException.printStackTrace();
System.exit( 1 );
}
while ( true )
{
try{
byte data[] = new byte[ 100 ];
DatagramPacket rp = new DatagramPacket( data, data.length );
socket.receive( rp );
DatagramPacket sendPacket = new DatagramPacket(
rp.getData(), rp.getLength(), rp.getAddress(), rp.getPort() );
socket.send( sendPacket );
}
catch( IOException ioException )
{
ioException.printStackTrace();
}
}
}
}
二、URL类
在HTTP协议中,用URI(Uniform Resource Identifier)来标识Internet上的数据,而用于指定文档资料在
Internet上的确切位置的URI称为URL(Uniform Resource Locator)。
java.net包中分别定义了URI类和URL类,用来封装统一资源标识符引用和统一资源定位符引用。使用URL类是定
位和检索网络上数据的最简单的方法,它是指向Internet上面的各种资源的指针。
URL对象实例可以在应用程序中代表一个网络资源,可以供用户访问资源信息。通常,URL可分成几个部分:协
议、主机、端口、文件路径,另外URL后面可能还会有一个由字符“#”指示的“片段”,称为“引用”。
下面的几个方法成员可以分别获取URL的各个部分及主要内容:
getProtocol() //获得此URL的协议名称
getHost() //获得此URL的主机名
getPort() //获得此URL的端口号
getFile() //获得此URL的文件名
getRef() //获得此URL的锚点引用
getQuery() //获得此URL的查询部分
getUserInfo() //获得此URL的 userInfo 部分
getAuthority() //获得此URL的授权部分
getDefaultPort() //获得与此URL关联协议的默认端口号
利用URL检索网络上面的数据时,以下几个方法成员是需要使用的:
openStream()方法用于建立由应用程序到URL指向的资源处的连接并返回一个从该资源处读取数据的输入流,可
以以原始字节流形式读取资源数据。
openConnection()方法返回一个URLConnection对象,它表示到URL所引用的远程对象即网络资源的连接。
getContent()方法可以获得此URL的内容,这个内容是被转换为其它形式的。
9.2 Internet通信
一、Socket通信机制
各种网络的服务器(Server)-客户(Client)应用是十分广泛的。套接字Socket是建立服务器-客户通讯通道
连接的低层机制,是独立于平台的连接。
在Socket通讯机制中,通过Socket的数据是原始字节流信息,通讯双方要约定数据的格式化与解释处理工作。
在网络程序设计中使用Socket通讯机制使得网络上面的输入输出工作就如同文件的输入输出工作一样,大量的
网络编程细节被Socket所隐藏,程序员的工作被大大地简化了。
Java语言在java.net包中定义了Socket类代表双向连接中的一端,该包中同时提供了ServerSocket类便于服务
器操作。Socket是两个程序之间用来进行双向数据传输的网络通讯端点,一般由一个地址加上一个端口号来标
识。
下面的几个方法成员是非常常用的:
getInetAddress() //返回套接字连接的地址
getInputStream() //返回此套接字的输入流
getOutputStream() //返回此套接字的输出流
getPort() //返回此套接字连接到的远程端口
getLocalPort() //返回此套接字绑定到的本地端口
getLocalAddress() //获取套接字绑定的本地地址
close() //关闭此套接字
Socket通讯机制可以完成三项基本功能:扫描网络端口、简单通讯和TCP/IP服务器。
⒈扫描网络端口:
可以使用形如:
InetAddress hostadd=InetAddress.getByName(hostname)
Socket skt = new Socket(hostadd, i)
这样的功能语句实现对名为hostname的主机上的端口i的测试,如果该端口不可用,所引用的Socket类的构造方
法将抛出IOException。
⒉简单通讯:
可以利用Socket与某个特定的主机通过指定的端口建立连接,之后通过输入输出流进行数据传输,数据传输的
基本格式是字节,也可以使用专门的输入输出流类进行字符传输、基本数据类型等操作。
⒊TCP/IP服务器:
可以使用Socket类和ServerSocket类建立一个服务器,实现服务器和客户端双向信息传输。程序代码分为服务
器方和客户方,其基本的操作步骤为:
//Example 1 of Chapter 9
import java.net.*;
public class NetIpAddressDemo1
{
public static void main(String args[])
{
try{
//给定IP地址获取主机名
InetAddress address1 = InetAddress.getByName( "159.226.3.9" );
System.out.println( address1.getHostName() );
System.out.println( address1.getCanonicalHostName() );
//给定域名构造InetAddress
InetAddress address2[] = InetAddress.getAllByName( "www.apple.com" );
for(int i = 0; i < address2.length; i++ )
{
System.out.println( address2[i] );
}
//获取本地机的名称与地址
InetAddress address3 = InetAddress.getLocalHost();
System.out.println( address3 );
System.out.println( address3.getHostName() );
System.out.println( address3.getHostAddress() );
}
catch(UnknownHostException e)
{
System.err.println( e );
}
}
}
//Example 2 of Chapter 9
import java.net.*;
public class NetIpAddressDemo2
{
public static int getLength( InetAddress ia )
{
byte[] address = ia.getAddress();
if( address.length == 4 ) return 4;
else if( address.length == 16 ) return 16;
else return -1;
}
public static char getKind( InetAddress ia )
{
byte[] address = ia.getAddress();
if( address.length != 4 )
{
throw new IllegalArgumentException( "No IPv6 addresses!" );
}
int firstByte = address[ 0 ];
if( ( firstByte & 0x80 ) == 0 ) return 'A';
else if( ( firstByte & 0xC0 ) == 0x80 ) return 'B';
else if( ( firstByte & 0xE0 ) == 0xC0 ) return 'C';
else if( ( firstByte & 0xF0 ) == 0xE0 ) return 'D';
else if( ( firstByte & 0xF8 ) == 0xF0 ) return 'E';
else return 'F';
}
public static void main(String args[])
{
try{
InetAddress ia = InetAddress.getByName( "www.microsoft.com" );
System.out.println( "IP地址长度为:" + getLength( ia ) );
System.out.println( "IP地址种类为:" + getKind( ia ) );
}
catch(UnknownHostException e)
{
System.err.println( e );
}
}
}
//Example 3 of Chapter 9
import java.net.*;
public class NetIpAddressDemo3
{
public static void main( String[] args )
{
try {
URL url = new URL( "http://www.sina.com/index.html" );
System.out.println( "URL: " + url );
System.out.println( "Protocal: " + url.getProtocol() );
System.out.println( "Host: " + url.getHost() );
System.out.println( "Port: " + url.getPort() );
System.out.println( "File: " + url.getFile() );
System.out.println( "REF: " + url.getRef() );
}
catch(MalformedURLException e)
{
System.out.println( e.toString() );
}
}
}
//Example 4 of Chapter 9
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.AppletContext;
import javax.swing.*;
public class NetIpAddressDemo4 extends JApplet implements ActionListener
{
AppletContext browser;
JTextField text;
URL url;
public void init()
{
Container container = getContentPane();
text = new JTextField( 20 );
container.add( text, BorderLayout.CENTER );
text.addActionListener( this );
}
public void actionPerformed( ActionEvent e )
{
try{
url = new URL( text.getText() );
}
catch( MalformedURLException exception )
{
exception.printStackTrace();
}
browser = getAppletContext();
browser.showDocument( url );
}
}
//Example 5 of Chapter 9
import java.net.*;
import java.io.*;
public class NetIpAddressDemo5 extends Thread
{
private static Socket socket;
public static void main( String[] args )
{
String hostname = "localhost";
int port = 65;
String s;
if( args.length > 1 )
{
hostname = args[0];
port = Integer.parseInt( args[1] );
}
try{
InetAddress hostaddress = InetAddress.getByName( hostname );
try{
socket = new Socket( hostaddress, port );
BufferedReader buf = new BufferedReader(
new InputStreamReader( socket.getInputStream( ) ) );
NetIpAddressDemo5 th = new NetIpAddressDemo5( );
th.start( );
while( ( s = buf.readLine( ) ) != null )System.out.println( s );
socket.close( );
}
catch( IOException e )
{
System.out.println( e.toString( ) );
}
}
catch( UnknownHostException e )
{
System.out.println( e.toString( ) );
}
}
public void run( )
{
String userInput;
BufferedReader buf;
PrintStream pstream;
try{
buf = new BufferedReader( new InputStreamReader( System.in ) );
pstream = new PrintStream( socket.getOutputStream( ) );
while( true )
{
if( socket.isClosed( ) ) break;
userInput = buf.readLine( );
pstream.println( userInput );
}
}
catch( IOException e )
{
System.out.println( e.toString( ) );
}
}
}
二、Datagram通讯机制
Socket工作方式是一种连接方式,其特点是通讯稳定可靠,输入输出操作始终在同一对进程之间进行。
数据报Datagram是一种非连接方式,通讯数据经过不确定的路径传向目的地,可靠性和正确性都不能保证,可
能会重复到达目的地,甚至还可能根本到不了目的地。
Java语言通过UDP(User Datagram Protocol)实现Datagram通讯机制。
在java.net包中定义了DatagramPacket和DatagramSocket两个类用来支持数据报通信。
DatagramPacket类表示数据报包,发送方可以用DatagramPacket构造一个数据报,其中包含拟发送的数据和目
的地址及端口;接收方可以用DatagramPacket构造一个数据报用于接收发送方发来的数据报。
DatagramSocket类表示用来发送和接收数据报包的套接字,代表数据报传送的发送和接收点,主要用来读/写称
为报文的数据报中的数据。
发送数据报用该类的send()方法,接收数据报用该类的receive()方法。
创建DatagramSocket类对象实例时如果构造方法不能将DatagramSocket与指定的端口绑定在一起,将抛出
SocketException异常,所以程序代码中要有相应的处理措施。
//Example 6 of Chapter 9
import java.net.*;
import java.io.*;
public class NetIpAddressSocketServerDemo
{
public static void main( String[] args )
{
try{
boolean flag = true;
Socket Socket = null;
String InputLine;
ServerSocket serverSocket = new ServerSocket( 0 );
System.out.println( "服务器等待:" + serverSocket.getLocalPort() );
while( flag )
{
Socket = serverSocket.accept();
DataInputStream is = new DataInputStream(
new BufferedInputStream( Socket.getInputStream() ) );
PrintStream os = new PrintStream(
new BufferedOutputStream( Socket.getOutputStream() ) );
while( ( InputLine = is.readLine( ) )!= null )
{
if( InputLine.equals( "The End" ) )
{
flag = false;
break;
}
os.println( InputLine );
os.flush();
}
os.close();
is.close();
Socket.close();
}
serverSocket.close();
}
catch( IOException e )
{
System.out.println( e.toString( ) );
}
}
}
//Example 7 of Chapter 9
import java.net.*;
import java.io.*;
public class NetIpAddressSocketClientDemo
{
public static void main( String[] args )
{
try{
Socket clientSocket = new Socket( "myhost", 15 );
OutputStream os = clientSocket.getOutputStream();
DataInputStream is = new DataInputStream( clientSocket.getInputStream() );
int a;
String ResponseLine;
while( ( a = System.in.read() )!= -1 )
{
os.write( ( byte ) a );
if( a == '/n' )
{
os.flush();
ResponseLine = is.readLine( );
System.out.println( "客户端:" + ResponseLine );
}
}
os.close();
is.close();
clientSocket.close();
}
catch( IOException e )
{
System.out.println( e.toString( ) );
}
}
}