欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

JavaEE基础第14章网络编程

时间:2023-07-30
第14章网络编程

等到JavaWeb阶段全是网络编程的内容

网络编程概述

一、网络编程中有两个主要的问题:

1.如何准确地定位网络上一台或多台主机;定位主机上的特定应用

2.找到主机后如何可靠高效地进行数据传输

二、网络编程中的两个要素:

1.对于问题一:IP 和 端口号

2.对应问题二:提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)

IP和端口号的理解

三、通信要素一:IP和端口号

1.IP:唯一的标识Internet上的计算机(通信实体)

2.在Java中使用InetAddress类代表IP。一个InetAddress类的对象就表示一个IP地址。

3.IP分类:IPv4 和 IPv6 ; 万维网 和 局域网

4.域名:www.baidu.com www.sina.com

5.本机的回路地址:127.0.0.1 对应着:localhost

6.如何实例化InetAddress:两个方法:getByName(String host)、getLocalHost()、两个常用方法:getHostName() / getHostAddress()

7.端口号:正在计算机上运行的进程。

​ 要求:不同的进程有不同的端口号。

​ 范围:被规定为一个16位的整数 0~ 65535

8.端口号与IP地址的组合得出一个网络套接字:Socket

InetAddress类

InetAddress类实例化,InetAddress类没有对外暴露构造器,将构造器私有化了,需要调用静态方法返回对象。

一个InetAddress类的对象就表示一个IP地址。

InetAddress类没有提供公共的构造器,而是提供了如下几个静态方法来获取InetAddress实例

public static InetAddress getLocalHost()public static InetAddress getByName(String host)

InetAddress提供了如下几个常用的方法

public String getHostAddress():返回 IP 地址字符串(以文本表现形式)。public String getHostName():获取此 IP 地址的主机名public boolean isReachable(int timeout):测试是否可以达到该地址

@Testpublic void test1(){ try { InetAddress inetAddress1 = InetAddress.getByName("220.181.38.251"); System.out.println(inetAddress1); InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com"); System.out.println(inetAddress2); InetAddress inetAddress3 = InetAddress.getByName("127.0.0.1"); System.out.println(inetAddress3); //获取本机的IP地址 InetAddress inetAddress4 = InetAddress.getLocalHost(); System.out.println(inetAddress4); //获取域名 System.out.println(inetAddress2.getHostName()); //获取IP地址 System.out.println(inetAddress2.getHostAddress()); } catch (UnknownHostException e) { e.printStackTrace(); }}

Internet上的主机有两种方式表示地址:

域名(hostName):www.baidu.comIP 地址(hostAddress):220.181.38.251

**InetAddress类主要表示IP地址,**两个子类:Inet4Address、Inet6Address。
InetAddress 类对象含有一个 Internet 主机地址的域名和IP 地址:www.baidu.com 和220.181.38.251。
域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。 -------域名解析

域名解析的过程:

域名解析时会先去寻找本机的hosts文件查看是否有对应的域名IP地址。若没有再提交给DNS(域名服务器)。可以手动在hosts文件中添加域名和IP地址的映射关系。

hosts文件的作用:

其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。对于要经常访问的网站,我们可以通过在Hosts中配置域名和IP的映射关系,提高域名解析速度。由于有了映射关系,当我们输入域名计算机就能很快解析出IP,而不用请求网络上的DNS服务器。清空hosts文件对系统正常运行并没有影响。

在命令提示符下输入ping + 域名可以得到对应的IP地址

端口号补充

端口号标识正在计算机上运行的进程(程序)

不同的进程有不同的端口号被规定为一个 16 位的整数 0~65535。

端口分类:

公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。动态/私有端口:49152~65535。

端口号与IP地址的组合得出一个网络套接字:Socket。

网络通信协议

TCP协议:

使用TCP协议前,须先建立TCP连接,形成传输数据通道传输前,采用“三次握手”方式,点对点通信,是可靠的TCP协议进行通信的两个应用进程:客户端、服务端。在连接中可进行大数据量的传输传输完毕,需释放已建立的连接,效率低

UDP协议:

将数据、源、目的封装成数据包,不需要建立连接每个数据报的大小限制在64K内发送不管对方是否准备好,接收方收到也不确认,故是不可靠的可以广播发送发送数据结束时无需释放资源,开销小,速度快 TCP网络编程例子

TCP网络编程创建Socket对象,指明服务器端的ip和端口号,因为TCP需要先建立连接,所以在创建对象时就需要指明ip和端口号。

先启动服务器端,再启动客户端。

例一、客户端发送内容给服务端,服务端将内容打印到控制台上。

客户端:

1.创建Socket对象,指明服务器端的ip和端口号

2.获取一个输出流,用于输出数据

3.写出数据的操作

4.资源的关闭

服务器端:

1.创建服务器端的ServerSocket,指明自己的端口号

2.调用accept()表示接收来自于客服端的socket

3.获取输入流

4.获取输入流中的数据

5.资源的关闭

注意:套接字socket也需要关闭;熟悉使用ByteArrayOutputStream,理解其底层原理。理解出现乱码的原因。

//客户端 @Test public void client(){ Socket socket = null; OutputStream outputStream = null; try { //1.创建Socket对象,指明服务器端的ip和端口号 InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); socket = new Socket(inetAddress,8899); //2.获取一个输出流,用于输出数据 outputStream = socket.getOutputStream(); //3.写出数据的操作 outputStream.write("你好我是客户端".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { //4.资源的关闭 try { if (outputStream != null) outputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) socket.close();//socket套接字也需要关闭 } catch (IOException e) { e.printStackTrace(); } } } //服务器端 @Test public void server(){ ServerSocket serverSocket = null; Socket socket = null;//接收 InputStream inputStream = null; ByteArrayOutputStream bas = null; try { //1.创建服务器端的ServerSocket,指明自己的端口号 serverSocket = new ServerSocket(8899); //2.调用accept()表示接收来自于客服端的socket socket = serverSocket.accept(); //3.获取输入流 inputStream = socket.getInputStream(); //采用ByteArrayOutputStream byte[] buffer = new byte[20]; int len; //4.获取输入流中的数据 bas = new ByteArrayOutputStream(); while ((len = inputStream.read(buffer)) != -1){ bas.write(buffer,0,len); } System.out.println(bas.toString());//转换要放在循环外 System.out.println("收到了来自:" + socket.getInetAddress().getHostAddress() + "的数据"); } catch (IOException e) { e.printStackTrace(); } finally { //5.资源的关闭 try { if (bas != null) bas.close(); } catch (IOException e) { e.printStackTrace(); } try { if (inputStream != null) inputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } try { if (serverSocket != null) serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }

例二、客户端发送文件给服务端,服务端将文件保存在本地。

@Test public void client1() { Socket socket = null; OutputStream os = null; FileInputStream fis = null; try { //1.创建Socket对象,指明服务器端的ip和端口号 socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090); //2.获取一个输出流,用于输出数据 os = socket.getOutputStream(); //3.获取一个输入流,实现从哪个文件读数据 fis = new FileInputStream("图片1.jpg"); //4.具体实现步骤 byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //5.资源关闭 try { if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); } try { if (os != null) os.close(); } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } @Test public void server1(){ ServerSocket ss = null; Socket socket = null; InputStream is = null; FileOutputStream fos = null; try { //1.创建服务器端的ServerSocket,指明自己的端口号 ss = new ServerSocket(9090); //2.调用accept()表示接收来自于客服端的socket socket = ss.accept(); //3.获取输入流 is = socket.getInputStream(); //4.将数据写入本地 fos = new FileOutputStream("图片4.jpg"); //5.实现步骤 byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1){ fos.write(buffer,0,len); } } catch (IOException e) { e.printStackTrace(); } finally { //6.关闭资源 try { if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (is != null) is.close(); } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } try { if (ss != null) ss.close(); } catch (IOException e) { e.printStackTrace(); } } }

例三:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。并关闭相应的连接。

学习服务器端是怎么给客户端反馈的。客户端在数据传输完毕后需要调用shutdownOutput()方法告诉服务器端数据传输完毕。

@Test public void client2() { Socket socket = null; OutputStream os = null; FileInputStream fis = null; InputStream is = null; ByteArrayOutputStream bas = null; try { //1.创建Socket对象,指明服务器端的ip和端口号 socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090); //2.获取一个输出流,用于输出数据 os = socket.getOutputStream(); //3.获取一个输入流,实现从哪个文件读数据 fis = new FileInputStream("图片1.jpg"); //4.具体实现步骤 byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } //关闭数据的输出 socket.shutdownOutput(); //5.接收来自服务器端的反馈。必须在关闭连接之前接收 is = socket.getInputStream(); bas = new ByteArrayOutputStream(); byte[] buffer1 = new byte[1024]; int len1; while ((len1 = is.read(buffer1)) != -1){ bas.write(buffer1,0,len1); } System.out.println(bas.toString()); } catch (IOException e) { e.printStackTrace(); } finally { //6.资源关闭 try { if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); } try { if (os != null) os.close(); } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } try { if (bas != null) bas.close(); } catch (IOException e) { e.printStackTrace(); } try { if (is != null) is.close(); } catch (IOException e) { e.printStackTrace(); } } } @Test public void server2(){ ServerSocket ss = null; Socket socket = null; InputStream is = null; FileOutputStream fos = null; OutputStream os = null; try { //1.创建服务器端的ServerSocket,指明自己的端口号 ss = new ServerSocket(9090); //2.调用accept()表示接收来自于客服端的socket socket = ss.accept(); //3.获取输入流 is = socket.getInputStream(); //4.将数据写入本地 fos = new FileOutputStream("图片4.jpg"); //5.实现步骤 byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1){ fos.write(buffer,0,len); } //6.服务器端给予客户端反馈 //这时候这个socket已经是接收到的从客户端发送过来的socket了,就是要给这个客户端反馈的 os = socket.getOutputStream(); os.write("照片已经收到!".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { //7.关闭资源 try { if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (is != null) is.close(); } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } try { if (ss != null) ss.close(); } catch (IOException e) { e.printStackTrace(); } try { if (os != null) os.close(); } catch (IOException e) { e.printStackTrace(); } } }

IO流中read()是一个阻塞式的方法,就是如果没有明确告诉传输完毕那么就不会退出循环。比如读取一个文件时,读到文件末尾返回值为-1,说明传输完毕,但是在网络编程中,客户端什么时候才算传完呢。如果客户端关闭了,说明客户端传输完毕,但是现在客户端还在等待服务器端的反馈,因此客户端还没有进行关闭,所以必须想一个办法告诉服务器端客户端已经传输完成,这样才能退出循环,否则一直在循环中,程序无法继续执行。仅需在客户端调用shutdownOutput()方法告诉服务器端数据传输完毕。

而在 NIO 中就是非阻塞式了,功能更强大,等学习到框架时会细说。

配置Tomcat

Tomcat配置,使用等到JavaWeb细讲。

UDP网络编程例子

UDP需要创建DatagramSocket对象,此时不需要指明ip和端口号,因为UDP是不可靠连接,ip和端口号放在数据报中。

//UDP网络编程例子 @Test public void sender(){ DatagramSocket socket = null; try { socket = new DatagramSocket(); String str = "我是UDP"; byte[] buffer = str.getBytes(); InetAddress localAddress = InetAddress.getLocalHost(); DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length,localAddress,9090); socket.send(packet); } catch (IOException e) { e.printStackTrace(); } finally { if (socket != null) socket.close(); } } @Test public void receiver(){ DatagramSocket socket = null; try { socket = new DatagramSocket(9090); byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length); socket.receive(packet); System.out.println(new String(packet.getData(),0,packet.getLength())); } catch (IOException e) { e.printStackTrace(); } finally { if (socket != null) socket.close(); } }

URL网络编程

1.URL:统一资源定位符,对应着互联网的某一资源地址

2.格式:

http://localhost:8080/examples/beauty.jpg?username=Tom

协议 主机名 端口号 资源地址 参数列表

@Test public void test2() throws MalformedURLException { URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom"); System.out.println(url.getProtocol());//获取该URL的协议名 System.out.println(url.getHost());//获取该URL的主机名 System.out.println(url.getPort());//获取该URL的端口号 System.out.println(url.getPath());//获取该URL的文件路径 System.out.println(url.getFile());//获取该URL的文件名 System.out.println(url.getQuery());//获取该URL的查询名 }

URL网络编程实现从Tomcat服务器端下载数据

这里只是简单用一下,实际上并不会这么操作。在JavaWeb中会讲从浏览器端下载数据。

把Tomcat服务器启动起来,相应的文件资源放在对应的目录下,运行程序即可完成下载。(实际开发中不会用这样的)

@Test public void test3() { HttpURLConnection urlConnection = null; InputStream is = null; FileOutputStream fos = null; try { URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom"); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.connect();//获取与服务器端的连接 is = urlConnection.getInputStream(); fos = new FileOutputStream("beauty.jpg"); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (is != null) is.close(); } catch (IOException e) { e.printStackTrace(); } if (urlConnection != null) urlConnection.disconnect(); } }

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。