Java中的InetAddress是一个代表IP地址的对象。IP地址可以由字节数组和字符串来分别表示,InetAddress将IP地址以对象的形式进行封装,可以更方便的操作和获取其属性。InetAddress没有构造方法,可以通过两个静态方法获得它的对象。代码如下:
//根据主机名来获取对应的InetAddress实例 InetAddress ip = InetAddress.getByName("www.itcast.cn"); //判断是否可达 System.out.println("oneedu是否可达:" + ip.isReachable(2000)); //获取该InetAddress实例的IP字符串 System.out.println(ip.getHostAddress()); //根据原始IP地址(字节数组形式)来获取对应的InetAddress实例 InetAddress local = InetAddress.getByAddress(new byte[] {127,0,0,1}); System.out.println("本机是否可达:" + local.isReachable(5000)); //获取该InetAddress实例对应的全限定域名 System.out.println(local.getCanonicalHostName());
这两个类可以别用于将application/x-www-form-urlencoded MIME类型的字符串转换为普通字符串,将普通字符串转换为这类特殊型的字符串。使用URLDecoder类的静态方法decode()用于解码,URLEncoder类的静态方法encode()用于编码。具体使用方法如下。
//将application/x-www-form-urlencoded字符串 //转换成普通字符串 String keyWord = URLDecoder.decode( "%E6%9D%8E%E5%88%9A+j2ee", "UTF-8"); System.out.println(keyWord); //将普通字符串转换成 //application/x-www-form-urlencoded字符串 String urlStr = URLEncoder.encode( "张孝祥" , "GBK"); System.out.println(urlStr);
URL可以被认为是指向互联网资源的“指针”,通过URL可以获得互联网资源相关信息,包括获得URL的 InputStream对象获取资源的信息,以及一个到URL所引用远程对象的连接URLConnection。
URLConnection对象可以向所代表的URL发送请求和读取URL的资源。通常,创建一个和URL的连接,需要如下几个步骤:
a. 创建URL对象,并通过调用openConnection方法获得URLConnection对象;
b. 设置URLConnection参数和普通请求属性;
c. 向远程资源发送请求;
d. 远程资源变为可用,程序可以访问远程资源的头字段和通过输入流来读取远程资源返回的信息。
这里需要重点讨论一下第三步:如果只是发送GET方式请求,使用connect方法建立和远程资源的连接即可;如果是需要发送POST方式的请求,则需要获取URLConnection对象所对应的输出流来发送请求。这里需要注意的是,由于GET方法的参数传递方式是将参数显式追加在地址后面,那么在构造URL对象时的参数就应当是包含了参数的完整URL地址,而在获得了URLConnection对象之后,就直接调用connect方法即可发送请求。
而POST方法传递参数时仅仅需要页面URL,而参数通过需要通过输出流来传递。另外还需要设置头字段。以下是两种方式的代码。
//1. 向指定URL发送GET方法的请求 String urlName = url + "?" + param; URL realUrl = new URL(urlName); //打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); //设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); //建立实际的连接 conn.connect(); //2. 向指定URL发送POST方法的请求 URL realUrl = new URL(url); //打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); //设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); //发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); //获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); //发送请求参数 out.print(param);
TCP协议是一种可靠的通络协议,通信两端的Socket使得它们之间形成网络虚拟链路,两端的程序可以通过虚拟链路进行通讯。Java使用socket对象代表两端的通信端口,并通过socket产生的IO流来进行网络通信。TCP协议帧如图:
TCP协议三次握手建立连接和终止连接:
在两个通信端没有建立虚拟链路之前,必须有一个通信实体首先主动监听来自另一端的请求。ServerSocket对象使用accept()方法用于监听来自客户端的Socket连接,如果收到一个客户端Socket的连接请求,该方法将返回一个与客户端Socket对应的Socket对象。如果没有连接,它将一直处于等待状态。通常情况下,服务器不应只接受一个客户端请求,而应该通过循环调用accept()不断接受来自客户端的所有请求。
这里需要注意的是,对于多次接收客户端数据的情况来说,一方面可以每次都在客户端建立一个新的Socket对象然后通过输入输出通讯,这样对于服务器端来说,每次循环所接收的内容也不一样,被认为是不同的客户端。另外,也可以只建立一次,然后在这个虚拟链路上通信,这样在服务器端一次循环的内容就是通信的全过程。
服务器端代码:
package com.itcast.tcp; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { ServerSocket server=null; Socket client=null; boolean running=true; try { server=new ServerSocket(10003); while(running){ client=server.accept(); new Thread(new ServerAction(client)).start(); } } catch (IOException e) { e.printStackTrace(); } } }
使用Socket可以主动连接到服务器端,使用服务器的IP地址和端口号初始化之后,服务器端的accept便可以解除阻塞继续向下执行,这样就建立了一对互相连接的Socket。
客户端代码:
package com.itcast.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; public class ServerAction implements Runnable{ private Socket s; public ServerAction(Socket s){ this.s=s; } @Override public void run() { InputStream is=null; OutputStream os=null; BufferedReader br=null; PrintWriter pw=null; try { is=s.getInputStream(); os=s.getOutputStream(); br=new BufferedReader(new InputStreamReader(is)); pw=new PrintWriter(os); } catch (IOException e) { e.printStackTrace(); } try { String line = null; String answer = null; line = br.readLine(); if (line.equalsIgnoreCase("quit")) { } answer = (new StringBuffer(line).reverse()).toString(); System.out.println(line + "-->" + answer); pw.println(line + "-->" + answer); } catch (IOException e) { e.printStackTrace(); } finally { } } }
测试结果:
UDP(User Datagram Protocol),中文意思是用户数据报协议,方式类似于发短信息,是一种物美价廉的通讯方式,使用该种方式无需建立专用的虚拟连接,由于无需建立专用的连接,所以对于服务器的压力要比TCP小很多,所以也是一种常见的网络编程方式。但是使用该种方式最大的不足是传输不可靠,当然也不是说经常丢失,就像大家发短信息一样,理论上存在收不到的可能,这种可能性可能是1%,反正比较小,但是由于这种可能的存在,所以平时我们都觉得重要的事情还是打个电话吧(类似TCP方式),一般的事情才发短信息(类似UDP方式)。网络编程中也是这样,必须要求可靠传输的信息一般使用TCP方式实现,一般的数据才使用UDP方式实现。
DatagramSocket类实现“网络连接”,包括客户端网络连接和服务器端网络连接。虽然UDP方式的网络通讯不需要建立专用的网络连接,但是毕竟还是需要发送和接收数据,DatagramSocket实现的就是发送数据时的发射器,以及接收数据时的监听器的角色。类比于TCP中的网络连接,该类既可以用于实现客户端连接,也可以用于实现服务器端连接。
DatagramPacket类实现对于网络中传输的数据封装,也就是说,该类的对象代表网络中交换的数据。在UDP方式的网络编程中,无论是需要发送的数据还是需要接收的数据,都必须被处理成DatagramPacket类型的对象,该对象中包含发送到的地址、发送到的端口号以及发送的内容等。其实DatagramPacket类的作用类似于现实中的信件,在信件中包含信件发送到的地址以及接收人,还有发送的内容等,邮局只需要按照地址传递即可。在接收数据时,接收到的数据也必须被处理成DatagramPacket类型的对象,在该对象中包含发送方的地址、端口号等信息,也包含数据的内容。和TCP方式的网络传输相比,IO编程在UDP方式的网络编程中变得不是必须的内容,结构也要比TCP方式的网络编程简单一些。
代码示例:
Server端:
package com.itcast.udp; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class DatagramSocketServer { public static void main(String[] args) { DatagramSocket ds = null; // 连接对象 DatagramPacket sendDp; // 发送数据包对象 DatagramPacket receiveDp; // 接收数据包对象 final int PORT = 10010; // 端口 try { // 建立连接,监听端口 ds = new DatagramSocket(PORT); System.out.println("服务器端已启动:"); // 初始化接收数据 byte[] b = new byte[1024]; receiveDp = new DatagramPacket(b, b.length); // 接收 ds.receive(receiveDp); // 读取反馈内容,并输出 InetAddress clientIP = receiveDp.getAddress(); int clientPort = receiveDp.getPort(); byte[] data = receiveDp.getData(); int len = receiveDp.getLength(); System.out.println("客户端IP:" + clientIP.getHostAddress()); System.out.println("客户端端口:" + clientPort); System.out.println("客户端发送内容:" + new String(data, 0, len)); // 发送反馈 String response = "OK"; byte[] bData = response.getBytes(); sendDp = new DatagramPacket(bData, bData.length, clientIP, clientPort); // 发送 ds.send(sendDp); } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭连接 ds.close(); } catch (Exception e) { } } } }
Client端:
package com.itcast.udp; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Date; public class DatagramSocketClient { public static void main(String[] args) { DatagramSocket ds = null; // 连接对象 DatagramPacket sendDp; // 发送数据包对象 DatagramPacket receiveDp; // 接收数据包对象 String serverHost = "127.0.0.1"; // 服务器IP int serverPort = 10010; // 服务器端口号 try { // 建立连接 ds = new DatagramSocket(); // 初始化发送数据 Date d = new Date(); // 当前时间 String content = d.toString(); // 转换为字符串 byte[] data = content.getBytes(); // 初始化发送包对象 InetAddress address = InetAddress.getByName(serverHost); sendDp = new DatagramPacket(data, data.length, address, serverPort); // 发送 ds.send(sendDp); // 初始化接收数据 byte[] b = new byte[1024]; receiveDp = new DatagramPacket(b, b.length); // 接收 ds.receive(receiveDp); // 读取反馈内容,并输出 byte[] response = receiveDp.getData(); int len = receiveDp.getLength(); String s = new String(response, 0, len); System.out.println("服务器端反馈为:" + s); } catch (Exception e) { e.printStackTrace(); } finally { try { // 关闭连接 ds.close(); } catch (Exception e) { } } } }
测试结果:
PS:有关于Java网络编程.与以后学习的J2EE是息息相关的.是建立在这基础之上的.