关键词:
Java高级篇(二)——网络通信
网络编程是每个开发人员工具相中的核心部分,我们在学习了诸多Java的知识后,也将步入几个大的方向,Java网络编程就是其中之一。
如今强调网络的程序不比涉及网络的更多。除了经典的应用程序,如电子邮件、Web浏览器和远程登陆外,大多数主要的应用程序都有某种程度的内质网络功能。比如我们最常使用的IDE(Eclipse/IDEA)与源代码存储库(GitHub等等)进行通信;再比如Word,可以从URL打开文件;又或者是我们玩的众多联机游戏,玩家实时相互对战等等。Java是第一个从一开始就为网络应用而设计的编程语言,最早的两个实用Java应用的程序之一就是Web浏览器,随着Internet的不断发展,Java成为了唯一适合构建下一代网络应用程序的语言。(节选自Java NetWork Programming——Elliotte Rusty Harold著)
一、Client/Server
为了实现两台计算机的通信,必须要用一个网络线路连接两台计算机。服务器(Server)是指提供信息的计算机或程序,客户机(Client)是指请求信息的计算机或程序,而网络用于连接服务器与客户机,实现两者相互通信。
下面我们看一个简单的通信例子。
如下的Server程序是一个服务器端应用程序,使用 Socket 来监听一个指定的端口。
1 import java.io.IOException; 2 import java.io.InputStreamReader; 3 import java.io.Reader; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 public class Server { 8 9 public static void main(String[] args) throws IOException {10 int port = 9999;11 12 System.out.println("-----------客户端启动-----------");13 14 ServerSocket server = new ServerSocket(port);15 Socket socket = server.accept();16 Reader reader = new InputStreamReader(socket.getInputStream());17 char chars[] = new char[1024];18 int len;19 StringBuilder builder = new StringBuilder();20 while ((len=reader.read(chars)) != -1) {21 builder.append(new String(chars, 0, len));22 }23 System.out.println("收到来自客户端的信息: " + builder);24 reader.close();25 socket.close();26 server.close();27 }28 29 }
如下的Client是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应。
1 import java.io.IOException; 2 import java.io.OutputStreamWriter; 3 import java.io.Writer; 4 import java.net.Socket; 5 import java.util.Scanner; 6 7 public class Client { 8 9 public static void main(String[] args) throws IOException {10 String host = "127.0.0.1";11 int port = 9999;12 13 System.out.println("-----------服务器启动-----------");14 15 Socket client = new Socket(host, port);16 Writer writer = new OutputStreamWriter(client.getOutputStream());17 Scanner in = new Scanner(System.in);18 writer.write(in.nextLine());19 writer.flush();20 writer.close();21 client.close();22 in.close();23 }24 25 }
先启动服务器,运行结果如下:
再运行客户端,并输入要发送的信息,如下:
此时Server就接收到了Client发送的消息,如下:
这就是一个简单的套接字通信了,具体分析见下方TCP。
二、TCP
TCP网络程序设计是指利用Socket类编写通信程序,具体实例参照上例。
套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
两台计算机间使用套接字建立TCP连接步骤如下:
服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
1. InetAddress
java.net包中的InetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。
InetAddress ip = InetAddress.getLocalHost(); String localName = ip.getHostName(); //获取本地主机名String localIp = ip.getHostAddress(); //获取本地主机的ip地址
2. ServerSocket
java.net包中的ServetSocket类用于表示服务器套接字,其主要功能是等待来自网络上的“请求”,它可以通过指定的端口来等待连接的套接字(如上方实例中的9999)。
而服务器套接字一次可以与一个套接字连接,如果多台客户机同时提出连接请求,服务器套接字会将请求连接的客户机存入队列中,然后从中取出一个套接字,与服务器新建的套接字连接起来。若请求连接数大于最大容纳数,则多出的连接请求被拒绝。
ServerSocket的具体方法可参照API,这里只对accept()方法进行一个说明。调用accept()方法将返回一个与客户端Socket对象相连的Socket对象,服务器端的Socket对象使用getOutputStream()方法获得的输出流对象,将指向客户端Socket对象使用getInputStream()方法获得的输入流对象,反之亦然。
需要注意的是,accept()方法会阻塞线程的继续执行,直到接受客户的呼叫,如果没有客户呼叫服务器,那么下面的代码将不会执行。
三、UDP
用户数据包协议(UDP)是网络信息传输的另一种形式,基于UDP的通信与基于TCP的通信不同,UDP的信息传递更快,但不提供可靠的保证。
1. DatagramPacket
java.net包中的DatagramPacket类用来表示数据包,构造方法如下:
DatagramPacket(byte[] buf, int length) DatagramPacket(byte[] buf, int length, InetAddress address, int port)
上述构造方法中,第一种指定了数据包的内存空间和大小,第二种不仅指定了数据包的内存空间和大小,并且指定了数据包的目标地址和端口。
2. DatagramSocket
java.net包中的DatagramSocket类用于表示发送和接受数据包的套接字,构造方法如下:
DatagramSocket() DatagramSocket(int port) DatagramSocket(int port, InetAddress addr)
上述构造方法中,第一种创建数据包套接字并将其绑定到本地主机上任何可用的端口,第二种创建数据包套接字并将其绑定到本地主机上的指定端口,创建数据包套接字并将其绑定到指定的本机地址。
四、实例测试
下面写一个完整的实例,题目如下:
建立服务端程序,服务器端程序接收来自客户端的请求;
从网上下载程序,英语900句,每句占一行;
服务端读取该文件,保存到集合或者列表中;
建立客户端程序,使用”sentence: <编号#>,<编号#>”的格式发生数据。例如:发送”sentense:1,2,3” , 服务端把相应编号的句子发送给客户端,并加以呈现;
客户端需要把服务端发送的句子保存起来,如果已经保存有相应的句子,将不再保存;
客户端需要把从服务端获取的数据存储到文件中。
1. 程序结构
2. Server.java
该类为客户端类。
1 import java.io.*; 2 import java.net.ServerSocket; 3 import java.net.Socket; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 /** 8 * 9 * @author adamjwh10 *11 */12 public class Server {13 14 public static List<String> sentence;15 private static String filename = "src/com/adamjwh/jnp/ex6_2/English900.txt";16 17 public static void main(String[] args) throws IOException {18 sentence=new ArrayList<>();19 System.out.println("-----------服务器启动-----------");20 21 FileReader fileReader = new FileReader(filename);22 BufferedReader br = new BufferedReader(fileReader);23 24 String inputLine = null;25 while ((inputLine = br.readLine()) != null) {26 sentence.add(inputLine);27 }28 29 ServerSocket ss = new ServerSocket(9999);30 while(true){31 Socket sk =ss.accept();32 ServerThread st = new ServerThread(sk);33 st.start();34 }35 36 }37 }
2. Client.java
该类为服务器类。
import java.io.BufferedReader;import java.io.FileWriter;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.util.Scanner;/** * * @author adamjwh * */public class Client { private static String filename = "src/com/adamjwh/jnp/ex6_2/result.txt"; public static void main(String[] args) { try { Socket sk = new Socket("127.0.0.1", 9999); System.out.println("-----------客户端启动-----------"); PrintStream ps = new PrintStream(sk.getOutputStream()); System.out.print("发送:"); Scanner sn = new Scanner(System.in); String str = sn.nextLine(); ps.println(str); InputStream is = sk.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); //写文件 FileWriter fw = new FileWriter(filename, true); //读文件 String result = new ReadFile().readFile(filename); String s; while ((s = br.readLine()) != null) { System.out.println("服务器推送:" + s); if(!result.contains(s)) { fw.write(s + " "); } } sk.shutdownInput(); ps.close(); sk.close(); fw.close(); } catch (Exception e) { e.printStackTrace(); } } }
3. ServerThread
通过线程实现信息交互。
1 import java.io.*; 2 import java.net.Socket; 3 4 /** 5 * 6 * @author adamjwh 7 * 8 */ 9 public class ServerThread extends Thread{10 Socket sk;11 public ServerThread(Socket sk){12 this.sk= sk;13 }14 public void run() {15 BufferedReader br=null;16 try{17 br = new BufferedReader(new InputStreamReader(sk.getInputStream()));18 String line = br.readLine();19 System.out.println("客户端:"+line);20 String[] split = line.split(":");21 String[] split1 = split[split.length - 1].split(",");22 sk.shutdownInput();23 24 OutputStream os = sk.getOutputStream();25 26 PrintStream bw = new PrintStream(os);27 28 //给客户端返回信息29 for(int i=0;i<split1.length;i++) {30 bw.print(Server.sentence.get(Integer.parseInt(split1[i])%Server.sentence.size())+" ");31 }32 bw.flush();33 br.close();34 sk.close();35 }36 catch(IOException e){37 e.printStackTrace();38 }39 }40 }
4. 运行结果
先运行服务器
再运行客户端,并输入信息
服务器接收到客户端发来的请求
服务器将请求结果推送给客户端,这里客户端就获取到了它请求的第174句、第258句及第5句,并输出到文件中
这里的测试文件我测试到了162(也就是该文件的第15行),可以看到在文件中追加了两行新的句子(174和258),而第5句因为在之前已经出现过了(该文件的第1行),所以没有追加第5句,完成上述题目。
socket网络编程-高级篇(代码片段)
7.Netty实现文件服务器(基于HTTP协议)8.最佳实践9.Mina入门基础********************************************************************************************************************1.7使用场景1:数据通信方式;1.第一种 查看详情
java高级知识系列篇
文章目录反射重载与重写I/O多态枚举反射反射重载与重写重载、重写(Override、Overload)I/OI/O(输入输出流)多态多态枚举枚举 查看详情
java高级篇——反射
之前写到了设计模式的代理模式,因为下一篇动态代理等内容需要用到反射的知识,所以在之前Java篇的基础上再写一篇有关反射的内容,还是以实际的程序为主,了解反射是做什么的、应该怎么用。一、什么是反射 反... 查看详情
java菜鸟到大牛学习路线之高级篇
这是一套java菜鸟到大牛的学习路线之高级教程,由本站工作了10年的资深Java架构师整理。 01-java高级架构师设计-基础深入 J2SE深入讲解 Java多线程与并发... 查看详情
备面百度
...程网络编程常用框架篇SpringSpringMVCSpringBoot/CloudMyBatis其他高级框架NettyDubboKafka工具篇MavenGit/SVN数据库篇MySqlRedisMongDB物联网篇http/httpsTcp/IPMQTT等其他能力Linux能力Python(机器学习) 查看详情
java基础篇
第一篇一、什么是JAVAJava是一种高级的面向对象的程序设计语言。Java是一种通过解释方式来执行的语言,一种跨平台的程序设计语言。Java语言编写的程序既是编译型,又是解释型。相比C++,JAVA语言更简洁,更可靠,更安全。二... 查看详情
java高级学习篇之反射
(一)什么是反射? 反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够获取这个类的所有属性和方法;对于任意一个对象,都能调用其任意一个方法和属性。... 查看详情
java高级篇(jvm内存模型内存管理)
JVM内存结构如 Java堆(Heap),是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内... 查看详情
java高级篇(jvm基本概念)
一、什么是JVMVM的中文名称叫Java虚拟机,它是由软件技术模拟出计算机运行的一个虚拟的计算机。JVM也充当着一个翻译官的角色,我们编写出的Java程序,是不能够被操作系统所直接识别的,这时候JVM的作用就体现出来了,它负... 查看详情
java高级学习篇之io流
(一)什么是IO? IO是InputOutput的缩写,表示的是输入输出流。(1) I:Input,表示的是将数据从硬盘的文件中输入到内存,称为Read操作。(2) O:Output,表示的是将数据从内存输出到硬盘的文件,也称为write操... 查看详情
11:高级篇-ctk事件管理机制(插件间通信)
作者:一去、二三里个人微信号:iwaleon微信公众号:高效程序员发布/订阅模式事件管理服务规范是CTKPluginFramework规范的一部分,它定义了一个通用的插件间通信机制。该机制遵循流行的发布/订阅模式,并且可以以同步或异步的... 查看详情
《docker高级篇(大厂进阶):4.docker网络》包括:是什么常用基本命令能干嘛网络模式docker平台架构图解(代码片段)
文章目录二、高级篇(大厂进阶)4.Docker网络4.1Docker网络是什么4.2常用基本命令4.3能干嘛4.4网络模式4.4.1总体介绍4.4.2容器实例内默认网络IP生产规则4.4.3案例说明bridgehostnonecontainer自定义网络4.5Docker平台架构图解本人其他相关文章链... 查看详情
云原生时代必须具备的核心技能之docker高级篇(docker网络详解)(代码片段)
...ker的基础内容Docker基础篇接下来给大家系统的介绍下Docker高级篇的内容:网络核心、Docker实战、DockerCompose、Harbor以及Swarm。欢迎关注收藏哦Docker网络介绍 Docker是基于LinuxKernel的namespace,CGroups,UnionFileSystem等技术封装成... 查看详情
python-初见-高级篇(代码片段)
目录正则表达式CGIMySQLPyMySQL网络编程多线程线程同步线程优先级JSON推荐阅读:https://www.cnblogs.com/zwtblog/tag/Python/正则表达式主要是re模块:#publicsymbols__all__=["match","fullmatch","search","sub","subn","split","findall","finditer","co 查看详情
13:高级篇-ctk事件管理机制(signal/slot)(代码片段)
...三里个人微信号:iwaleon微信公众号:高效程序员在《12:高级篇-CTK事件管理机制(sendEvent/postEvent)》一文中,我们介绍了如何进行插件间通信-sendEvent()/postEvent()+ctkEventHandler。然而,除了这种方式之外,EventAdmin还提供了另一种... 查看详情
校招实习面试系列,每日10题,快速学习java高级篇(代码片段)
【校招实习面试系列,每日10题,快速学习】Java高级篇1、ThreadLocal的应用场景有哪些?2、ThreadLocal为什么存在内存泄露的问题,如何解决?3、AQS是什么?4、CAS是什么?5、基于CAS实现的锁和synchronized有... 查看详情
java岗大厂面试百日冲刺-日积月累,每日三题day02——java高级篇
大家好,我是陶然同学,软件工程大三明年实习。认识我的朋友们知道,我是科班出身,学的还行,但是对面试掌握不够,所以我将用这100多天更新Java面试题 查看详情
java岗大厂面试百日冲刺-日积月累,每日三题day03——java高级篇
大家好,我是陶然同学,软件工程大三明年实习。认识我的朋友们知道,我是科班出身,学的还行,但是对面试掌握不够,所以我将用这100多天更新Java面试题 查看详情