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 adamjwh 10 * 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 + "\n");}}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())+"\n"); 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句,完成上述题目。
转载于:https://www.cnblogs.com/adamjwh/p/8856516.html
Java高级篇(二)——网络通信相关推荐
- java rabbitmq 并发_RabbitMQ消息中间件 高级篇二 高并发情况下保障消息投递可靠性...
RabbitMQ消息中间件技术精讲9 高级篇二 高并发场景下,消息的延迟投递做二次确认进行回调检查来保障生产者消息投递成功的可靠性 在上一篇文章中,我们介绍了BAT大厂中一种方式保障生成者消息投递可靠 ...
- Java高级篇——深入浅出Java类加载机制
转载自 Java高级篇--深入浅出Java类加载机制 类加载器 简单讲,类加载器ClassLoader的功能就是负责将class文件加载到jvm内存. 类加载器分类 从虚拟机层面讲分为两大类型的类加载 ...
- 【转】java提高篇(二)-----理解java的三大特性之继承
[转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...
- elasticsearch - java - 高级篇 - 封装类 - 2
世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程. -侯氏工坊 文章目录 说明 参考 核心封装类 新增类 说明 高级篇是自我封装的一个进化过程 封装类并不是固定不变 ...
- Java高级篇-0-为什么要掌握Java高级篇知识
好长时间了,就想要花时间系统去学习下Java的高级篇知识,这部分是我个人目前比较欠缺的,而且是急缺的知识.我认为的Java高级篇内容是这样划分的:对Java这个编程语言有基本了解,基本掌握了基础语法, ...
- 服务异常通讯高级篇二(死信交换机、DelayExchange延迟队列插件)
服务异常通讯高级篇二(死信交换机) 1.初始死信交换机 当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter): 消费者使用basic.reject或 basic.nack声明消 ...
- 谷粒商城-个人笔记(高级篇二)
目录 二.商城业务-首页 1.整合thymeleaf渲染首页 1).在"gulimall-product"项目中导入前端代码: 2).渲染一级分类数据&&整合dev ...
- 2022金三银四面试总结-Java高级篇
Java面试总结 1.你用过哪些集合类? 大公司最喜欢问的Java集合类面试题 40个Java集合面试问题和答案 java.util.Collections 是一个包装类.它包含有各种有关集合操作的静 ...
- 【鲁班学院】面试总结:Java高级篇(上):集合的类型以及重新认识HashMap
1.你用过哪些集合类? 大公司最喜欢问的Java集合类面试题 40个Java集合面试问题和答案 java.util.Collections 是一个包装类.它包含有各种有关集合操作的静态多态方法. ja ...
最新文章
- php伪类型,解密PHP伪类型和伪变量的含义
- MySQL 命令行下执行.sql脚本
- Sharepoint摸索之路
- 跟随我在oracle学习php(21)
- mysql5.5提示Deprecated: mysql_query(): The mysql extension is deprecated
- 解决android4.0系统中菜单(Menu)添加Icon无效问题
- xis表格怎么打印_Excel做的表格怎么打印
- 安装window10出错:选中的磁盘具有 MBR 分区表。在 EFI 系统上,Windows只能安装到GPT磁盘。
- Linux unison 效率,Linux中inotify+unison实现数据双向(多向)实时同步
- unity3D的FingerGestures插件
- win10系统快速进入bios的设置方法
- PCIE switch 连接绿联SSD
- 视觉工程师笔试知识汇总
- 矩阵键盘逐行扫描C语言,(原创)51单片机C语言程序设计--速学教程实例(入门篇)之矩阵键盘(逐行扫描法).pdf...
- bugkuCTF——猫片(安恒)
- Linux内核配置(二) :CPU类型配置
- 数据库数据 与 excel 对比。(项目一)
- 教你用福昕PDF转换器将手机图片转PDF文档
- 复变函数与积分变换matlab,《复变函数与积分变换》课程教学与MATLAB应用
- 诺基亚系列手机型号命名研究
热门文章
- 数字图像处理频域滤波实现低通与高通滤波(包含matlab代码)
- zip:命令行下zip压缩/解压缩
- filter-mutate过滤插件
- Java动态代理深入解析
- 记忆化搜索,FatMouse and Cheese
- Google 拼音会导致卡 Ctrl 键?
- 虚拟软驱影像文件制作程序下载路径:http://download.csdn.net/source/738137
- [FxCop.设计规则]13. 定义自定义属性参数的访问属性
- LeetCode—221. 最大正方形
- 浏览器打不开html链接,win7系统ie浏览器打不开网站链接怎么办