IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> java网络编程 -> 正文阅读

[网络协议]java网络编程

1.计算机网络入门

1.软件架构mspaint

  • C/S结构:全称为Client/Server,是指客户端和服务器的结构,常见的有QQ,百度网盘等
    在这里插入图片描述

  • B/S结构:全称为Browser/Server结构,是指浏览器和服务器的结构,常见的有谷歌,火狐,IE等

两种架构各有优势,但无论使用那种架构,都离不开网络的支持,网络编程,再一定的协议下,实现两台计算机通信的程序。

2.网络通信协议

网络通信协议: 通过计算机网络可以使很多太计算机实现互联,位于同一个网络的计算机进行连接和通信时,需要遵守一定的规则,,再计算机网络张志宏,这些连接和通信的规则成为网络通信协议,它对数据传输格式,传输速率,传输步骤等做了同一的规定,通信双方必须同时遵守才能完成数据的交换。

TCP/IP协议:传输控制协议:因特网互联网(Transmission Control Protocol/Internet Protocol)是Internet最基本,最广泛的协议,它定义了计算机如何连入因特网,以及数据如何在他们之间传输的标准,它的内部包含了一系列的用户数据通信协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。

在这里插入图片描述

上图中:TCP/IP协议四川分别是:应用层,传输层,网络层,数据链路层,每层负责不同的通信功能。

数据链路层:数据链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如:针对光纤,网线提供的驱动

网络层:网络层是整个TCP/IP协议的核心,它主要用于传输的数据进行分组,将分组的数据发生到目标计算机或者网络

传输层:主要使用网络程序进行通信,在信息网络通信时,可以采用TCP协议也可以采用UDP协议

应用层:应用层主要负责应用程序的协议,例如HTTP协议,FTP协议等…

我们编写的程序位于应用层,因此我们的程序是和TCP/UDP打交道的。

通信协议分层思想

1.为什么要分层

由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式就是层次方式,及同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

2.通信协议的分层规定

把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。

3.协议的分类

通信的协议还是比较复杂的,java.net 包中的类和接口,他们提供底层次的通信细节,我们可以使用这些类和接口,来专注网络程序的开发,而不用考虑通信的细节。

java.net包提供了常见的网络协议支持:

  • UDP:用户数据报协议(User Datagram Protocol0),UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会去确认接收端是否存在,就会发送数据,同样接收端在接收到数据时,也不会向发送端反馈自己是否接收到数据。

    由于使用UDP协议消耗资源比较小,通信效率比较高,所以通常都会用于音频,视频和普通数据的传输,例如视频会议都会使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对结果产生太大的影响。

    但是在使用UDP协议传输数据时,由于UDP的面向无连接性,不能保证数据的完整性,所以在传输重要数据时,不建议使用UDP协议,UDP的交换过程如下:

在这里插入图片描述

特点:数据传输被限制在64kb之内,超出这个范围就不能发送了。

  • TCP:传输控制协议(Transmission Control Protocol)TCp协议是面向连接的协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之前的可靠无差错性的数据传输。

    再TCP连接中必须要明确客户端与服务器端,由客户端向服务器发送连接请求,每次连接的创建都需要经过三次握手。

  • 三次握手:TCP协议中,在发送数据的准备阶段,客户端和服务端之间的三次交互,以保证连接的可靠性。

    • 第一次握手:客户端向服务器端发出连接请求,等待服务端确认
    • 第二次握手:服务器端向客户端发送一个响应,通知客户端自己手动了连接请求
    • 第三次握手:客户端再次向服务器端发送确认信息,确认连接,整个连接交互过程如下:

在这里插入图片描述

完成三次握手之后,客户端就可以向服务端发送数据了,由于这种面向连接的特性,TCP协议可以保证数据的安全性,所以应用十分广泛,例如:文件的下载,网页的浏览。

四次挥手:

其次,TCP的客户端和服务端断开连接,需要四次挥手

在这里插入图片描述

1.客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。

2.服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。

3.客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。

4.等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。

5.客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态

6.服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。

7.客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态。

为什么挥手需要四次?
关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。

4.网络编程的三要素

1.协议: 计算机网络必须遵守的通信规则

2.IP地址: 指互联网协议地址(Interternet Proctocol Address)俗称IP地址,IP地址给一个网络中的计算机设备做唯一的编号

IP地址的分类:

  • IPV4:是一个32位的二进制数,通常被分为4个自己,表示成a,b,c,d的形式 例如192.168.75.44.其中a,b,c,d都是0-255之间的十进制整数,那么最多可以表示42亿个。

  • IPV6:由于互联网的飞速发展,IP的需求的越来越大,但是由于IP地址的资源有限,使得IP地址的分配越来越紧张,为了扩大地址空间,通过IPV6重新定义地址空间,采用128地址长度,每16个字节为一组,分成8组十六进制数

    表示成:fe80::10ec:a136:b433:6ec2%5,号称可以为全世界每一粒沙子都可以编上一个IP地址,这样就解决了网络地址资源数量不够的问题。

    windows查看本机的ip地址:ipconfig

    windows检查网络是否联通:ping IP地址(域名) 例如:ping baidu.com

    特殊的IP地址:127.0.0.1 本机域名:localhost

Pv4又可以分为五类:

img

端口号:使用两个字节表示数据,它的取值范围是0-65535,其中0-1024之间的端口号,用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号,如果端口号被另外一个服务或应用所占用,会导致单前程序启动失败。

利用 协议+IP地址+端口号,就可以标识网络中的进程了,那么进程之间的通信就可以利用这个标识与其它的进程所进行交互

A类:在IP地址的四段号码中,第一段号码为网络号码,剩下的三段号码为本地计算机的号码;A类IP地址中网络的标识长度为8位,主机标识的长度为24位,A类网络地址数量较少,有126个网络,每个网络可以容纳主机数达1600多万(256的三次方-2)台。

B类:在IP地址的四段号码中,前两段号码为网络号码。B类IP地址中网络的标识长度为16位,主机标识的长度为16位,B类网络地址适用于中等规模的网络,有16384个网络,每个网络所能容纳的计算机数为6万多(256的二次方-2)台

C类:在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码;此类地址中网络的标识长度为24位,主机标识的长度为8位,C类网络地址数量较多,有209万余个网络。适用于小规模的局域网络,每个网络最多只能包含254(256-2)台计算机

D类:此类IP地址在历史上被叫做多播地址(multicast address),即组播地址;在以太网中,多播地址命名了一组应该在这个网络中应用接收到一个分组的站点;多播地址的最高位必须是“1110”,范围从224.0.0.0到239.255.255.255

E类: 此类地址也不分网络地址和主机地址,它的第1个字节的前五位固定为“11110”,为将来使用保留,地址范围从240.0.0.1到255.255.255.254

InetAddress类:说到IP地址,就要引入一个类:InetAddress, 此类表示互联网协议 (IP) 地址

在这里插入图片描述

InetAddress类无构造方法

1.常用方法摘要

byte[] getAddress() :返回此 InetAddress 对象的原始 IP 地址。

static InetAddress getByName(String host):在给定主机名的情况下确定主机的 IP 地址。

String getHostAddress():返回 IP 地址字符串(以文本表现形式)。

String getHostName():获取此 IP 地址的主机名。

static InetAddress getLocalHost():返回本地主机。

127.0.0.1:本机地址,主要用于测试。别名:Localhost

案例演示1:

package net;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class TestIP {
    public static void main(String[] args) throws UnknownHostException {
        //InetAddress 类表示IP地址
        //获取本机IP
        InetAddress ip = InetAddress.getLocalHost();// DESKTOP-C25J2PS/192.xx.xx.x
        System.out.println(ip);
        //获得主机名
        System.out.println(ip.getHostName());// DESKTOP-C25J2PS
        //获得IP地址
        System.out.println(ip.getHostAddress());// 192.xx.xx.x
        // 获取本机域名和ip localhost/127.0.0.1
        System.out.println(InetAddress.getByName("localhost"));
    }
}

案例演示2:

package net;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class TestIP2 {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getByName("jd.com");
        // 获取此 IP 地址的主机名。
        System.out.println(inetAddress.getHostName());
        //返回 IP 地址字符串(以文本表现形式)。
        System.out.println(inetAddress.getHostAddress());
    }
}

3.端口号: 网络的通信,本质上是两个进程(应用程序)的通信,每台计算机都有很多进程,那么在网络通信时,如何区分这些进程呢?

  1. 公有端口:0~1023

    • HTTP:80
  • HTTPS:443
    • FTP:21
    • Telnet:23
  1. 程序注册端口

    (分配给用户或者程序):1024~49151

    • Tomcat:8080
    • MySQL:3306
    • Oracle:1521
  2. 动态、私有端口:49152~65535

DOS命令查看端口

  • 查看所有端口:netstat -ano
  • 查看指定端口:netstat -ano|findstr “端口号”
  • 查看指定端口的进程:tasklist|findstr “端口号”

InetSocketAddress类:

说到端口,则要引入一个类:InetSocketAddress

此类实现 IP 套接字地址(IP 地址 + 端口号)

1 .构造方法摘要

InetSocketAddress(InetAddress addr, int port):根据 IP 地址和端口号创建套接字地址。

InetSocketAddress(int port):创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。

InetSocketAddress(String hostname, int port):根据主机名和端口号创建套接字地址。

2.常用方法摘要

InetAddress getAddress():获取 InetAddress。

String getHostName(): 获取 hostname。

int getPort() : 获取端口号。

案例演示:

package net;

import java.net.InetAddress;
import java.net.InetSocketAddress;

public class TestPort {
    public static void main(String[] args) {
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1",8080);
        // inetSocketAddress:ip地址和端口号
        System.out.println(inetSocketAddress);
        //返回主机名
        System.out.println(inetSocketAddress.getHostName());
        //获得InetSocketAddress的端口
        System.out.println(inetSocketAddress.getPort());
        //返回一个InetAddress对象(IP对象)
        InetAddress address = inetSocketAddress.getAddress();
      
    }
}

4.计算机网络的分类

计算机网络按其覆盖的地理范围可分为如下3类:

  • 局域网(LAN)。局域网是一种在小区域内使用的,由多台计算机组成的网络,覆盖范围通常局限在10 千米范围之内,属于一个单位或部门组建的小范围网。
  • 城域网(MAN)。城域网是作用范围在广域网与局域网之间的网络,其网络覆盖范围通常可以延伸到整个城市,借助通信光纤将多个局域网联通公用城市网络形成大型网络,使得不仅局域网内的资源可以共享,局域网之间的资源也可以共享。
  • 广域网(WAN) 广城网是一种远程网,涉及长距离的通信,覆盖范围可以是个国家或多个国家,甚至整个世界。由于广域网地理上的距离可以超过几千千米,所以信息衰减非常严重,这种网络一般要租用专线,通过接口信息处理协议和线路连接起来,构成网状结构,解决寻径问题。

2.TCP通信程序

TCP通信能实现两台计算机之间的数据交互,通信的两端,要求严格的区分客户端(Client)和服务端(Server)

两端通信的步骤:

1.服务端启动程序,需要事先启动,等待客户端连接

2.客户端主动连接服务端,连接成功才可以进行通信,服务端不可主动连接客户端。

在java中提供了两个类用于实现TCP通信程序:

1.客户端java.net.Socket类表示,创建Socket对象,向服务端发出连接请求,服务端响应请求,两种建立连接开始通信。

2.服务端:java.netServSocket类表示,创建ServerSocket对象,表示相当于开启一个服务,并等待客户端的连接。

**Socket 类:**该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。
(1)构造方法摘要

public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址。

  • 回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。

案例演示:

 Socket client = new Socket("127.0.0.1", 6666);

常用方法摘要

  • public InputStream getInputStream() : 返回此套接字的输入流。

    • 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
    • 关闭生成的InputStream也将关闭相关的Socket。
  • public OutputStream getOutputStream() : 返回此套接字的输出流。

    • 如果此Socket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
    • 关闭生成的OutputStream也将关闭相关的Socket。
  • public void close() :关闭此套接字。

    • 一旦一个socket被关闭,它不可再使用。
    • 关闭此socket也将关闭相关的InputStream和OutputStream 。
  • public void shutdownOutput() : 禁用此套接字的输出流。

    • 任何先前写出的数据将被发送,随后终止输出流。

erverSocket类

ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。

构造方法摘要

public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。

案例演示

ServerSocket server = new ServerSocket(8080);

常用方法摘要

public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBfACpRj-1632572337595)(C:\Users\14823\AppData\Roaming\Typora\typora-user-images\image-20210916211801000.png)]

案例:创建一个客户端和服务端进行通信:需要先启动服务端再去启动客户端,服务端启动之后是一直都是启动状态

客户端:

package net;



import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021/09/16/21:22
 * @Description:
 */
public class SocketDemo {
    public static void main(String[] args) throws IOException {

        // TCP通信的客户端,向服务器发送连接请求,给服务器发送数据,读写服务器回写的数据
        // 表示客户端的类,此类实现客户端套接字,套接字是两台计算机通信的端点
        // 套接字:包含了ip地址和端口号
        /**
         * 实现步骤:
         * 1.创建一个客户端对象Socket,构造方法绑定服务器的ip地址和端口号
         * 2.使用Socket中的getOutputStream()方法获取网络中的OutputStream对象
         * 3.使用网络字节输出流给OutputStream对象中的write()方法给服务端发送数据
         * 4.使用Socket对象中的getInputStream()获取网络字节输入流对象
         * 5.使用网络字节输入流InputStream对象中的read方法读取服务器回写的数据
         * 客户端和服务器必须使用Socket中的提供的网络流,不能使用自己创建流对象
         * 当我们创建Socket对象的时候,就会去请求服务器和服务器经过3次握手,建立连接,如果服务器没有启动,就会抛出异常
         * 如果服务器已经启动,那么就可以进行交互了
         *   String serverIp = socket.getInetAddress().toString().substring(1);
         *         System.out.println("serverIp="+serverIp);
         */
        // 创建客户端对象
        Socket socket = new Socket("127.0.0.1",8888);
        // 获取到socket对象在中的OutputStream对象
        OutputStream os = socket.getOutputStream();
        // 使用网络字节输出流向服务器中的write()方法写入数据
        os.write("hello server".getBytes());
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len = in.read(bytes);
        String serverMessage = new String(bytes, 0, len);
        System.out.println("serverMessage="+serverMessage);
        // 关闭客户端连接
        socket.close();

    }
}

服务端:

package net;



import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021/09/16/21:40
 * @Description: TCP通信的服务端,接收客户端的请求,读取客户端发送的数据,给客户端回显数据
 * 服务器的实现步骤:
 * 1.创建一个服务器对象ServerSocket对象,需要使用指定端口号的构造方法
 * 2.使用ServerSocket的对象中的accept()方法获取到请求的客户端对象socket
 * 3.使用accept对象中的getInputStream()获取到网络字节流中的输入对象
 * 4.使用网络字节输入流中的read()方法读取客户端传递过来的数据
 * 5.获取网络字节输出流accept.getOutputStream(),使用write()方法给客户端回显数据
 * 6.关闭serverSocket对象
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(8888);
        Socket accept = serverSocket.accept();
        InputStream in = accept.getInputStream();
        OutputStream os = accept.getOutputStream();
        byte[] bytes = new byte[1024];
        int len = in.read(bytes);
        String receiveMessage=new String(bytes, 0, len);
        System.out.println("receiveMessage="+receiveMessage);
        os.write("receive client message".getBytes());
        accept.close();
        serverSocket.close();

    }
}

3.UDP网络通信

UDP网络编程

从技术意义上来讲,只有TCP才会分Server和Client。对于UDP来说,严格意义上,并没有所谓的Server和Client。
java.net包给我们提供了两个类DatagramSocket(此类表示用于发送和接收数据报的套接字)和 DatagramPacket(该类表示数据报的数据包。 )

1.DatagramSocket :构造方法摘要

protected DatagramSocket(): 构造数据报套接字并将其绑定到本地主机上的任何可用端口。
protected DatagramSocket(int port): 构造数据报套接字并将其绑定到本地主机上的指定端口。
protected DatagramSocket(int port, InetAddress laddr): 创建一个数据报套接字,绑定到指定的本地地址。

DatagramPacket: 构造方法摘要

DatagramPacket(byte[] buf, int offset, int length): 构造一个 DatagramPacket用于接收指定长度的数据报包到缓冲区中。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port): 构造用于发送指定长度的数据报包到指定主机的指定端口号上。

常用方法摘要

byte[] getData(): 返回数据报包中的数据。
InetAddress getAddress(): 返回该数据报发送或接收数据报的计算机的IP地址。
int getLength() : 返回要发送的数据的长度或接收到的数据的长度。

4.URL

URL(Uniform Resource Locator)统一资源定位符,它表示Internet上某一资源的地址。
通过URL我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。

URI=URL+URN

  • URI:Uniform Resource Identifier ,统一资源标志符。
  • URL:Uniform Resource Locator,统一资源定位符。
  • URN:Uniform Resource Name,统一资源命名。

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

片段名:即锚点,例如看小说,直接定位到章节
参数列表格式:参数名=参数值&参数名=参数值…

例如:
http://localhost:8080/index.html#a?username=jack&password=admin

URL类

java.net包下
1.构造方法摘要

URL(String spec) 根据 String 表示形式创建 URL 对象。
URL(String protocol, String host, int port, String file) 根据指定协议名、主机名、端口号和文件名创建 URL 对象。
URL(String protocol, String host, String file) 根据指定的协议名、主机名和文件名创建 URL。

2.常用方法摘要

String getProtocol() : 获取此 URL的协议名称。
String getHost() : 获取此 URL 的主机名。
int getPort() : 获取此 URL 的端口号。
String getPath() : 获取此 URL 的文件路径。
String getFile() : 获取此 URL 的文件名。
String getQuery() : 获取此 URL的查询部分。
URLConnection openConnection() : 返回一个URLConnection实例,表示与URL引用的远程对象的URL 。

URLConnection 类中又有一个方法:
InputStream getInputStream() 返回从此打开的连接读取的输入流。

URL下载网络资源:

package net;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public  class URLDownload {
    public static void main(String[] args) throws IOException {
        //下载地址
        URL url = new URL("https://img-baofun.zhhainiao.com/market/133/2366564fa6b83158208eb3181752a8d6_preview.jpg");
        //连接到这个资源 HTTP
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        InputStream in = urlConnection.getInputStream();
        FileOutputStream os = new FileOutputStream("back.png");
        byte[] buffer = new byte[1024];
        int len=0;
        while ((len=in.read(buffer))!=-1){
            os.write(buffer,0,len);
        }
        //释放资源
        urlConnection.disconnect();//断开连接
        in.close();
        os.close();
    }
}

5.综合案例

1.文件上传案例

文件上传分析图解

  1. 【客户端】输入流,从硬盘读取文件数据到程序中。
  2. 【客户端】输出流,写出文件数据到服务端。
  3. 【服务端】输入流,读取文件数据到服务端程序。
  4. 【服务端】输出流,写出文件数据到服务器硬盘中。

在这里插入图片描述

文件上传案例:

客户端:

package net.demo;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/*
    文件上传案例的客户端:读取本地文件,上传到服务器,读取服务器回写的数据

    明确:
        数据源:d:\\1.jpg
        目的地:服务器

    实现步骤:
        1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
        2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
        3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
        4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
        5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
        6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
        7.使用网络字节输入流InputStream对象中的方法read读取服务回写的数据
        8.释放资源(FileInputStream,Socket)
 */
public class TCPClient {
    public static void main(String[] args) {
        try {
            TCPClient.upload();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public  static  void upload ()  throws IOException{
        //1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("back.png");
        //2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
        Socket socket = new Socket("127.0.0.1",8888);
        //3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
        OutputStream os = socket.getOutputStream();
        //4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
        int len = 0;
        byte[] bytes = new byte[1024];
        while((len = fis.read(bytes))!=-1){
            //5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
            os.write(bytes,0,len);
        }

        /*
            解决:上传完文件,给服务器写一个结束标记
            void shutdownOutput() 禁用此套接字的输出流。
            对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。
         */
        socket.shutdownOutput();

        //6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
        InputStream is = socket.getInputStream();



        //7.使用网络字节输入流InputStream对象中的方法read读取服务回写的数据
        while((len = is.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }


        //8.释放资源(FileInputStream,Socket)
        fis.close();
        socket.close();
    }
}

服务端:

package net.demo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

/*
    文件上传案例服务器端:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写"上传成功"

    明确:
        数据源:客户端上传的文件
        目的地:服务器的硬盘 d:\\upload\\1.jpg

    实现步骤:
        1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
        3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
        4.判断d:\\upload文件夹是否存在,不存在则创建
        5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
        6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
        7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
        8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
        9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
        10.释放资源(FileOutputStream,Socket,ServerSocket)
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        ServerSocket server = new ServerSocket(8888);
        //2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象

        /*
            让服务器一直处于监听状态(死循环accept方法)
            有一个客户端上传文件,就保存一个文件
         */
        while(true){
            Socket socket = server.accept();

            /*
                使用多线程技术,提高程序的效率
                有一个客户端上传文件,就开启一个线程,完成文件的上传
             */
            new Thread(new Runnable() {
                //完成文件的上传
                @Override
                public void run() {
                   try {
                       //3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                       InputStream is = socket.getInputStream();
                       //4.判断d:\\upload文件夹是否存在,不存在则创建
                       File file =  new File("d:\\upload");
                       if(!file.exists()){
                           file.mkdirs();
                       }

                    /*
                        自定义一个文件的命名规则:防止同名的文件被覆盖
                        规则:域名+毫秒值+随机数
                     */
                       String fileName = "picture"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";

                       //5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
                       //FileOutputStream fos = new FileOutputStream(file+"\\1.jpg");
                       FileOutputStream fos = new FileOutputStream(file+"\\"+fileName);
                       //6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件


                       int len =0;
                       byte[] bytes = new byte[1024];
                       while((len = is.read(bytes))!=-1){
                           //7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
                           fos.write(bytes,0,len);
                       }


                       //8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
                       //9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
                       socket.getOutputStream().write("upload success".getBytes());
                       //10.释放资源(FileOutputStream,Socket,ServerSocket)
                       fos.close();
                       socket.close();
                   }catch (IOException e){
                       System.out.println(e);
                   }
                }
            }).start();


        }

        //服务器就不用关闭
        //server.close();
    }
}

2.B/S服务器模拟

服务器代码:

package net.bstcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*
    创建BS版本TCP服务器
     访问地址:http://localhost:8080/web/index.html
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //创建一个服务器ServerSocket,和系统要指定的端口号
        ServerSocket server = new ServerSocket(8080);
        //使用accept方法获取到请求的客户端对象(浏览器)
        Socket socket = server.accept();
        //使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
        InputStream is = socket.getInputStream();
        //使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
        byte[] bytes = new byte[1024];
        int len = 0;
        while((len = is.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }

        //把is网络字节输入流对象,转换为字符缓冲输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        //把客户端请求信息的第一行读取出来 GET /11_Net/web/index.html HTTP/1.1
        String line = br.readLine();
        //把读取的信息进行切割,只要中间部分 /11_Net/web/index.html
        String[] arr = line.split(" ");
        //把路径前边的/去掉,进行截取 11_Net/web/index.html
        String htmlpath = arr[1].substring(1);

        //创建一个本地字节输入流,构造方法中绑定要读取的html路径
        FileInputStream fis = new FileInputStream(htmlpath);
        //使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
        OutputStream os = socket.getOutputStream();

        // 写入HTTP协议响应头,固定写法
        os.write("HTTP/1.1 200 OK\r\n".getBytes());
        os.write("Content-Type:text/html\r\n".getBytes());
        // 必须要写入空行,否则浏览器不解析
        os.write("\r\n".getBytes());

        //一读一写复制文件,把服务读取的html文件回写到客户端
        int length = 0;
        byte[] bt = new byte[1024];
        while((length = fis.read(bytes))!=-1){
            os.write(bytes,0,len);
        }

        //释放资源
        fis.close();
        socket.close();
        server.close();
    }
}

客户端代码: web/index.html 文件放置在src同目录下

package net.bstcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*
    创建BS版本TCP服务器
 */
public class TCPServerThread {
    public static void main(String[] args) throws IOException {
        //创建一个服务器ServerSocket,和系统要指定的端口号
        ServerSocket server = new ServerSocket(8080);

        /*
            浏览器解析服务器回写的html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
            我们就的让服务器一直处于监听状态,客户端请求一次,服务器就回写一次
         */
        while(true){
            //使用accept方法获取到请求的客户端对象(浏览器)
            Socket socket = server.accept();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                        InputStream is = socket.getInputStream();
                        //使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
                        /*byte[] bytes = new byte[1024];
                        int len = 0;
                        while((len = is.read(bytes))!=-1){
                            System.out.println(new String(bytes,0,len));
                        }*/

                        //把is网络字节输入流对象,转换为字符缓冲输入流
                        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        //把客户端请求信息的第一行读取出来 GET /11_Net/web/index.html HTTP/1.1
                        String line = br.readLine();
                        System.out.println(line);
                        //把读取的信息进行切割,只要中间部分 /11_Net/web/index.html
                        String[] arr = line.split(" ");
                        //把路径前边的/去掉,进行截取 11_Net/web/index.html
                        String htmlpath = arr[1].substring(1);

                        //创建一个本地字节输入流,构造方法中绑定要读取的html路径
                        FileInputStream fis = new FileInputStream(htmlpath);
                        //使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
                        OutputStream os = socket.getOutputStream();

                        // 写入HTTP协议响应头,固定写法
                        os.write("HTTP/1.1 200 OK\r\n".getBytes());
                        os.write("Content-Type:text/html\r\n".getBytes());
                        // 必须要写入空行,否则浏览器不解析
                        os.write("\r\n".getBytes());

                        //一读一写复制文件,把服务读取的html文件回写到客户端
                        int len = 0;
                        byte[] bytes = new byte[1024];
                        while((len = fis.read(bytes))!=-1){
                            os.write(bytes,0,len);
                        }

                        //释放资源
                        fis.close();
                        socket.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }).start();


        }


        //server.close();
    }
}

客户端代码: web/index.html 文件放置在src同目录下

package net.bstcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*
    创建BS版本TCP服务器
 */
public class TCPServerThread {
    public static void main(String[] args) throws IOException {
        //创建一个服务器ServerSocket,和系统要指定的端口号
        ServerSocket server = new ServerSocket(8080);

        /*
            浏览器解析服务器回写的html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
            我们就的让服务器一直处于监听状态,客户端请求一次,服务器就回写一次
         */
        while(true){
            //使用accept方法获取到请求的客户端对象(浏览器)
            Socket socket = server.accept();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                        InputStream is = socket.getInputStream();
                        //使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
                        /*byte[] bytes = new byte[1024];
                        int len = 0;
                        while((len = is.read(bytes))!=-1){
                            System.out.println(new String(bytes,0,len));
                        }*/

                        //把is网络字节输入流对象,转换为字符缓冲输入流
                        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        //把客户端请求信息的第一行读取出来 GET /11_Net/web/index.html HTTP/1.1
                        String line = br.readLine();
                        System.out.println(line);
                        //把读取的信息进行切割,只要中间部分 /11_Net/web/index.html
                        String[] arr = line.split(" ");
                        //把路径前边的/去掉,进行截取 11_Net/web/index.html
                        String htmlpath = arr[1].substring(1);

                        //创建一个本地字节输入流,构造方法中绑定要读取的html路径
                        FileInputStream fis = new FileInputStream(htmlpath);
                        //使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
                        OutputStream os = socket.getOutputStream();

                        // 写入HTTP协议响应头,固定写法
                        os.write("HTTP/1.1 200 OK\r\n".getBytes());
                        os.write("Content-Type:text/html\r\n".getBytes());
                        // 必须要写入空行,否则浏览器不解析
                        os.write("\r\n".getBytes());

                        //一读一写复制文件,把服务读取的html文件回写到客户端
                        int len = 0;
                        byte[] bytes = new byte[1024];
                        while((len = fis.read(bytes))!=-1){
                            os.write(bytes,0,len);
                        }

                        //释放资源
                        fis.close();
                        socket.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }).start();


        }


        //server.close();
    }
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-27 14:27:29  更:2021-09-27 14:29:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年6日历 -2024/6/27 1:48:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码