Java系列(十九)__Java网络编程
网络编程的时代已经过去了,而且也很难再有新的突破了,所以对于此部分的内容了解一些就够了。如果你不会,也不影响开发。
1.1、网络编程简介
网络:指的是将物理上分离的计算机通过连接形成的布局,而网络编程指的是实现网络的通讯操作,而在实际的工作之中网络编程分为两类:
· C/S结构(Client / Server):类似于QQ,需要编写两套程序,一套是服务器端程序,另外一套是客户端程序,而在进行维护的时候也需要维护两套程序,C/S使用专署的协议,所以安全性较高;
· B/S结构(Browse/Server):利用浏览器实现客户端功能,开发者只需要开发出服务器端一套程序即可,维护的时候也只需要维护一套程序,B/S结构一般都使用公共的通讯协议(HTTP),所以安全性较差。
而今天讲解的网络编程主要是以C/S为主进行介绍。而在C/S开发之中也分为两种:TCP(可靠的传输)、UDP(数据报的传输)。今天的内容主要以TCP程序为主,而这个就是Socket程序。
1.2、基本的Socket程序开发
如果要想开发出Socket程序需要使用java.net包,里面主要使用两操作类完成:
· ServerSocket:运行在服务器端,只有通过ServerSocket才可以打开一个监听端口;
· Socket:每一个连接到服务器端的用户都是一个Socket对象,服务器端如果要想操作用户的数据,则必须通过Socket对象取得(输入/输出)。
范例:编写一个服务器端程序
服务器端主要是ServerSocket服务,在ServerSocket类之中提供有如下方法:
· 构造方法:public ServerSocket(int port) throws IOException;
· 取得连接:public Socket accept() throws IOException;
而当服务器端取得了客户端操作之后,就可以向客户端输出信息:
· 取得输出流:public OutputStream getOutputStream() throws IOException;
package cn.mldn.demo; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class HelloServer { public static void main(String[] args) throws Exception { // 在本机的9999端口上进行监听,连接的时候IP地址就是本机地址 ServerSocket server = new ServerSocket(9999) ; System.out.println("服务器端启动....."); Socket client = server.accept() ; // 等待客户端连接 PrintStream out = new PrintStream(client.getOutputStream()) ; out.println("Hello World .") ; out.close() ; client.close(); server.close(); } } |
本程序只能够处理一个用户的请求,同时只会向客户端发送一次数据,发送完毕之后服务器端就将结束运行。
运行服务器端之后下面为了测试程序方便,可以直接利用telnet命令进行服务器端的连接操作。这个时候连接到服务器上之后取得服务器上的信息,那么telnet就会被关闭,而此时服务器端也已经关闭了。
此时的通讯是利用TCP协议实现的连接操作,并且使用的是一个公共工具完成的连接,这样用户将无法进行更多的处理,所以现在可以直接编写一个客户端连接。
范例:编写客户端
每一个Socket都表示一个客户端连接,所以在Socket类里面存在有以下方法:
· 构造方法:public Socket(String host, int port) throws UnknownHostException, IOException;
但是服务器端的输出数据对客户端而言属于输入数据,所以需要使用Socket类的如下方法取得输入数据:
· 取得输入数据:public InputStream getInputStream() throws IOException。
package cn.mldn.demo; import java.net.Socket; import java.util.Scanner; public class HelloClient { public static void main(String[] args) throws Exception{ Socket client = new Socket("192.168.0.253",9999) ; // 连接服务器端 Scanner scan = new Scanner(client.getInputStream()) ; scan.useDelimiter("\n") ; if (scan.hasNext()) { System.out.println("服务器端返回数据:" + scan.next()); } scan.close(); client.close(); } } |
这就是一个最基本的网络通讯模型。下面为了方便起见不再重复编写客户端。利用telnet操作。
1.3、网络编程的经典案例 —— Echo程序
ECHO是现在所有网络编程的基本模型,所谓的ECHO指的是客户端向服务器端发送数据,服务器端接收到数据之后,前面增加一个“ECHO”后返回。
范例:编写服务器端
package cn.mldn.demo; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class EchoServer { public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(9999) ; Socket client = server.accept() ; // 连接客户端 Scanner in = new Scanner(client.getInputStream()) ; in.useDelimiter("\n") ; PrintStream out = new PrintStream(client.getOutputStream()) ; // 如果要想进行无限制的输入,那么可以采用循环的方式进行操作 boolean flag = true ; // 循环标记 while (flag) { if (in.hasNext()) { // 有输入数据 String data = in.next().trim() ; // 接收数据 if ("byebye".equalsIgnoreCase(data)) { // 结束 flag = false ; // 退出循环 out.println("程序结束,拜拜,下次再来!"); } else { // 前面要增加ECHO返回 out.println("ECHO : " + data); } } } server.close(); } } |
此时的程序只是一个单线程应用,因为只在主线程之中接收用户的请求,那么如果要想让一个服务器可以同时满足于多个用户的使用,则需要将每一个连接到服务器上的用户通过一个新的线程表示。
范例:使用多线程处理多用户访问
package cn.mldn.demo; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class EchoServer { public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(9999) ; boolean flag = true ; while(flag) { // 循环 Socket client = server.accept() ; // 连接客户端 new Thread(new MyThread(client)).start(); } server.close(); } static class MyThread implements Runnable { private Socket client ; public MyThread(Socket client) { this.client = client ; } @Override public void run() { try { Scanner in = new Scanner(this.client.getInputStream()) ; in.useDelimiter("\n") ; PrintStream out = new PrintStream(this.client.getOutputStream()) ; // 如果要想进行无限制的输入,那么可以采用循环的方式进行操作 boolean flag = true ; // 循环标记 while (flag) { if (in.hasNext()) { // 有输入数据 String data = in.next().trim() ; // 接收数据 if ("byebye".equalsIgnoreCase(data)) { // 结束 flag = false ; // 退出循环 out.println("程序结束,拜拜,下次再来!"); } else { // 前面要增加ECHO返回 out.println("ECHO : " + data); } } } this.client.close(); } catch (Exception e) { e.printStackTrace(); } } }} |
此时每一个连接到服务器上的用户都使用一个线程进行处理,从而可以让一个服务器端处理多个客户端的请求。
所以对于服务器端的开发基本的组成:网络编程 + IO + 多线程,这个概念知道就行了。