一、Socket开发
基于TCP协议的通讯,客户端和服务端都需要使用socket对象获取输入流和输出流,使用io流对象进行读或写数据通讯。
如果需要一个服务器为多个客户端提供服务,那么必须为每个客户端都启动一个线程。
结论:
在一个线程里处理多个客户端请求会发生阻塞问题,
如果同时服务多个客户端,则必须为每个客户端启动一个线程提供服务。
- 实际编程中,我们通常需要一个服务器对多个客户端提供网络服务;
- 要实现一个服务器对多个客户端提供网络服务,则在接受请求后,启动一个独立线程为当前客户端服务即可;
服务器:接受客户端请求指令以及数据进行处理将数据信息持久化存储在本地数据库中。
客户端:展示给用户界面,并且受用户的信息发送给服务器,展示服务器返回的信息
- JDK1.5以后io包的很多功能已经通过nio的方式进行了重构,因此io操作本身的性能已经得到了极大的提升,但是nio和传统的io还有一个极大的差异:nio能够以非阻塞的形式完成数据读取
- 以事件循环的方式读取数据而不是传统的阻塞方式读取数据带来的好处是无需在服务器端构建多余的线程来等待数据从而减轻服务器的性能负担
- 构建nio版本的Socket服务器的基本过程是:
- 开启ServerSocket通道并绑定一个TCP端口
- 创建nio事件选择器并注册到ServletSocket
- 循环处理选择器中关联的Socket事件(isAcceptable-有用户连接,isAcceptable-有数据可供读取)
- 构建nio版本的Socket客户端的基本过程是:
- 构建Socket通道(与服务器连接)
- 创建事件选择器,与Socket通道绑定
- 处理Socket通道事件
- 利用传统io完成Socket通讯中一个服务器端对多个客户端提供服务时,线程特征是什么?为什么需要这样的结构?
- 利用传统io完成Socket通讯中一个服务器端对多个客户端提供服务时,由于传统io在读取数据时是以阻塞的方式获取数据,即调用读取数据的方法后会导致调用线程阻塞,直到真的读取到期望的数据才会返回,因此,每一个客户端均需要提供一个独立的线程来维护(读取数据),否则,每一个用户均会影响其他用户的数据读取操作
二、UDP
Java语言中使用数据报(datagram)进行基于UDP的网络编程
数据报如同邮件系统,不能保证可靠的传输,而面向连接的TCP就好比打电话,双方能肯定对方接受了信息。
- Java API中java.net包提供了DatagramSocket和DatagramPacket两个类,用来支持数据报通信;
- DatagramSocket用于在程序之间建立传送数据报的通信连接;
- DatagramPacket则用来表示一个数据报;
- Java中数据报通讯开发中用于发送和接受数据的工具DatagramSocket,无论是服务器端还是客户端均使用该工具完成数据收发工作,该工具在完成数据的接收和发送的过程均须将数据转换为byte[]完成
1 package com.chinasofti.udp; 2 3 import java.io.IOException; 4 import java.net.*; 5 import java.util.Scanner; 6 7 public class ClientUdp { 8 public static void main(String[] args) throws IOException { 9 // 获取一个udp数据报的套接字对象 参数 发送端端口 10 DatagramSocket client = new DatagramSocket(12344); 11 while (true) { 12 // 创建一个发送数据 13 System.out.print("请输入:"); 14 Scanner sc = new Scanner(System.in); 15 String msg = sc.next(); 16 // 创建数据报 参数是 (数据的字节数组 数据的长度 本机地址 目标的端口) 17 DatagramPacket datagramPacket = new DatagramPacket(msg.getBytes(),msg.length(), InetAddress.getLocalHost(),12345); 18 // 发送数据报 19 client.send(datagramPacket); 20 System.out.println("发送数据完毕"); 21 } 22 } 23 }
1 package com.chinasofti.udp; 2 3 import java.io.IOException; 4 import java.net.DatagramPacket; 5 import java.net.DatagramSocket; 6 7 public class ServerUdp { 8 public static void main(String[] args) throws IOException { 9 // 创建服务器udp套接字对象 10 DatagramSocket server = new DatagramSocket(12345); 11 // 创建一个接受信息的字节数组 12 byte[] bytes = new byte[100]; 13 // 创建服务器接受数据报 14 DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length); 15 // 循环接收发送到12345端口的数据 16 while (true) { 17 System.out.println("服务器等待接受客户端数据。。。"); 18 // 接受数据报 19 server.receive(datagramPacket); 20 // 在控制台输出从客户端接受的信息 21 System.out.println(datagramPacket.getAddress().getHostAddress()+"用户发送了:"+new String(datagramPacket.getData(),0,datagramPacket.getLength())); 22 } 23 } 24 }
三、URL
- URL统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL
- 基本URL包含模式(或称协议)、服务器名称(或IP地址)、路径和文件名,如
- 协议://授权/路径?查询
- 完整的、带有授权部分的普通统一资源标志符语法看上去如下:
- 协议://用户名:密码@子域名.域名.顶级域名:端口号/目录/文件名.文件后缀?参数=值#标志
- 因此从理论上来说,任何形式的网络连接(Socket、UDP以及HTTP等)均可以用URL来进行描述(URL的第一部分即描述了通讯协议,第二部分包含了连接的主机)
- 如果URL的形式类似于“http://192.168.1.1:8080/res“的形式,那么就能够说明访问该资源使用的协议为HTTP
- JDK提供了一个使用十分方便的工具利用HTTP协议创建一个网络连接并提供数据传输通道:HttpURLConnection
- 由于目前的HTTP是基于TCP协议的应用层协议,因此事实上可以用更为底层的方式来访问HTTP服务-直接使用Socket完成HTTP的请求和响应过程,例如上例获取图片的过程本质上就是通过Socket连接服务器后按照HTTP协议的请求格式向服务器发送了基础的资源请求:
- 和模拟客户端类似,Socket模拟服务器端也是按照之前普通Socket服务器的方式构建,区别在于服务器需要按照HTTP协议的要求解析客户端通过Socket发送来的请求属性,并同样按照该规则返回HTTP响应
- 一般情况下服务器针对请求会有不同的响应策略,例如返回固定的响应、返回由程序生成的临时响应内容或者根据请求中的资源路径返回对应的文件资源:
- 由于当前版本HTTP的通讯特征和固定流程(客户请求->处理->服务器响应)是建立在可信的TCP协议基础之上,因此存在以下特点:
- 每一个独立的请求均可看作一个单独的客户
- 每个客户需要在独立的线程中维护处理(io的阻塞读取)
- HTTP请求的声明周期很短,因此对其数据进行维护的线程声明周期也很短,在一个较短的时间段内也会存在大量的请求,如果每次都创建新的线程,则会存在大量的线程申请和释放的操作,消耗性能,因此HTTP服务器均需要创建适当的线程池
- 在JDK中可以通过几种形式实现HTTP通讯?
- HTTP服务器中线程池有什么重要性?
- 在JDK中可以通过HttpURLConnection客户端完成HTTP通讯,也可以直接通过Socket模拟完成HTTP的客户端和服务器端应用
- HTTP请求的声明周期很短,因此对其数据进行维护的线程声明周期也很短,在一个较短的时间段内也会存在大量的请求,如果每次都创建新的线程,则会存在大量的线程申请和释放的操作,消耗性能,因此HTTP服务器均需要创建适当的线程池来保证性能
四、常用工具
什么是xml:
XML 指可扩展标记语言(EXtensible Markup Language)
XML 的设计宗旨是传输数据,而不是显示数据
XML 标签没有被预定义,需要自行定义标签
XML 被设计为具有自我描述性,不依赖与语言平台
XML 是 W3C 的推荐标准
XML 不会做任何事情,XML 被设计用来结构化、存储以及传输信息:
- XMl文件示例:
- 这条便签具有自我描述性,它包含了发送者和接受者的信息,同时拥有标题以及消息主体
- 这个 XML 文档不会做任何事情,它仅仅是包装在 XML 标签中的纯粹的信息。我们需要编写程序,才能传送、接收和解析这个文档(XML 和JSON是目前各种应用程序之间进行数据传输的最常用的格式)
- XML文件形成了一种树结构,它从“根部”开始,然后扩展到“枝叶”
- XML 文档必须包含根节点。该节点是所有其他节点的父节点(一个XML文档有且只有一个根节点)
- XML 文档中的节点元素形成了一棵文档树。这棵树从根部开始,并扩展到树的最底端,所有的元素都可以有子元素:
- 拥有正确语法的 XML 被称为“形式良好”的 XML,通过 DTD 验证的XML是“合法”的 XML,“形式良好”的 XML 文档拥有正确的语法:
- XML文档必须有一个根元素
- XML节点元素都必须有一个关闭标签
- XML标签对大小写敏感
- XML元素必须被正确的嵌套
- XML属性值必须加引号
- 一般情况下,程序中对XML文档进行解析可以使用两种方式:DOM和SAX:
- DOM:
- Document Object Model,文档对象模型,将整个文档加载进内存并分析整颗树的数据结构,根据节点元素之间的父子关系完成整棵树上所有节点的遍历
- 优势:符合XML树的数据结构逻辑定义,可以对树结构进行修改
- 劣势:需要完整加载文档,对于LDAP领域等能够产生超大型XML文档的环境明显不适用
-
- SAX:
- Simple API for XML,针对XML文档的事件驱动解析引擎,逐行对文档进行分析,遇到文档的特定组成部分后回调预先定义的事件回调
- 优势:无需预先完整加载文档,不会对程序的运行时内存造成毁灭性影响
- 劣势:不符合XML文档的本质数据结构,只能用来解析遍历,而不能修改
- SAX:
JDK工具对DOM和SAX方式的XML解析均提供了参考实现,无需第三方库即能完成
- 对DOM节点进行修改后,可以利用Transformer API将DOM结构还原为XML文档: