随笔 -- IO -- Socket/ServerSocket -- 系统概述
Java中提供的专门的网络开发程序包------java.net
Java的网络编程提供的两种通信协议:TCP和UDP
19.1 IP与InetAddress
19.1.1 IP地址简介
19.1.2 InetAddress
InetAddress类主要表示IP地址,这个类有两个子类:Inet4Address、Inet6Address。
InetAddress类的常用方法:
⊙ public static InetAddress getByName(String host)throws UnknownHostException :通过主机名称得到InetAddress对象
⊙ public static InetAddress getLocalHost() throws UnknownHostException : 通过本机得到InetAddress对象
⊙ public String getHostName() : 得到IP地址
⊙ public boolean isReachable(int timeout)throws IOException : 判断地址是否可以到达,同时指定超时时间。
package java_.net_.demo.java_15_5; import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressMain { public static void main(String[] args) throws Exception { InetAddress locAdd = null; InetAddress remAdd = null; locAdd = InetAddress.getLocalHost(); remAdd = InetAddress.getByName("www.baidu.com"); System.out.println("本机名称 :" + locAdd.getHostName()); System.out.println("本机IP地址 :" + locAdd.getHostAddress()); System.out.println("百度IP地址 :" + remAdd); System.out.println("本机是否可达 :" + locAdd.isReachable(5000)); System.out.println("百度是否可达 :" + remAdd.isReachable(5000)); } }
19.2 URL与URLConnection
19.2.1 URL
URL统一资源定位符,可以直接使用此类找到互联网上的资源(如一个简单的网页)。
URL类的常用方法:
⊙ public URL(String spec) throws MalformedURLException : 根据指定的地址实例化URL对象。
⊙ public URL(String protocal,String host,int port,String file) throws MalformedURLException : 实例化URL对象,并指定协议、主机、端口名称、资源文件。
⊙ public URLConnection openConnection() throws IOException : 取得一个URLConnection对象。
⊙ public final InputStream openStream() throws IOException : 取得输入流。
package java_.net_.demo.java_15_5.URL_; import java.io.InputStream; import java.net.URL; import java.util.Scanner; public class URLMain { public static void main(String[] args) throws Exception{ URL url = new URL("http","www.mldnjava.cn",80,"/curriculum.htm"); InputStream input = url.openStream(); Scanner sc = new Scanner(input); sc.useDelimiter(" "); while(sc.hasNext()){ System.out.println(sc.next()); } } }
19.2.2 URLConnection
URLConnection是封装访问远程网络资源一般方法的类,通过它可以建立与远程服务器的连接,检查远程资源的一些属性。
此类的常用方法:
⊙ public int getContentLength() : 取得内容的长度。
⊙ public String getContentType() : 取得内容的类型。
⊙ public InputStream getInputStream() throws IOException : 取得连接的输入流。
URLConnection对象可以通过URL实例的openConnection()方法取得。
package java_.net_.demo.java_15_5.URLConnection; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.Scanner; public class URLConnectionMain { public static void main(String[] args) throws Exception{ URL url = new URL("http://www.mldnjava.cn"); URLConnection urlCon = url.openConnection(); System.out.println("内容大小 :" + urlCon.getContentLength()); System.out.println("内容类型 :" + urlCon.getContentType()); InputStream input = urlCon.getInputStream(); Scanner sc = new Scanner(input); sc.useDelimiter(" "); while (sc.hasNext()) { System.out.println(sc.next()); } } }
19.3 URLEncoder 与 URLDecoder
在Java中如果要完成编码和解码操作就必须使用URLEncoder 和 URLDecoder两个类。
URLEncoder 可以为传递的内容进行编码;URLDecoder可以为传递的内容进行解码。
URLEncoder类常用的方法:
⊙ public static Spring encode(String s,String enc) throws UnsupportedEncodingException : 使用指定的编码机制将字符串转换为application/x-www-form-urlencoded格式。
URLDecoder类的常用方法:
⊙ public static Spring decode(String s,String enc) throws UnsupportedEncodingException : 使用指定的编码机制对application/x-www-form-urlencoded字符串解码。
package java_.net_.demo.java_15_5.URLEncoder; import java.net.URLDecoder; import java.net.URLEncoder; public class URLEncoderMain { public static void main(String[] args) throws Exception{ String keyWord = "lime甲骨文"; String encod = URLEncoder.encode(keyWord, "UTF-8"); System.out.println("编码之后的内容 : " + encod); String decod = URLDecoder.decode(encod, "UTF-8"); System.out.println("解码之后的内容 : " + decod); } }
19.4 TCP程序设计
在Java中使用Socket(即套接字)完成TCP程序的开发,使用此类可以方便地简历可靠的、双向的、持续的、点对点的通信连接。
在Socket的程序开发中,服务器端使用ServerSocket等待客户端连接,对于Java的网络程序来讲,每一个客户端都使用Socket对象表示。
19.4.1 ServerSocket 类与 Socket 类
ServerSocket主要用在服务器端程序的开发上,用于接收客户端的连接请求。
ServerSocket类的常用方法:
⊙ public ServerSocket(int port)throws IOException : 创建ServerSocket实例,并指定监听端口。
⊙ public Socket accept() throws IOException : 等待客户端连接,此方法连接之前一直阻塞。
⊙ public InetAddress getInetAddress() : 返回服务器的IP地址。
⊙ public boolean isClosed() : 返回ServerSocket的关闭状态。
⊙ public void close() throws IOException : 关闭ServerSocket。
在服务器端每次运行时都要使用accept()方法等待客户端连接,此方法执行之后服务器端将进入阻塞状态,知道客户端连接之后程序可以向下继续执行。此方法返回值类型是Socket,每一个Socket都表示一个客户端对象。
Socket类的常用方法:
⊙ public Socket(String host,int port) throws UnknownHostException,IOException : 构造Socket对象,同时指定要连接服务器的主机名称及连接端口。
⊙ public InputStream getInputStream() throws IOException : 返回此套接字的输入流。
⊙ public OutputStream getOutputStream() throws IOException : 返回此套接字的输入流。
⊙ public void close() throws IOException : 关闭此Socket。
⊙ public boolean isClosed() : 判断此套接字是否被关闭。
在客户端,程序可以通过Socket类的getInputStream()方法取得服务器的输入信息,在服务器端可以通过getOutputStream()方法取得客户端的输出信息。
19.4.2 第一个TCP程序
Class : ServerSocketMain
package java_.net_.demo.java_15_5.serverSocket; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; public class ServerSocketMain { public static void main(String[] args) throws Exception{ ServerSocket server = new ServerSocket(8888); Socket client = null; PrintStream out = null; int count = 1; while(true){ System.out.println("等待第 " + count + " 个客户端接入"); client = server.accept(); System.out.println("第 " + count + " 个客户端已接入"); count++; String resp = "Now is : " + new Date(); out = new PrintStream(client.getOutputStream()); out.println(resp); } } }
Class : SocketMain
package java_.net_.demo.java_15_5.socket; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.Socket; public class SocketMain { public static void main(String[] args) throws Exception{ Socket client = new Socket("localhost",8888); BufferedReader buf = null; buf = new BufferedReader(new InputStreamReader(client.getInputStream())); String str = buf.readLine(); System.out.println("服务器端输出内容 :" + str); client.close(); buf.close(); } }
19.4.3 案例:Echo程序(BIO)
Echo程序是一个网络编程通信交互的一个经典案例,称为回应程序,即客户端输入那些内容,服务器端会在这些内容前加上“ECHO:”并将信息发回客户端。
本程序中将通过循环的方式使用accept(),这样,每一个客户端执行完毕后,服务器端都可以重新等待用户连接。
Class : EchoServer
package limeNet.server; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class EchoServer { public static void main(String[] args) throws Exception { ServerSocket server = null; Socket client = null; PrintStream out = null; BufferedReader buf = null; server = new ServerSocket(8888); boolean f = true; while(f){ System.out.println("服务器运行,等待客户端连接。"); client = server.accept(); buf = new BufferedReader(new InputStreamReader(client.getInputStream())); out = new PrintStream(client.getOutputStream()); boolean flag = true; while(flag){ String str = buf.readLine(); if(null == str || "".equals(str)){ flag = false; }else{ if("bye".equals(str)){ flag = false; }else{ out.print("ECHO : " + str); } } } out.close(); buf.close(); client.close(); } server.close(); } }
Class : EchoClient
package limeNet.client; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; public class EchoClient { public static void main(String[] args) throws Exception, Exception { Socket client = null; client = new Socket("localhost",8888); BufferedReader input = null; PrintStream out = null; BufferedReader buf = null; input = new BufferedReader(new InputStreamReader(System.in)); out = new PrintStream(client.getOutputStream()); buf = new BufferedReader(new InputStreamReader(client.getInputStream())); boolean flag = true; while(flag){ System.out.print("输入信息:"); String str = input.readLine(); out.print(str); if("bye".equals(str)){ flag = false; }else{ String echo = buf.readLine(); System.out.println(echo); } } client.close(); buf.close(); } }
19.4.4 在服务器上应用多线程
对于服务器端来说,如果要加入多线程机制,则应该在每个用户连接之后启动一个新的线程。
Class : EchoThread
package limeNet.thread.server; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; public class EchoThread implements Runnable { private Socket accept; public EchoThread() { super(); } public EchoThread(Socket accept) { super(); this.accept = accept; } public void run() { DataInputStream in = null; DataOutputStream out = null; try { in = new DataInputStream(accept.getInputStream()); out = new DataOutputStream(accept.getOutputStream()); boolean goon = true; while (goon) { String str = in.readUTF(); if (null == str || "".equals(str)) { goon = false; } else { if ("bye".equalsIgnoreCase(str)) { goon = false; } else { out.writeUTF("ECHO:" + str); } } } in.close(); out.close(); accept.close(); } catch (IOException e) { e.printStackTrace(); } } }
Class : EchoThreadServer
package limeNet.thread.server; import java.net.ServerSocket; import java.net.Socket; public class EchoThreadServer { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8888); while(true){ System.out.println("服务器运行,等待客户端连接。"); Socket accept = serverSocket.accept(); new Thread(new EchoThread(accept)).start(); } } }
Class : EchoClient
package limeNet.client; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.util.Scanner; public class EchoClient { public static void main(String[] args) throws Exception, Exception { Socket client = null; client = new Socket("localhost",8888); DataInputStream in = null; DataOutputStream out = null; in = new DataInputStream(client.getInputStream()); out = new DataOutputStream(client.getOutputStream()); Scanner sc = new Scanner(System.in); boolean flag = true; while(flag){ System.out.print("输入信息:"); String str = sc.nextLine(); out.writeUTF(str); if("bye".equals(str)){ flag = false; }else{ String echo = in.readUTF(); System.out.println(echo); } } in.close(); out.close(); sc.close(); client.close(); } }
19.5 UDP程序设计
19.5.1 UDP简介
19.5.2 UDP程序实现
Class : UDPClient
package limeNet.udp.client; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UDPClient { public static void main(String[] args) throws IOException { DatagramSocket ds = new DatagramSocket(9000); byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, 1024); // 阻塞 ds.receive(dp); String str = new String(dp.getData(),0,dp.getLength()) + "from " + dp.getAddress().getHostAddress() + " : " + dp.getPort(); System.out.println(str); ds.close(); } }
Class : UDPServer
package limeNet.udp.server; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPServer { public static void main(String[] args) throws IOException { DatagramSocket ds = null; DatagramPacket dp = null; ds = new DatagramSocket(3000); String str = "Hello World"; dp = new DatagramPacket(str.getBytes(), str.length(),InetAddress.getByName("localhost"),9000); System.out.println("发送信息。"); ds.send(dp); ds.close(); } }
啦啦啦
啦啦啦
啦啦啦
啦啦啦
啦啦啦
啦啦啦
啦啦啦
啦啦啦