学做网站会员,老网站301跳转新网站,软件技术毕业设计论文,cms 企业网站目录
一、网络编程
二、客户端和服务器
三、客户端和服务器的交互模式
四、TCP 和 UDP
UDP socket api 的使用
1、DatagramSoket
2、DatagramPacket
TCP socket api 的使用
1、ServerSocket
2、Socket 一、网络编程
本质上就是学习传输层给应用层提供的 api#x…目录
一、网络编程
二、客户端和服务器
三、客户端和服务器的交互模式
四、TCP 和 UDP
UDP socket api 的使用
1、DatagramSoket
2、DatagramPacket
TCP socket api 的使用
1、ServerSocket
2、Socket 一、网络编程
本质上就是学习传输层给应用层提供的 api通过 api 把数据交给传输层进一步地层层封装将数据通过网卡发送出去这也是网络程序的基本工作流程。
掌握了基础 api 就能更好的理解实际开发中使用的框架springdubbo的工作过程也提供了魔改/自己实现框架的能力。 二、客户端和服务器
在网络中主动发起通信的一方称为“客户端”被动接受的一方称为“服务器”。同一个程序在不同的场景中可能是客户端也可能是服务器。
客户端给服务器发送的数据称为“请求”request
服务器给客户端返回的数据称为“响应”response 三、客户端和服务器的交互模式
1、“一问一答”
一个请求对于一个响应这是交互模式是最常见的后续进行的“网站开发”web开发都是这种模式。
2、“一问多答”
主要在“下载”场景中涉及
3、“多问一答”
主要在“上传”场景中涉及
4、“多问多答”
主要在“远程控制/远程桌面”场景中涉及 四、TCP 和 UDP
进行网络编程需要使用系统的 API【本质上是传输层提供的协议】。
传输层主要涉及到两个协议TCP 和 UDP。
连接性可靠性面向数据传输方式TCP面向连接可靠传输面向字节流全双工UDP无连接不可靠传输面向数据报全双工
连接此处说的“连接”不是物理意义的连接是抽象虚拟的“连接”。所谓计算机中的“网络连接”是指通信双方各自保存对方的信息。客户端的数据结构中记录了谁是它的服务器服务器的数据结构中记录了谁是它的客户端本质上就是记录对方的信息。可靠传输/不可靠传输无论如何都不能保证100%的信息传输。可靠传输主要是指发送方能够感知数据有没有传输给接收方如果没接收到可以采取相应的措施补救例如重传机制。面向字节流与文件中的字节流完全一致网络中传输数据的基本单位就是字节。面向数据报每次传输的基本单位是一个数据报有一系列字节构成。全双工一个信道可以双向通信就叫全双工。可以理解成马路的多车道就是全双工。半双工可以理解为吸管同一时刻只能吸或者呼。 UDP socket api 的使用
Java 把系统原生 api 封装了UDP socket 提供的两个核心的类
1、DatagramSoket
操作系统中有一类文件就叫 socket 文件这类文件抽象地表示了“网卡”这样的硬件设备。而进行网络通信最核心的硬件设备就是网卡。
DatagramSocket 类就是负责对 socket 文件进行读写从而借助网卡发送接收数据。 2、DatagramPacket
UDP 面向数据报每次发送接收数据的基本单位是一个 UDP 数据报。
DatagramPacket 类就表示了一个 UDP 数据报。 关于 receive 接收数据报的底层实现过程 UdpEchoServer 实例
public class UdpEchoServer {private DatagramSocket socket null;public UdpEchoServer(int port) throws SocketException {socket new DatagramSocket(port);}public void start() throws IOException {System.out.println(服务器启动);while (true) {//每次循环都是一次处理请求进行响应的过程//1. 读取请求并解析DatagramPacket requestPacket new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// 将读到的字节数组转换成 String 方便后续操作String request new String(requestPacket.getData(),0,requestPacket.getLength());//2. 根据请求计算响应String response process(request);//3. 把响应返回到客户端// 与请求数据报创建不同请求数据报是使用空白字节数组而此处直接把 String 里包含的字节数组作为参数创建DatagramPacket responsePacket new DatagramPacket(response.getBytes(), response.getBytes().length,requestPacket.getSocketAddress()); // 因为 UDP 无连接因此必须从【请求数据报】中获取对应客户端的 ip 和端口socket.send(responsePacket);//打印日志System.out.printf([%s:%d] req: %s, resp: %s\n,requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server new UdpEchoServer(9090);server.start();}
} 上述代码中 1、可以看到 23 行需要从【请求数据报】中获取对应客户端 ip 和端口号才能完成发送响应证明了 UDP socket 自身不保存对端的 ip 和端口号体现了无连接。 2、不可靠传输代码中没有体现。 3、receive 和 socket 都是以DatagramPacket 为单位体现了面向数据报。 4、一个 socket 既能发送send有能接收receive体现了全双工。 UdpEchoClient 示例
public class UdpEchoClient {private DatagramSocket socket null;private String serverIp;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {// 客户端正常情况下不需要指定端口socket new DatagramSocket();this.serverIp serverIp;this.serverPort serverPort; // 客户端对应的服务器端口号}public void start() throws IOException {System.out.println(客户端启动);Scanner sc new Scanner(System.in);while (true) {//1. 从控制台读取要发送的数据System.out.print(- ); //表示提示用户输入if (!sc.hasNext()) { //hasNext 具有阻塞功能break;}String request sc.next();//2. 构造请求并发送DatagramPacket requestPacket new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);//3. 读取服务器的响应DatagramPacket responsePacket new DatagramPacket(new byte[4096],4096);// 阻塞等待响应数据返回socket.receive(responsePacket);//4. 把响应显示到控制台String response new String(responsePacket.getData(),0,responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client new UdpEchoClient(127.0.0.1, 9090);client.start();}
}
TCP socket api 的使用
由于 TCP 是面向字节流的传输的基本单位是字节因此没有像 UDP 中 DatagramPacket 这样的类。 Java 把系统原生 api 封装了TCP socket 提供的两个核心的类
1、ServerSocket
这是Socket 类同样抽象地表示了“网卡”但是这个类与 UDP 中使用的 DatagramSocket 不同这个类只能给服务器进行使用。只负责处理对客户端的连接主要 api 是 accept()。
2、Socket
对应到“网卡”既能给服务器使用又能给客户端使用。相当于电话的两个听筒通过 Socket 完成对端之间的通信。主要的 api 是 getInputStream 和 getOutputStream。需要注意由于服务器端的 Socket 对象与客户端时一一对应的为了避免无限占用文件描述符表使用完毕后需要 close 关闭。
TcpEchoServer 示例
public class TcpEchoServer {private ServerSocket serverSocket null;public TcpEchoServer(int port) throws IOException {serverSocket new ServerSocket(port);}public void start() throws IOException {System.out.println(服务器启动);while (true) {// 当客户端创建出 socket 后new socket就会和对应的服务器进行 tcp 连接建立流程// 此时通过 accept 方法来“接听电话”然后才能进行通信Socket clientSocket serverSocket.accept();Thread t new Thread(() - {processConnection(clientSocket);});t.start();}}private void processConnection(Socket clientSocket) {System.out.printf([%s:%d] 客户端上线\n, clientSocket.getInetAddress(), clientSocket.getPort());// 循环读取客户端的请求并返回响应try (InputStream inputStream clientSocket.getInputStream();OutputStream outputStream clientSocket.getOutputStream()){// 可以使用 inputStream 原本的 read 方法进行读取// 但是比较繁琐为了【方便读入】这里使用 Scanner 对输入流进行输入Scanner sc new Scanner(inputStream);while (true) { // 长连接if (!sc.hasNext()) {// 读取完毕客户端断开连接System.out.printf([%s:%d] 客户端下线\n, clientSocket.getInetAddress(), clientSocket.getPort());break;}//1. 读取请求并解析此处使用 next 需要注意 next 的读入规则String request sc.next();//2. 根据请求计算响应String response process(request);//3. 把响应返回给客户端/* 通过这种方式也可以写回但是这种方式不方便添加 \noutputStream.write(response.getBytes(),0,response.getBytes().length);*/// 因此为了【方便写入】给 outputStream 也套一层即使用 printWriter// 此处的 printWriter 就类似于 Scanner 将输入流包装了一下而 printWriter 对输出流包装了一下PrintWriter printWriter new PrintWriter(outputStream);// 通过 println 在末尾添加了 \n与客户端的 scNetwork.next 呼应printWriter.println(response);// 刷新缓冲区确保数据能够发送出去printWriter.flush();// 打印日志System.out.printf([%s:%d] req: %s, resp: %s\n, clientSocket.getInetAddress(), clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} finally {clientSocket.close();}} private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server new TcpEchoServer(9090);server.start();}
} 需要注意的是 1、理解ServerSocket 和Socket 的不同作用Socket作为接收对象。 2、只有当客户端 new Socket 时ServerSocket 才能通过 accept 完成连接。 3、Scanner 和 PrintWriter 。 4、flush 刷新缓冲区。 5、finaly{ clientSocket.close(); } 每个客户端对应一个Socket因此每个客户端完成任务后需要关闭文件从而销毁文件描述符表。而 try自动关闭的是流对象而没有释放文件本体。 TcpEchoClient 示例
public class TcpEchoClient {private Socket socket null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {// 这里直接将 ip 和 port 传入是由于 tcp 是有连接的socket 里能够保存 ip 和 portsocket new Socket(serverIp,serverPort);// 因此也不需要额外创建【类成员对象】来保存 ip 和 port}public void start() {System.out.println(客户端启动);try (InputStream inputStream socket.getInputStream();OutputStream outputStream socket.getOutputStream()){// 此处的 scanner 用于控制台读取数据Scanner scConsole new Scanner(System.in);// 此处的 scanner 用于读取服务器响应回来的数据Scanner scNetwork new Scanner(inputStream);// 此处 printWriter 用于向服务器写入请求数据PrintWriter printWriter new PrintWriter(outputStream);while (true) {// 这里流程和 UDP 的客户端类似//1. 从控制台读取输入的字符串System.out.print(- );if (!scConsole.hasNext()) {break;}String request scConsole.next();//2. 把请求发送给服务器// 使用 printWriter 是为了使发送的请求末尾带有 \n与服务器的 sc.next 呼应printWriter.println(request);// 刷新缓冲区确保数据能够发送出去printWriter.flush();//3. 从服务器读取响应String response scNetwork.next();//4. 打印响应System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client new TcpEchoClient(127.0.0.1, 9090);client.start();}
} 需要注意的是 1、TCP 是有连接的因此 Socket 能够直接保存 ip 和 port。 2、flush 刷新缓冲区。 【博主推荐】
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CASCompare and swap-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/136288256?spm1001.2014.3001.5501【Java多线程】对线程池的理解并模拟实现线程池-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/136160003?spm1001.2014.3001.5501【Java多线程】分析线程加锁导致的死锁问题以及解决方案-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/136150237?spm1001.2014.3001.5501
如果觉得作者写的不错求给博主一个大大的点赞支持一下你们的支持是我更新的最大动力
如果觉得作者写的不错求给博主一个大大的点赞支持一下你们的支持是我更新的最大动力
如果觉得作者写的不错求给博主一个大大的点赞支持一下你们的支持是我更新的最大动力