随笔 -- IO -- Socket/ServerSocket -- Echo(BIO)实例

时间:2024-08-18 22:37:32

随笔 -- 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("\n");
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("\n");
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();
}
}

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦