Loading... > 网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,最后再做一些处理,代码、开发工具、数据库、服务器架设和网页设计这5部分都要接触。 # 1、软件结构 * C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。 * B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。 网络编程,就是在一定的协议下,实现两台计算机 的通信的程序。 # 2、网络通信协议 * 网络通信协议::通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信。协议中对数据的传输格式、传输速率、传输步骤等做了 统一规定,通信双方必须同时遵守,最终完成数据交换。 * TCP/IP协议:传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是 Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它 的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的 协议来完成自己的需求。 ![在这里插入图片描述](https://blog.fivk.cn/usr/uploads/2021/10/3603643279.png) ## 2.1、通信协议分类(传输层) java.net:包中包含的类和接口,提供低层次的通信细节。可以直接使用这 些类和接口,来专注于网络程序开发,而不用考虑通信的细节。 * TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是**面向连接** 的通信协议,即传输数据之前, 在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。TCP协议可 以保证传输数据的安全。应用十分广泛,例如下载文件、浏览网页等。 * 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。 * 第一次握手,客户端向服务器端发出连接请求,等待服务器确认; * 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求; * 第三次握手,客户端再次向服务器端发送确认信息,确认连接。 * UDP:用户数据报协议(User Datagram Protocol)。UDP协议是一个**面向无连接** 的协议。传输数据时,不需 要建立连接,不管对方端服务是否启动,直接将数据、数据源和目的地都封装在数据包中,直接发送。每个 数据包的大小限制在64k以内。它是不可靠协议,因为无连接,所以传输速度快,但是容易丢失数据。日常应用中,例如视频会议、QQ聊天等 # 3、网络通信三要素 * 通信协议:计算机网络通信必须遵守的规则。 * IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设 备做唯一的编号。 * 端口号:用两个字节表示的整数,它的取值范围是0~65535。可以唯一标识设备中的进程(应用程序)。,0~ 1023之间的端口号用于一些知名的网 络服务和应用。 利用 协议 + IP地址 + 端口号 三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其 它进程进行交互。 # 4、TCP通信程序 ## 4.1、概述 TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。 * 两端通信时步骤: 1. 服务端程序,需要事先启动,等待客户端的连接。 2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。 * 在Java中,提供了两个类用于实现TCP通信程序: 1. 客户端: java.net.Socket 类表示。创建 Socket 对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。 2. 服务端: java.net.ServerSocket 类表示。创建 ServerSocket 对象,相当于开启一个服务,并等待客户端的连接。服务端accept() 接收客户端Socket对象,和客户端进行交互。 ## 4.2、Socket类 java.net.Socket:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点(包含IP和端口号的网络单位)。 ## 4.3、构造方法 `public Socket(String host, int port)` :创建套接字对象并将其连接到指定主机上的指定端口号。如果指 定的host是null ,则相当于指定地址为回送地址。 回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本 地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。 ## 4.4、成员方法 `public InputStream getInputStream()` :返回此套接字的输入流。 * 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。 * 关闭生成的InputStream也将关闭相关的Socket。 `public OutputStream getOutputStream()` :返回此套接字的输出流。 * 如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。 * 关闭生成的OutputStream也将关闭相关的Socket。 `public void close()` :关闭此套接字。 * 一旦一个socket被关闭,它不可再使用。 * 关闭此socket也将关闭相关的InputStream和OutputStream。 `public void shutdownOutput()` :禁用此套接字的输出流。 * 任何先前写出的数据将被发送,随后终止输出流。 【注意】 1. 使用Socket对象获取流; 2. 创建Socket对象是,客户端和服务端进行3次握手连接。如果服务端未启动,则抛出异常。 3. 流的read()方法读取结束后会阻塞,需要调用Socket对象的shutdownOutput()方法终止流。 ## 4.5、ServerSocket类 java.io.ServerSocket:这个类实现了服务器套接字,该对象等待通过网络的请求。 ## 4.6、构造方法 `public ServerSocket(int port)` :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指 定的端口号上,参数port就是端口号。 ## 4.7、成员方法 `public Socket accept()` :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法 会一直阻塞直到建立连接。 # 5、文件上传案例 ![在这里插入图片描述](https://blog.fivk.cn/usr/uploads/2021/10/3159147259.png) * 客户端 ```java has-numbering public class FileUploadClient { public static void main(String[] args) throws IOException { System.out.println("客户端已启动!资源发送中..."); // 创建输入流,读取本地文件 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aa.jpeg")); // 创建Socket对象 Socket socket = new Socket("127.0.0.1", 3000); // 创建输出流,写出数据到服务器端 BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); byte[] b = new byte[1024 * 8]; int len; while ((len = bis.read(b)) != -1) { bos.write(b, 0, len); bos.flush(); } // 终止输出流 socket.shutdownOutput(); System.out.println("发送完毕!"); // 解析回写 InputStream in = socket.getInputStream(); byte[] back = new byte[1024]; int read = in.read(back); System.out.println(new String(back, 0, read)); in.close(); // 释放资源 bos.close(); bis.close(); socket.close(); } } ``` * 服务端 ```java has-numbering public class FileUploadServer { public static void main(String[] args) throws IOException { System.out.println("服务端已启动!"); // 创建ServerSocket对象 ServerSocket serverSocket = new ServerSocket(3000); while (true) { // 接收服务端请求 Socket accept = serverSocket.accept(); System.out.println("文件接收中..."); new Thread(() -> { try { // 创建输入流,接收客户端数据 BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); // 创建输出流,将接收到的数据写出到硬盘 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\IMG\\" + System.currentTimeMillis() + ".jpeg")); byte[] b = new byte[1024 * 8]; int len; while ((len = bis.read(b)) != -1) { bos.write(b, 0, len); } // 信息回写 OutputStream out = accept.getOutputStream(); out.write("接收成功!!!".getBytes()); out.close(); // 释放资源 bos.close(); bis.close(); accept.close(); System.out.println("文件上传成功"); } catch (IOException e) { e.printStackTrace(); } }).start(); } } } ``` # 6、模拟B\S服务器案例 ```java has-numbering public class Server { public static void main(String[] args) throws IOException { // 创建ServerSocket对象 ServerSocket serverSocket = new ServerSocket(3000); while (true) { // 接收客户端Socket Socket socket = serverSocket.accept(); // 在多线程中处理客户端请求 new Thread(new Web(socket)).start(); } } private static class Web implements Runnable { private Socket socket; public Web(Socket socket) { this.socket = socket; } @Override public void run() { try { // 转换流读取请求的第一行 BufferedReader readerWeb = new BufferedReader(new InputStreamReader(socket.getInputStream())); String req = readerWeb.readLine(); // 获取请求路径 String path = req.split(" ")[1].substring(1); // 读取服务端文件 FileInputStream fis = new FileInputStream(path); // 向浏览器端写回数据 OutputStream out = socket.getOutputStream(); out.write("HTTP/1.1 200 OK\r\n".getBytes()); out.write("Content‐Type:text/html\r\n".getBytes()); out.write("\r\n".getBytes()); byte[] b = new byte[1024 * 3]; int len; while ((len = fis.read(b)) != -1) { out.write(b, 0, len); } // 释放资源 out.close(); fis.close(); readerWeb.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } ``` > 感谢小伙伴们的关注! > 你的点赞、评论、关注、收藏是对博主的最大鼓励! > 持续更新JavaSE学习笔记!欢迎订阅专栏! 最后修改:2021 年 10 月 06 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏