网络编程
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,实现资源共享和信息传递的计算机系统;
Java中专门提供java.net包,方便开发网络程序。Java的网络编程包括了两种通信协议:
- TCP(Transmission Control Protocal):传输控制协议
- UDP(User Datagram Protocol):用户数据协议
相关术语
两台计算机进行网络通信需要满足一下条件:
- 两台主机需要有一个唯一的标识:也就是IP地址,用来表示所处的身份和位置
- 需要有共同的语言:协议(TCP/IP)
- 都需要有相应的端口号:port
一台主机上可以运行多个应用程序,如何辨别不同应用程序的通信,就是通过端口号port来进行区分。
IP地址
为实现网络中不同计算机之间的通信,每台计算器都必须有一个唯一的标识,那就是IP地址(公网IP),这就相当于每个人的手机号码一样。例如:192.168.0.1
IP分以下两个大类:
- IPv4:32位,分4段,(每段的范围0-255)0~255之间的十进制表示。使用4个8位的二进制数据表示,每8位之间使用圆点隔开,每个8位整数可以转换成一个0~255的十进制整数,因此一般看到的IP地址类似:192.168.1.1 这4段组成的个数有限度(42.28亿),可能会不够用,就出现了Ipv6。
- IPv6:128位,分8段,0000~FFFF的十六进制数值,冒号分割,如:1080:0:0:0:8:800:200C:417A
IP地址号段分类:A类留给政府机构,B类分配给中等规模的公司,C类分配给任意需要的人,D类用于组播,E类用于实验,各类可容纳的地址数目不同:
注:
-
外网IP是全世界唯一的IP地址,仅分配给一个网络设备(计算机、交互机、路由器、打印机、光纤等)。而内网IP是由路由器分配给每一部内部使用的IP地址,而内网的所有用户都是通过同一个外网IP地址进行上网的;
-
内网的IP地址每个人的都不一样,Internet上的用户也无法直接访问到内网用户。简单来说呢,外网IP就是标示了在整个互联网上的地址,就相当于小区的地址,而内网IP呢,就是标识着在局域网里面的地址,也就是小区内的几栋几楼几号房子;
-
在局域网中,每台电脑都可以自己分配自己的IP,这个IP只在局域网中有效。而如果将电脑连接到互联网,网络提供商(ISP)的服务器会分配一个IP地址,这个IP地址才是在外网的IP。两个IP同时存在,一个对内,一个对外;
-
区分内网和公网IP的区别,公网IP是全球唯一的,而内网IP只是在局域网内有效,不具有公网IP的作用。查询公网IP地址:www.ip138.com
Port端口
端口port用来区分不同的应用程序,端口号范围为0~65535,其中0~1023被系统所保留,如果自定义端口号,建议为1023以后的;
注:同一台机器上不能有两个程序使用同一个端口,会冲突;tomcat:8080/80,mysql:3306
URL&URI
URL(Uniform Resource Locator)统一资源定位符,可以直接使用此类找到互联网上的资源如一个简单的网页。一般由:协议名,资源所在主机,端口,资源名等部分组成。如:https://stackoverflow.com/questions/75698432/angular-ngrx-combinelatest-unwanted-emit
URI(Uniform Resource Identifier) 是统一资源标识符,俗称请求资源路径。http://localhost:808/myweb/hello.html
区别:URL包含URI,URI只是URL的一部分
URL类中的常用方法:
URL(String protocol, String host, int port, String file)
URL(String url)
InputStream openStream()
打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream;
public void testURL() throws Exception {
// java要通过URL地址操作网页,可以通过URL对象来操作
// 创建URL的方式有很多种
// 第一种:就是通过网站的URL地址创建URL对象
//URL url = new URL("https://itsource.cn/javaWeb.htm");
// 第二种:就是通过https+ip+端口号+页面地址创建url对象
URL url = new URL("https","itsource.cn",443,"/javaWeb.htm");
// 通过URL对象获取网页的输入流
InputStream openStream = url.openStream();
// 转换为缓冲输入流
BufferedInputStream bis = new BufferedInputStream(openStream);
// 创建缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.html"));
// 创建byte,每次输出1KB
byte[] bytes = new byte[1024];
// 标识符
int let;
while ((let = bis.read(bytes)) != -1) {
bos.write(bytes,0,let);
bos.flush();
}
bos.close();
bis.close();
}
URLEncoder与URLDecoder:
编码与解码,如果有中文的场景,那么可以使用编码解决。
@Test
public void test01() throws Exception {
// 编码与解码主要针对中文,编码必须一致
// URL地址的编码与解码
String str = "www.baidu.com?usernam=源码官网";
// 对URL地址编码
String encode = URLEncoder.encode(str,"UTF-8");
System.out.println(encode);
// 对URL地址解码
String decode = URLDecoder.decode(encode,"UTF-8");
System.out.println(decode);
}
TCP传输控制协议与UDP用户传输协议
TCP协议是Transmission Control Protocol传输控制协议,TCP是一种面向连接的、可靠的、基于字节流的传输层(Transport layer)通信协议。当客户和服务器彼此传递数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据;当客户和服务器彼此交互数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据,TCP 协议使用超时重传、数据确认等方式来确保数据包被正确地发送至目的端,故而效率低,速度慢;
TCP可靠传输协议,不丢包,经常用来传输文件(回值内部处理),缺点是效率低,慢,而且占用资源,相当于打电话;
UDP(User Datagram Protocol)是一种无连接、不可靠、基于数据报的用户数据协议。UDP在传输数据报前不用在客户和服务器之间建立一个连接。它只是把数据报发送出去,但是并不能保证他们能到达目的,并且没有超时重发机制,故而传输速度很快;UDP不可靠传输协议,容易丢包。但是效率高,快,占用资源少。一般游戏中数据采用UDP传输数据,相当于快递;
区别:
- 首先它们都是传输层的协议;
- TCP 协议可靠,UDP 协议不可靠。可靠即指数据由A发送到B,是否能确保数据真的有送达到B;TCP 协议使用超时重传、数据确认等方式来确保数据包被正确地发送至目的端。而 UDP 协议无法保证数据从发送端正确传送到目的端,如果数据在传输过程中丢失或者目的端通过数据检验发现数据错误,则UDP协议只是简单地通知应用程序发送失败。对于 TCP 协议拥有的超时重传、数据确认等需要应用程序自己来处理这些逻辑;
- TCP 是面向连接的,UDP 是无连接的。这也比较好理解,因为 TCP 连接需要经历"三次握手";
- TCP 服务是基于流的,而UDP是基于数据报的,基于流的数据没有边界(长度)限制,而基于数据报的服务,每个UDP数据报都有一个长度,接收端必须以该长度为最小单位将其所有内容一次性读出;
- TCP 协议为应用层提供可靠的、面向连接的、基于流的服务。而 UDP 协议则与 TCP 协议完全相反,它为应用层提供不可靠、无连接和基于数据报的服务;
Socket编程
网络编程实现了客户端与服务端之间的沟通(接收和发送数据),而在网络编程中使用最多的就是Socket,应用程序可以通过它发送或接收数据。像QQ,MSN这些网络应用都使用了Socket技术;
Socket通常称作"套接字",用于描述IP地址和端口。应用程序通常通过"套接字"向网络发出请求或者应答网络请求;Socket是Java实现数据通信的API,而TCP/UPD是通信协议。用Socket可以实现TCP(或者UDP)通信。 但是TCP或者UDP通信也可以不用Socket实现;
Java平台为我们提供了一组强大的类,方便我们使用Socket进行网络程序的开发;Socket和ServerSocket类库位于java.net包中。ServerSocket是服务端套接字,Socket是客户端套接字。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话;
TCP编程
编写步骤:
-
服务端创建ServerSocket;
-
通过调用ServerSocket的accept方法监听客户端的连接;
-
客户端创建Socket并指定服务端的地址以及端口来建立与服务端的连接;
-
当服务端accept发现客户端连接后,获取对应该客户端的Socket;
-
双方通过Socket分别获取对应的输入与输出流进行数据通讯;
-
通讯结束后关闭连接;
// 这是socket的服务器端
public class ServerSocket {
// 像这种有客户端和服务器端的程序,一般都是先启动服务器端,因为必须要进行监听
@Test
public void test() throws IOException {
System.out.println("1111111");
// 根据端口号创建socket服务器端
java.net.ServerSocket serverSocket = new java.net.ServerSocket(8888);
// 服务器端中有个方法,就是会监听客户端的请求,只要客户端请求进来了就会继续执行后面的代码
Socket accept = serverSocket.accept();
System.out.println("22222222");
// 服务器端获取客户端传递的数据
InputStream inputStream = accept.getInputStream();
// 将字节输入流转换为字符缓冲流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// 读取一行
String readLine = bufferedReader.readLine();
// 打印
System.out.println(readLine);
// 发送数据到客户端
OutputStream outputStream = accept.getOutputStream();
outputStream.write("我是服务器端\n".getBytes());
}
}
// 这是socket的客户端
public class ClientSocket {
@Test
public void test() throws IOException {
// 根据IP+端口号连接服务器端
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 从socket中获取输出流,往服务器传传递数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("我是客户端\n".getBytes());
// 获取服务器端传递的数据
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// 此方法是读取一行,他是需要遇到空格才停止,但是我们在发送数据的时候,并没有空格,他就不知道到底需不需要停止
String readLine = bufferedReader.readLine();
System.out.println(readLine);
}
}
HTTP协议
HTTP(超文本传输协议),是利用TCP在两台电脑(通常是Web服务器和客户端)之间传输信息的协议。客户端使用Web浏览器发起HTTP请求给Web服务器,Web服务器发送响应的信息给客户端或浏览器;HTTP协议:主要定义通信规则,基于TCP协议进行封装。浏览器发送请求给服务器,服务器响应数据给浏览器,这整个过程都需要遵守一定的规则。
TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。
HTTP协议是基于TCP之上的,当浏览器须要从server获取网页数据的时候,会发出一次HTTP请求。HTTP会通过TCP建立起一个到server的连接通道。当本次请求须要的数据完成后,HTTP会马上将TCP连接断开,这个过程是非常短的。所以HTTP连接是一种短连接,是一种无状态的连接。所谓的无状态,是指浏览器每次向server发起请求的时候,不是通过一个连接,而是每次都需要建立一个新的连接。
在传输数据时,可以只使用(传输层)TCP/IP协议,但如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等。
注:浏览器给服务器发送数据是一次请求(request)。服务器给浏览器反馈数据是一次响应(response)。
HTTP报文
协议是用来定义数据传输的格式,那么按照一定格式形成的数据包即报文,也可以叫数据报;
HTTP 报文分三个部分:起始行(请求行 – 响应行/状态行),头部(请求头/消息头 – 响应头/消息头),主体(请求体/实体内容 – 响应体/实体内容)。HTTP 报文分为请求报文和响应报文。
-
请求报文
请求方法:也叫请求方式,有很多,后期需要掌握get和post两种即可;
与Http1.0不同(连接一次,请求一次,响应一次。响应完毕,马上断开连接。如果还需要请求,需要重新连接),从HTTP/1.1(连接一次,请求多次,响应多次)起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完毕后。client和server之间用于传输HTTP数据的TCP连接不会关闭,假设client再次访问这个server上的网页,会继续使用这一条已经建立的连接。但Keep-Alive不会永久保持连接。它有一个保持时间。能够在不同的server软件(如Apache)中设定这个时间;
部分消息头:
Accept:告诉服务器能够发送哪些媒体类型;
Referer:告诉服务器该网页是从哪个页面链接过来的;
Accept-Language:告诉服务器能够发送哪些语言;
User-Agent:告诉网站服务器,访问者是通过什么工具来请求的,如果是爬虫请求,一般会拒绝,如果是用户浏览器,就会应答;
Host:HTTP 1.1 协议中新增的一个请求头,主要用来实现虚拟主机技术。同一台服务器部署多个服务,可以依靠虚拟主机来区分,而Host 请求头决定着访问哪个虚拟主机;
Content-type:用于描述该请求来自于表单默认的提交数据的格式(application/x-www-formurlencoded);
Connection:为keep-alive在很多情况下能够重用连接,减少资源消耗,缩短响应时间。所以在HTTP1.1中缺省就是支持keep-alive的;
Content-Length:用于描述HTTP消息实体的传输长度;
Cookie:客户端用它向服务器传送一个令牌。注意它并不是真正的安全首部,但确实隐含了安全功能;
-
响应报文
部分响应头:
Server:服务器类型;
Content-Type:响应的类型;
Date:服务器产生响应的日期;
Transfer-Encoding:传输编码;
状态码:
100~199 – 信息性状态码
200~299 – 成功状态码
300~399 – 重定向状态码
400~499 – 客户端错误状态码
500~599 – 服务器错误状态码
常见的状态码:
200 OK – 处理成功;
302 found – 重定向;
400 Bad Request – 客户端请求有语法错误,不能被服务器所理解;
403 Forbidden – 服务器收到请求,但是拒绝提供服务;
404 Not Found – 请求资源找不到;
500 Internal Server Error – 服务端代码异常;
自定义Web服务器
访问方式是通过file:///C:/Users/123/Desktop/login.html 即是通过文件协议访问本地的login.html 数据;index.html页面都需要放入服务器里面,然后浏览器通过http协议来访问页面,比如:http://ip地址:端口号/login.html来进行访问;如果需要实现这个种效果,需要通过socket可以模拟服务器;
实现思路:首先必须通过socket开启监听端口服务,当在浏览器输入http://localhost:8088/login.html 这个时候就通过socket来接收,找到服务器的login.html页面 ,解析出来,把内容写到浏览器里面。
public class TomcatServer {
@Test
public void test() throws IOException {
// 创建服务器的socket
ServerSocket serverSocket = new ServerSocket(8088);
// 创建监听,如果不想只监听一次,那么可以无限循环监听
while (true) {
// 监听
Socket accept = serverSocket.accept();
System.out.println("访问进入了服务器......");
// 将页面转换为流
File file = new File("src/Demo1.html");
// 根据文件流创建缓冲输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
// 从socket中获取输出流
OutputStream outputStream = accept.getOutputStream();
// 根据file文件创建输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
// 设置响应头
// 设置http协议版本,响应状态码,注意,必须换行,因为每个配置都是单独的
bufferedOutputStream.write("HTTP/1.1 200 OK\n".getBytes());
// 设置编码,以什么格式打开文件
bufferedOutputStream.write("Content-Type: text/html;charset=UTF-8\n".getBytes());
bufferedOutputStream.write("\n".getBytes());
// 一次读1kb
byte[] bytes = new byte[1024];
// 创建标识符
int len = -1;
while ((len = bufferedInputStream.read(bytes)) != -1) {
// 输出数据
bufferedOutputStream.write(bytes, 0, len);
// 刷新
bufferedOutputStream.flush();
}
// 关流
bufferedOutputStream.close();
bufferedInputStream.close();
}
}
}
服务器概述
上述的Web服务器功能比较弱,还有很多功能需要实现,其实我们不需要自己实现,已经有很多三方的Web服务器软件可以直接给我们使用。Tomcat就是其中一个,今天我们就来学习一下,首先Tomcat是一个Web服务器,所以我们先来看一下服务器相关的概念。
常用的Javaweb服务器:
- WebLogic:WebLogic是Oracle公司的产品,是目前应用最广泛的Web服务器,支持JavaEE规范,而且不断的完善以适应新的开发要求
- WebSphere:另一个常用的Web服务器是IBM公司的WebSphere,支持JavaEE规范
- Jboss:大名鼎鼎的红帽的产品,原来属于开源组织Jboss,后被红帽收购。支持JavaEE规范,免费(产品免费,服务收费)
- Tomcat:是一个开源免费,占用内存小的javaWeb服务器,我们要学的就是它
Tomcat相关
Tomcat是一个开源免费的Web服务器,它是 Apache 软件基金会的一个顶级项目,由 Apache,Sun和其他一些公司及个人共同开发而成。Tomcat8 支持最新的 Servlet 3.1 和JSP2.3 规范。Tomcat用java语言开发,Tomcat是一个符合J2EE(Servlet规范)标准的WEB服务器。如果要运行Tomcat,必需要有java的运行环境。
注:在项目部署的时候,Web应用必须选择正确的Web服务器版本,否则可能不能正常运行
修改端口:Tomcat默认端口是8080,很把这个端口进行修改成80,则访问直接可以不用加端口号访问。80端口是为HTTP(HyperText Transport Protocol)即超文本传输协议开放的,是HTTP的默认端口号。配置文件是conf/server.xml。