Java学习笔记 10、网络编程

简介: Java学习笔记 10、网络编程

一、网络编程概述


1、什么是网络编程


Java是Internet上的语言,从语言级别上提供了网络应用程序的支持,通过java.net网络功能包,能够很容易的开发网络应用程序。


联网的底层细节被隐藏在Java的本机安装系统里,由JVM进行控制。并且Java实现了一个跨平台的网络库,相当于程序员面对的是一个统一的网络编程环境。


说是说给我们提供了网络功能包,但是对于网络一些基础知识应该是在要知晓并且了解的,负责碰到实际一些麻烦时若是没有一些基础会找不到问题源头所在。


计算机网络:将分布在不同地理区域的计算机与专门的外部设备用通信线路互连城一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源。


网络编程目的:直接或间接地通过网络协议与其他计算机实现数据交换,进行通讯。



2、网络通信要素


认识网络通信协议

问题描述


问题1:如何准确定位网络上一台或多太主机;定位主机上的特定应用?


通过IP地址与端口号

问题2:找到主机后如何进行可靠高效的数据传输?


提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理层以及数据链路层)

网络通信也可以称为socket通信或者socket编程。



认识一下网络通信协议


对于网络通信协议有两套参考模型:


OSI参考模型:模型过于理想化,未在因特网上广泛推行。

TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

网络通信协议对速率、传输代码、代码结构、传输控制步骤以及出错控制等制定标准。


网络通信涉及内容很多,例如指定源地址和目标地址、加密节目,压缩加压,差错控制,流量控制,路由控制,那么这么多内容如何更好的处理呢?


将通信协议分层,即同层间可以通信、上一层可以调用下一层,并且与下一层不发生关系,各层互不影响便于系统开发与扩展。

分层如下图:



对于传输的数据在不同层也进行了封装:




要素1:IP地址和端口号

知识补充

①IP地址(InetAddress):唯一标识Internet的计算机。


分类一:IPV4和IPV6

IPV4:4个字节组成,4个0-255,大概42亿个,北美有30亿,亚洲4亿,在2011年初已经用尽,例如192.168.0.1

IPV6:16个字节,写成8个无符号整数,每个整数用四个十六进制来表示,例如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984。(冒号隔开)

分类2:公网地址(万维网使用)和私有地址(局域网使用)。例如192.168.开头就是私有地址,范围为192.168.0.0-192.168.255.255。

本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost


②TCP端口:只是一个16位宽、用来识别服务器上特定程序的数字。


网页服务器(8080),Telnet(23),POP3邮件服务器(110),SMTP邮局交换服务器(25),Tomcat(8080),Mysql(3306),Oracle(1521)。

每个服务器上都有65536个端口(0-65535)

0-1023的TCP端口号是保留给已知的特定服务器使用,不应该使用这个范围的,若是我们自己使用的话一般在1024-65535这个范围。

不同程序无法使用同一个端口,若是想要使用(称绑定)会受到BindException。。


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


通过Socket进行连接,Socket是个代表两台机器之间网络连接的对象(java.net.Socket),我们不需要在乎低层的细节,因为这是在底层的网络设备中处理掉的。这种 网络设备是一种让运行在Java虚拟机上的程序能够找到方法去通过实际的硬件(如网卡)在机器之间传送数据的机制。


这部分由操作系统的特定部分以及Java的网络API所组成,我们只需要考虑高层的部分。


认识InetAddress类

在Java中使用InetAddress类来代表IP地址,查看一下实例化方法:



比较常用的是getByName(String host)、getLocalhost()

并且这里列举两个常用方法:


getHostAddress():获取主机地址
getHostName():获取主机域名
@Test
public void test01() throws UnknownHostException {
    //获取实例方法1:返回回送地址
    InetAddress ip = InetAddress.getLoopbackAddress();
    System.out.println(ip);//localhost/127.0.0.1
    //获取实例方法2:通过输入主机名获取id地址 涉及到DNS解析
    InetAddress ip1 = InetAddress.getByName("www.baidu.com");
    System.out.println(ip1);//www.baidu.com/36.152.44.95
    //使用两个常用方法分别获取主机名以及ip地址
    System.out.println(ip1.getHostName());//www.baidu.com
    //获取原始ip地址
    System.out.println(ip1.getAddress());//[B@621be5d1
    System.out.println(ip1.getHostAddress());//36.152.44.95
}



要素2:网络协议

网络协议有很多很多,对于不同层也有不同的协议。


传输层两个重要的协议:


传输控制协议TCP(Transmission Control Protocal)

使用该协议前需要建立TCP连接,采用三次握手方式(可靠的),形成传输数据通道之后进行大数据量传输,传输完毕之后还有四次挥手来中断连接。安全,但是效率低。

TCP 协议可以解决数据在传送过程中的丢失、损坏、重复、乱序以及网络 拥挤等问题,它保证数据可靠的传送。

用户数据报协议UDP(User Datagram Protocal)

直接将数据、源、目的封装成数据包发送过去,不需要进行连接,直接发送。每个数据包大小限制在64K内,发送数据结束后也无需释放资源,开销小速度快,但是不安全,容易丢失。

TCP场景:打电话


UDP场景:发送短信,发电报



二、TCP网络编程


例题一:创建客户端与服务端实现发送与接收

客户端:


//客户端
@Test
public void test01() {
    //首先创建ip地址实例
    InetAddress ip = InetAddress.getLocalHost();
    //创建socket实例,添加一个目标端口
    try(Socket socket = new Socket(ip, 8899);
        OutputStream os = socket.getOutputStream();){
        //发送数据,通过写入字节传输
        os.write("服务端你好,我是客户端".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
}


创建Socket实例(包含ip地址以及端口号),接着使用getOutputStream()获取到其中的输出流,直接使用write()写入想要传的字符串即可发送过去。


服务端:


//服务端
@Test
public void test02(){
    try( //创建ServerSocket用来接收Socket
         ServerSocket ss = new ServerSocket(8899);
         //accept()方法会在等待用户的Socket连接时闲置下来,一旦用户连接,会返回一个Socket来方便通信
         Socket socket = ss.accept();
         InputStream is = socket.getInputStream();
         //通过这个字节数组输出流来获取传入过来的字节
         ByteArrayOutputStream baos = new ByteArrayOutputStream();){
        //进行读取数据
        byte[] data = new byte[20];
        int len;
        while((len = is.read(data))!=-1){
            baos.write(data,0,len);
        }
        //打印出输入到该流中的内容
        System.out.println("接收到主机名:"+socket.getInetAddress().getHostName()+
                ",ip地址为"+socket.getInetAddress().getHostAddress()+" 接收内容如下:");
        System.out.println(baos.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}


创建ServerSocket实例,指定开放的端口,通过accept()方法等待接收Socket数据包。

通过ByteArrayOutputStream来存储从Socket中读出的数据,创建ByteArrayOutputStream不需要指定节点流,获取读出的字节内容直接使用toString()方法即可。

先启动服务端,之后启动客户端发送数据包:




例题二:客户端发送一张图片到服务器端

思路:客户端使用FileInputStream来读取本地的图片字节,之后通过指定的IP地址与端口号的Socket将数据传输出去,服务端使用FileOutputStream从ServiceSocket中的Socket读取传来的数据直接保存到本地。


客户端:


//客户端
@Test
public void test01() {
    InetAddress ip = InetAddress.getLocalHost();
    try( Socket socket = new Socket(ip, 8899);
         //获取输入流
         OutputStream os = socket.getOutputStream();
         //读取本地文件
         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1234.jpg"));){
        byte[] data = new byte[1024];
        int len;
        while((len = bis.read(data))!=-1){
            //发送字节
            os.write(data,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}



服务端:


//服务端
@Test
public void test02(){
    try( //创建ServerSocket用来接收Socket
         ServerSocket ss = new ServerSocket(8899);
         //accept()方法会在等待用户的Socket连接时闲置下来,一旦用户连接,会返回一个Socket来方便通信
         Socket socket = ss.accept();
         InputStream is = socket.getInputStream();
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("changlu.jpg"));){
        //进行读取数据
        byte[] data = new byte[20];
        int len;
        while((len = is.read(data))!=-1){
            bos.write(data,0,len);
        }
        //打印出输入到该流中的内容
        System.out.println("接收到主机名:"+socket.getInetAddress().getHostName()+
                ",ip地址为"+socket.getInetAddress().getHostAddress()+"发送的图片");
    } catch (IOException e) {
        e.printStackTrace();
    }
}



这里使用了缓冲流来处理文件流。

例题三:客户端发送数据到服务端,服务端再返回数据到客户端

与上面例2有些相同,只不过多了一些做的内容,本题在接收到数据之后还要重新发送数据到客户端,客户端也要进行接收,接下来看下面的演示,主要是-------------下内容。


客户端:


//客户端
@Test
public void test01() {
    InetAddress ip = InetAddress.getLocalHost();
    try( Socket socket = new Socket(ip, 8899);
         //获取输入流
         OutputStream os = socket.getOutputStream();
         //读取本地文件
         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1234.jpg"));){
        byte[] data = new byte[1024];
        int len;
        while((len = bis.read(data))!=-1){
            //发送字节
            os.write(data,0,len);
        }
        System.out.println("客户端已成功发送图片");
        //-----------------------------------
        //主要来接收服务端收到我们照片后发来信息
        //首先禁用此套接字的输出流,之后进行读取操作
        socket.shutdownOutput();
        InputStream is = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        data = new byte[1024];
        len = 0;
        while((len = is.read(data)) != -1){
            baos.write(data,0,len);
        }
        System.out.println("接收到服务端发送的数据为:"+baos.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}


关键部分是21行的socket.shutdownOutput();是关闭输出流,如果不手动关闭的话会有阻塞问题,如下



服务端:


//服务端
@Test
public void test02(){
    try( //创建ServerSocket用来接收Socket
         ServerSocket ss = new ServerSocket(8899);
         //accept()方法会在等待用户的Socket连接时闲置下来,一旦用户连接,会返回一个Socket来方便通信
         Socket socket = ss.accept();
         InputStream is = socket.getInputStream();
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("changlu.jpg"));){
        //进行读取数据
        byte[] data = new byte[20];
        int len;
        while((len = is.read(data))!=-1){
            bos.write(data,0,len);
        }
        //打印出输入到该流中的内容
        System.out.println("接收到主机名:"+socket.getInetAddress().getHostName()+
                ",ip地址为"+socket.getInetAddress().getHostAddress()+"发送的图片");
        //------------------------------------
        //发送数据到客户端
        //获取到数据流
        OutputStream os = socket.getOutputStream();
        os.write("服务端已接收到图片,感谢你的分享!".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
}


这里当图片数据读取之后可以直接获取Socket的输出流,再通过输出流write()即可发送数据了。


服务端—Tomcat

服务器处理流程:针对于jsp


客户端请求 —> tomcat服务器 -->java程序 —>返回相对应的html(前后端没有分离返回的是html,分离了就返回json数据结构)


**介绍:**服务器实际上就是已经使用代码编写号的一个可以根据浏览器发送的请求到本地服务器并调用执行对应逻辑代码的容器。我们只需要安装服务器到本地并将事先编写好的处理业务逻辑请求的代码放置到服务器指定位置。服务器一旦启动就能够根据接收到的请求来执行指定的逻辑代码。


之后我们会使用servlet来处理业务逻辑。



三、UDP网络编程


认识UDP的相关类

UDP是直接发送数据,不需要与服务端进行连接的,使用UDP编程的话,java也有相应的API可供调用使用,一般使用DatagramSocket与DatagramPacket搭配并使用send()与receive()方法进行发送与接收。


相对于TCP编程不同点介绍:


作为发送端DatagramSocket是无参构造器,而DatagramPacket的构造器中则需要填入指定内容的字节数组、长度、ip地址以及端口号。

作为接收端DatagramSocket需要确定端口号,DatagramPacket仅仅填入字节数组与长度

两个类介绍:


DatagramSocket:数据报包,用于实现无连接分组传送服务,下面是常用方法


public InetAddress getLocalAddress():获取套接字绑定的本地地址。

public int getLocalPort():返回此套接字绑定的本地主机上的端口号。

public InetAddress getInetAddress():返回此套接字连接的地址。如果套接字未连接,则返回 null。

public int getPort():返回此套接字的端口。如果套接字未连接,则返回 -1。

DatagramSocket:发送与接收数据报数据包的套接字,下面是常用方法


public InetAddress getAddress():返回某台机器的 IP 地址,此数据报将要发往该 机器或者是从该机器接收到的。

public int getPort():返回某台远程主机的端口号,此数据报将要发往该主机或 者是从该主机接收到的。

public byte[] getData():返回数据缓冲区。接收到的或将要发送的数据从缓冲区 中的偏移量 offset 处开始,持续 length 长度。

public int getLength():返回将要发送或接收到的数据的长度。


小案例

描述:使用UDP来发送指定内容的数据包到接收端,打印出来。


发送端:


//发送端
@Test
public void test01() {
  //创建一个空参的DatagramSocket实例
    try(DatagramSocket ds = new DatagramSocket();){
        byte[] data = "我是UDP传来的数据包".getBytes();
        //创建数据包 待发出的字节数组、发送数据包长度,InetAddress实例,端口号
        DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 8899);
        //发送数据包
        ds.send(packet);
    }catch (IOException e) {
        e.printStackTrace();
    }
}


直接将数据放置到DatagramPacket实例中,并用DatagramSocket的send()发送数据包


接收端:


//接收端
@Test
public void test02(){
    //创建实例时需要指定端口
    try(DatagramSocket ds = new DatagramSocket(8899);){
        byte[] data = new byte[1024];
        //这里需要填入一个字节数组用于等会进行接收,还有作为接收的长度
        DatagramPacket packet = new DatagramPacket(data, data.length);
        //进行接收,需要数据包作为参数之后将数据放置到其中
        ds.receive(packet);
        //使用ds.getData()方法获取字节数组,之后转为字符串打印输出
        System.out.println(new String(packet.getData(),0,packet.getData().length));
    } catch (IOException e) {
        e.printStackTrace();
    }
}


我们需要拿到客户端发送的数据包内容那么就需要使用DatagramSocket实例的receive()方法,注意其中需要有一个DatagramPacket实例来进行接收数据。

如何拿到包中的数据呢?调用DatagramPacket的getData()即可拿到传输过来的字节。

**注意:**UDP编程与TCP编程最大的不同就是TCP需要开启服务端之后再进行发送端发送,才能够顺利进行;UDP是直接发送数据过去,速度快但是并不稳定安全,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。



四、URL编程、


1、认识URL及URL类

了解一下URL


URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上某一资源的地址。


URL不仅用来标识一个资源,还指名了如何locate(定位)这个资源。

通过URL我们可以访问Internet上的各种网络资源,例如最常见的www,ftp站点。

浏览器通过解析指定的URL可以在网络上查找相应的文件及资源。

URL基本组成(5部分):<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表


#表示指定锚点,用于当前页面的指定部分。

参数列表:表示传递的参数


认识URL类


通过URL对象可以创建当前应用程序和 URL 表示的网络资源之 间的连接,这样当前程序就可以读取网络资源数据,或者把自己的数据传送到网络上去


在java中使用URL类来表示URL,我们通过构造器来创建实例,其实例会抛出异常:


public URL (String spec):通过一个表示URL地址的字符串可以构造一个URL对象

例如:URL url = new URL (“http://www. atguigu.com/”);

public URL(URL context, String spec):通过基 URL 和相对 URL 构造一个 URL 对象

例如:URL downloadUrl = new URL(url, “download.html")

public URL(String protocol, String host, String file);:通过协议,主机名及指定页面

例如:URL down = new URL(“http”, “www.atguigu.com”, “download. html");

public URL(String protocol, String host, int port, String file); :通过协议,主机名、端口号、指定页面

例如:URL gamelan = new URL(“http”, “www.atguigu.com”, 80, “download.html");

URL实例方法:


public String getProtocol( ):获取该URL的协议名

public String getHost( ):获取该URL的主机名

public String getPort( ):获取该URL的端口号

public String getPath( ):获取该URL的文件路径

public String getFile( ):获取该URL的文件名

public String getQuery( ):获取该URL的查询名

实操一下:


//客户端
@Test
public void test01() throws MalformedURLException {
    URL url = new URL("https://www.baidu.com/");
    System.out.println("Protocol():"+url.getProtocol());
    System.out.println("getHost():"+url.getHost());
    System.out.println("getPort():"+url.getPort());
    System.out.println("getPath():"+url.getPath());
    System.out.println("getFile():"+url.getFile());
    System.out.println("getQuery():"+url.getQuery());
}




2、针对Http协议的URLConnection类

若我们想向服务器发送一些数据,例如向服务器端的CGI(公共网关接口-Common GatewayInterface,是用户浏览器与服务器端的应用程序连接的接口)数据,我们就需要与URL建立连接,之后才能进行读写操作,那么就需要使用URLConnection。


URLConnection类:表示到URL所引用的远程对象连接。当我们实例化URL建立连接时,首先要在URL对象上通过方法openConnection()生成对应的URLConnection对象。


通过该对象来获取输入流与输出流,与服务器端的CGI程序进行交互。

相关方法:


public void connect():若是调用时尚未与url连接,那么打开与此URL引用的资源通信链接。

public Object getContent( ) throws IOException:检索此url连接的内容。

public int getContentLength( ):返回content-encoding标题字段的值。

public String getContentType( ):返回content-type标题字段的值。

public long getDate( ):取到date字段的值。

public long getLastModified( ):取得last-modified的值。

public InputStream getInputStream( )throws IOException:获得打开连接的读取输入流。

public OutputSteram getOutputStream( )throws IOException:获取写入此连接的输出流。


小案例

下载指定url的图片:


@Test
public void test01() throws IOException {
    URL url = new URL("https://pics7.baidu.com/feed/fc1f4134970a304ec448a9204a685981c8175c2e.jpeg?token=b8477ffbb8442bf478c2a6cfeeefc62a&s=FCCB905416190DD0962277900300D09C");
    //获取URLConnection实例
    URLConnection conn = url.openConnection();
    //进行连接
    conn.connect();
    //获取连接的输入流
    InputStream is = conn.getInputStream();
    //创建字节缓冲流包裹文件输出流
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("upload.jpg"));
    //读取操作
    byte[] data = new byte[1024];
    int len;
    while((len = is.read(data))!=-1){
        bos.write(data,0,len);
    }
}


将指定url地址的图片下载到本地。


参考资料


[1]. 尚硅谷-Java30天基础-网络编程(宋红康)

相关文章
|
5天前
|
存储 监控 安全
单位网络监控软件:Java 技术驱动的高效网络监管体系构建
在数字化办公时代,构建基于Java技术的单位网络监控软件至关重要。该软件能精准监管单位网络活动,保障信息安全,提升工作效率。通过网络流量监测、访问控制及连接状态监控等模块,实现高效网络监管,确保网络稳定、安全、高效运行。
32 11
|
1月前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
63 9
|
1月前
|
人工智能 Java 物联网
JAVA网络编程的未来:URL与URLConnection的无限可能,你准备好了吗?
随着技术的发展和互联网的普及,JAVA网络编程迎来新的机遇。本文通过案例分析,探讨URL与URLConnection在智能API调用和实时数据流处理中的关键作用,展望其未来趋势和潜力。
46 7
|
2月前
|
Ubuntu 网络安全 图形学
Ubuntu学习笔记(二):ubuntu20.04解决右上角网络图标激活失败或者消失,无法连接有线问题。
在Ubuntu 20.04系统中解决网络图标消失和无法连接有线网络问题的方法,其中第三种方法通过检查并确保Windows防火墙中相关服务开启后成功恢复了网络连接。
751 0
Ubuntu学习笔记(二):ubuntu20.04解决右上角网络图标激活失败或者消失,无法连接有线问题。
|
1月前
|
网络协议 Java 物联网
Java网络编程知识点
Java网络编程知识点
43 13
|
1月前
|
Java 开发者
JAVA高手必备:URL与URLConnection,解锁网络资源的终极秘籍!
在Java网络编程中,URL和URLConnection是两大关键技术,能够帮助开发者轻松处理网络资源。本文通过两个案例,深入解析了如何使用URL和URLConnection从网站抓取数据和发送POST请求上传数据,助力你成为真正的JAVA高手。
64 11
|
1月前
|
安全 Java API
深入探索Java网络编程中的HttpURLConnection:从基础到进阶
本文介绍了Java网络编程中HttpURLConnection的高级特性,包括灵活使用不同HTTP方法、处理重定向、管理Cookie、优化安全性以及处理大文件上传和下载。通过解答五个常见问题,帮助开发者提升网络编程的效率和安全性。
107 9
|
1月前
|
JSON 安全 算法
JAVA网络编程中的URL与URLConnection:那些你不知道的秘密!
在Java网络编程中,URL与URLConnection是连接网络资源的两大基石。本文通过问题解答形式,揭示了它们的深层秘密,包括特殊字符处理、请求头设置、响应体读取、支持的HTTP方法及性能优化技巧,帮助你掌握高效、安全的网络编程技能。
66 9
|
1月前
|
JSON Java API
JAVA网络编程新纪元:URL与URLConnection的神级运用,你真的会了吗?
本文深入探讨了Java网络编程中URL和URLConnection的高级应用,通过示例代码展示了如何解析URL、发送GET请求并读取响应内容。文章挑战了传统认知,帮助读者更好地理解和运用这两个基础组件,提升网络编程能力。
55 5
|
2月前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
31 1
下一篇
DataWorks