当前位置: 首页 > news >正文

【网络编程】从零开始彻底了解网络编程(二)

在这里插入图片描述

本篇博客给大家带来的是网络编程的知识点,.
🐎文章专栏: JavaEE初阶
🚀若有问题 评论区见
欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .

王子,公主请阅🚀

  • 要开心
    • 要快乐
      • 顺便进步
  • 1. 网络编程的目的和概念
  • 2. 网络编程中的基本概念
  • 3. Socket套接字
  • 4. 两种Java通信模型
    • 4.1 Java数据报套接字通信模型
    • 4.2 Java流套接字通信模型
  • 5. UDP数据报套接字编程

要开心

要快乐

顺便进步

1. 网络编程的目的和概念

Ⅰ 为什么需要学习网络编程?

网络资源是非常丰富的, 用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。与本地打开视频文件类似,只是视频文件这个资源的来源是网络。
相比本地资源来说,网络提供了更为丰富的网络资源:

在这里插入图片描述
所谓的网络资源,其实就是在网络中可以获取的各种数据资源。
而所有的网络资源,都是通过网络编程来进行数据传输的。

Ⅱ 什么是网络编程?
网络编程指网络上的主机通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输).

在这里插入图片描述

当然,我们只要满足进程不同就行;所以即便是同一个主机,只要是不同进程,基于网络来传输数据,也属于网络编程.
特殊地,对于开发来说,在条件有限的情况下,一般也都是在一个主机中运行多个进程来完成网络编程.但是,我们一定要明确,我们的目的是提供网络上不同主机,基于网络来传输数据资源:
进程A:编程来获取网络资源.
进程B:编程来提供网络资源.



2. 网络编程中的基本概念

Ⅰ 发送端和接受端
在一次网络数据传输时:
发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。

在这里插入图片描述

Ⅱ 请求和响应
一般来说,获取一个网络资源,涉及到两次网络数据传输:
①:请求数据的发送
②:响应数据的发送。
好比在快餐店点一份炒饭:
先要发起请求:点一份炒饭,再有快餐店提供的对应响应:提供一份炒饭.

在这里插入图片描述

Ⅲ 客户端和服务端
服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务。
客户端:获取服务的一方进程,称为客户端。
对于服务端来说,一般是提供:
① 客户端获取服务资源.
② 客户端保存资源在服务端.

Ⅳ 常见的客户端服务端模型

最常见的场景,客户端是指给用户使用的程序,服务端是提供用户服务的程序:
① 客户端先发送请求到服务端.
② 服务端根据请求数据,执行相应的业务处理.
③ 服务端返回响应:发送业务处理结果.
④ 客户端根据响应数据,展示处理结果.(展示获取的资源,或提示保存资源的处理结果)

3. Socket套接字

Ⅰ 概念

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。
基于Socket套接字的网络程序开发就是网络编程。

Ⅱ 分类

Socket套接字主要针对传输层协议划分为如下三类:

①流套接字

使用传输层TCP协议TCP,即Transmission Control Protocol(传输控制协议),传输层协议。
以下为TCP的特点(细节后续再说):
有连接
可靠传输
面向字节流
有接收缓冲区,也有发送缓冲区
大小不限

对于字节流来说,可以简单的理解为,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。

② 数据报套接字
使用传输层UDP协议UDP,即User Datagram Protocol(用户数据报协议),传输层协议。
以下为UDP的特点(细节后续再学习):
无连接
不可靠传输
面向数据报
有接收缓冲区,无发送缓冲区
大小受限:一次最多传输64k

对于数据报来说,可以简单的理解为,传输数据是一块一块的,发送一块数据假如100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节。

4. 两种Java通信模型

4.1 Java数据报套接字通信模型

对于UDP协议来说,具有无连接,面向数据报的特征,即每次都是没有建立连接,并且一次发送全部数据报,一次接收全部的数据报。
java中使用UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使用DatagramPacket 作为发送或接收的UDP数据报。对于一次发送及接收UDP数据报的流程如下:

在这里插入图片描述

以上只是一次发送端的UDP数据报发送,及接收端的数据报接收,并没有返回的数据。也就是只有请求,没有响应。对于⼀个服务端来说,重要的是提供多个客户端的请求处理及响应,流程如下:

在这里插入图片描述

4.2 Java流套接字通信模型

在这里插入图片描述

Socket编程注意事项
① 客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务端,但真实的场景,一般都是不同主机.
② 注意的IP和目的端口号,标识了一次数据传输时要发送数据的终点主机和进程.
③ Socket编程我们是使用流套接字和数据报套接字,基于传输层的TCP或UDP协议,但应用层协议,也需要考虑,这块我们在后续来说明如何设计应用层协议。
④ 关于端口被占用的问题
如果一个进程A已经绑定了一个端口,再启动一个进程B绑定该端口,就会报错,这种情况也叫端口被占用。对于java进程来说,端口被占用的常见报错信息如下:

在这里插入图片描述
此时需要检查进程B绑定的是哪个端口,再查看该端口被哪个进程占用。以下为通过端口号查进程的方式:
① 在cmd输入 netstat -ano | findstr 端口号 ,则可以显示对应进程的pid。如以下命令显示了8888进程的pid.
② 在任务管理器中,通过pid查找进程

解决端口被占用的问题:
① 如果占用端口的进程A不需要运行,就可以关闭A后,再启动需要绑定该端口的进程B.
② 如果需要运行A进程,则可以修改进程B的绑定端口,换为其他没有使用的端口.

5. UDP数据报套接字编程

1. DatagramSocket
DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。
DatagramSocket 构造方法:

在这里插入图片描述

DatagramSocket 方法:

在这里插入图片描述

2. DatagramPacket
DatagramPacket是UDP Socket发送和接收的数据报。
DatagramPacket 构造方法:

在这里插入图片描述
DatagramPacket 方法:

在这里插入图片描述

3. InetSocketAddress

构造UDP发送的数据报时,需要传入SocketAddress ,该对象可以使用 InetSocketAddress来创建.
InetSocketAddress ( SocketAddress 的子类 )构造方法:

在这里插入图片描述

4. 写一个简单的 UDP 的客户端/服务器通信的程序,这个程序没有啥业务逻辑,只是单纯的调用 socket api.让客户端给服务器发送一个请求,请求就是一个从控制台输入的字符串,服务器收到字符串之后,也就会把这个字符串原封不动的返回给客户端, 客户端再显示出来.

服务器代码示例:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class test1Sever {private static DatagramSocket socket = null;public test1Sever(int port) throws SocketException {//服务器的端口号由程序猿指定则相对可控,不容易出问题,所以不必交给系统.socket = new DatagramSocket(port);//服务器需要指定端口号,而客户端不用.}public static void start() throws IOException {System.out.println("服务器启动!");while(true) {//1. 接受客户端传过来的请求DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);//客户端传过来的数据以二进制的形式存在requestPacket中String request = new String(requestPacket.getData(),0, requestPacket.getLength());//2. 根据请求计算响应//由于此处我们只是实现一个简单的回显服务器,所以请求是什么,响应就是什么.String respond = process(request);//3. 将响应构造为packet,发回给客户端.DatagramPacket respondPacket = new DatagramPacket(respond.getBytes(),respond.getBytes().length,requestPacket.getSocketAddress());socket.send(respondPacket);//打印一个日志System.out.printf("[%s,%d] req = %s resp = %s\n",requestPacket.getSocketAddress().toString(),requestPacket.getPort(),request,respond);}}public static String process(String request) {return request;}public static void main(String[] args) throws IOException {test1Sever sever = new test1Sever(9090);sever.start();}
}

客户端代码示例:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;public class test1Client {private  DatagramSocket socket = null;private  String serverIp = "";private  int serverPort = 0;public test1Client(String ip, int port) throws SocketException {//客户端的端口号如果是由客户手动指定则容易起冲突,所以要交给系统分配.socket = new DatagramSocket();//客户端的端口号由系统自行分配.//记录对端的ip和端口号.serverIp = ip;serverPort = port;}public void start() throws IOException {System.out.println("客户端启动!");Scanner sc = new Scanner(System.in);while(true) {//1. 给服务器发送请求.System.out.println("-> ");String request = sc.next();DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),serverPort);socket.send(requestPacket);//2. 读取服务器发过来的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);//3. 把响应转成字符串显示出来String response = new String(responsePacket.getData(),0,responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {test1Client client = new test1Client("127.0.0.1",9090);client.start();}
}

执行过程:
1.服务器先启动. 服务器启动之后,就会进入循环,执行到 receive 这里并阻塞 (此时还没有客户端过来)
2.客户端开始启动,也会先进入 while 循环,执行 sc.next.并且也在这里阻塞当用户在控制台输入字符串之后,next 就会返回,从而构造请求数据并发送出来.
3.客户端发送出数据之后,
服务器会从 receive 中返回,进一步的执行解析请求为字符串,执行 process 操作,执行 send 操作
客户端则继续往下执行,执行到 receive,等待服务器的响应
4.客户端收到从服务器返回的数据之后, 就会从 receive 中返回执行这里的打印操作,也就把响应给显示出来了.
5.服务器这边完成一次循环之后,又执行到 receive 这里.客户端这边完成一次循环之后,又执行到 sc.next 这里双双进入阻塞

这俩程序,都是在同一个主机上.并没有真正的"跨主机通信"效果,想要让其他人访问我的服务器,就得将程序放到云服务器上. 因为云服务器上有公网IP.

如果此时我想实现一个英译汉的服务器,只需要重写process
代码示例:

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;public class test1DictServer extends test1Sever{private Map<String,String> dict = new HashMap<>();public test1DictServer(int port) throws SocketException {super(port);dict.put("dog","小狗");dict.put("elephant","大象");dict.put("cat","小猫");}@Overridepublic String process(String request) {return dict.getOrDefault(request,"没有查询到这个词");}public static void main(String[] args) throws IOException {test1DictServer server = new test1DictServer(9090);server.start();}
}

本篇博客到这里就结束啦, 感谢观看 ❤❤❤

🐎期待与你的下一次相遇😊😊😊

相关文章:

  • 【2025计算机网络-面试常问】http和https区别是什么,http的内容有哪些,https用的是对称加密还是非对称加密,流程是怎么样的
  • wordpress独立站的产品详情页添加WhatsApp链接按钮
  • 深入探索 Unix 与 Linux:历史、内核及发行版
  • 02_解决Class com.sun.tools.javac.tree.JCTree
  • 【失败总结】Win10系统安装docker
  • FTP客户端实现(文件传输)
  • DreamDiffusion的mae_for_eeg.py网络架构
  • 基于maven-jar-plugin打造一款自动识别主类的maven打包插件
  • [Spring]SSM整合
  • 游戏引擎学习第238天:让 OpenGL 使用我们的屏幕坐标
  • 基于Redis实现RAG架构的技术解析与实践指南
  • idea中运行groovy程序报错
  • 【perf】perf工具的使用生成火焰图
  • 基于 OpenCV 的图像与视频处理
  • Kubernetes(k8s)学习笔记(二)--k8s 集群安装
  • React+TS编写轮播图
  • 计算机视觉cv入门之Haarcascade的基本使用方法(人脸识别为例)
  • 【后端】【Django】Django 模型中的 `clean()` 方法详解:数据校验的最后防线
  • 【人工智能】推荐开源企业级OCR大模型InternVL3
  • css3新特性第四章(渐变)
  • 全国登记在册民营企业超过5700万户,占企业总量92.3%
  • 老旧高层遭“连环漏水”,如何携手共治解难题?
  • 涉嫌在饭局后性侵一女子,湖南机场董事长邱继兴被警方刑拘
  • 42岁北京大学科学技术与医学史系副教授陈昊逝世
  • 14岁男孩膀胱内现52颗磁力珠,专家呼吁关注青春期少年心理健康
  • 自然资源部:一季度存量商品房转移登记办理量同比增长超三成