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

网络编程~

什么是⽹络编程

网络编程是指通过编写程序实现计算机之间的通信和数据交换,通常基于网络协议(如TCP/IP)进行数据传输。其核心目标是让不同设备或系统能够通过网络连接共享信息、资源或服务。

常⻅的客⼾端服务端模型

最常⻅的场景,客⼾端是指给⽤⼾使⽤的程序,服务端是提供⽤⼾服务的程序:

  • 客⼾端先发送请求到服务端
  • 服务端根据请求数据,执⾏相应的业务处理
  •  服务端返回响应:发送业务处理结果
  • 客⼾端根据响应数据,展⽰处理结果(展⽰获取的资源,或提⽰保存资源的处理结果)

Socket套接字

Socket(套接字)是网络编程中的一个重要概念,它是网络通信的端点,用于在不同计算机之间进行数据传输。可以把它理解为两个程序之间通信的桥梁。

IP 地址:用于标识网络中的设备
端口号:用于标识设备中的具体应用程序
协议:定义数据传输的规则,主要有 TCP 和 UDP

Socket 的类型

1.流式套接字(SOCK_STREAM)

  • 有连接
  • 可靠传输
  •  ⾯向字节流 
  • 有接收缓冲区,也有发送缓冲区 
  • ⼤⼩不限

2. 数据报套接字(SOCK_DGRAM)

  • ⽆连接
  •  不可靠传输
  • ⾯向数据报
  • 有接收缓冲区,⽆发送缓冲区
  • ⼤⼩受限:⼀次最多传输64k

3. 原始套接字(SOCK_RAW)简单理解即可

  • 可以直接访问底层协议
  • 主要用于实现新的网络协议

Java数据报套接字通信模型

对于UDP协议来说,具有⽆连接,⾯向数据报的特征,即每次都是没有建⽴连接,并且⼀次发送全部 数据报,⼀次接收全部的数据报。

java中使⽤UDP协议通信,报主要基于 DatagramSocket 类来创建数据套接字,并使⽤ DatagramPacket 作为发送或接收的UDP数据报。

具体流程:

UDP数据报套接字编程

这里的DatagramSocket t可以看作邮局,DatagramPacket可以看作信件,邮件对新建进行发送和接收,信件里面这里记录着我们的内容(也就是IP和端口)。

DatagramSocket 

  • 用于发送和接收 UDP 数据包
  • 不需要建立连接,直接发送数据
  • 提供无连接、不可靠的数据传输服务
DatagramSocket 构造方法
方法签名说明
DatagramSocket()创建一个未绑定的套接字
DatagramSocket(int port)创建一个绑定到指定端口的套接字
DatagramSocket(int port, InetAddress addr)创建一个绑定到指定地址和端口的套接字
DatagramSocket(SocketAddress bindaddr)创建一个绑定到指定本地地址的套接字
DatagramSocket 主要方法
方法签名说明
void send(DatagramPacket p)从此套接字发送数据报包
void receive(DatagramPacket p)从此套接字接收数据报包
void bind(SocketAddress addr)将套接字绑定到指定的本地地址
void close()关闭此套接字
boolean isClosed()返回套接字是否已关闭
void setSoTimeout(int timeout)启用/禁用 SO_TIMEOUT,以毫秒为单位
int getPort()返回套接字连接的远程端口
InetAddress getInetAddress()返回套接字连接的地址

DatagramPacket 类

  • 表示 UDP 数据包
  • 包含数据、目标地址和端口信息
  • 是数据传输的基本单位
    DatagramPacket 构造方法
    方法签名功能描述
    DatagramPacket(byte[] buf, int length)构造用于接收长度为 length 的数据包
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)构造用于发送长度为 length 的数据包到指定主机的指定端口
    DatagramPacket(byte[] buf, int offset, int length)构造用于接收从 offset 开始的长度为 length 的数据包
    DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)构造用于发送从 offset 开始的长度为 length 的数据包到指定主机的指定端口
    DatagramPacket 主要方法
    方法签名功能描述
    InetAddress getAddress()返回发送/接收数据报的机器 IP 地址
    byte[] getData()返回数据缓冲区
    int getLength()返回发送/接收数据的长度
    int getOffset()返回缓冲区中数据的偏移量
    int getPort()返回远程端口号
    void setAddress(InetAddress iaddr)设置目标机器 IP 地址
    void setData(byte[] buf)设置数据缓冲区
    void setData(byte[] buf, int offset, int length)设置带偏移量和长度的数据缓冲区
    void setLength(int length)设置数据包长度
    void setPort(int iport)设置远程端口号
    InetSocketAddress 构造方法
    方法签名方法说明
    InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

客户端示例

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;public class UdpClient {public DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpClient(String serverIp, int serverPort) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;socket = new DatagramSocket();}public  void start() throws IOException{Scanner scanner = new Scanner(System.in);while (true) {//1这里读取用户输入的内容System.out.println("这里输入发送的内容");if (!scanner.hasNext()) {break;}String request = scanner.next();//2.把请求发送给服务器,需要构造 DatagramPacket 对象.DatagramPacket resquePacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),serverPort);//3.发送数据报socket.send(resquePacket);//4.接收服务器的响应DatagramPacket responsePacket = new DatagramPacket(new byte[1024],1024);socket.receive(responsePacket);//5.解析并打印String response = new String(responsePacket.getData(),0,responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpClient client = new UdpClient("127.0.0.1",9000);client.start();}
}

服务端示例

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UdpEchoServer {public DatagramSocket socket = null;public UdpEchoServer(int port) throws Exception {socket = new DatagramSocket(port);}public String start() throws IOException {//服务器启动了System.out.println("服务器启动了");while (true){// 循环一次, 就相当于处理一次请求.// 处理请求的过程, 典型的服务器都是分成三个步骤的.// 1. 读取请求并解析.//    DatagramPacket 表示一个 UDP 数据报. 此处传入的字节数组, 就保存 UDP 的载荷部分.DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4069);//接收数据报socket.receive(requestPacket);//把读取到的二进制数据转换为字符串。String request= new String(requestPacket.getData(),0,requestPacket.getLength());//2.根据请求,计算响应//此处写的是回显服务器,也就是服务器返回与请求相同的字符串。String response = process(request);//3.把响应返回给客服端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());//获取客户端地址(这里是之前自动记录的地址)socket.send(responsePacket);//打印日志System.out.printf("[%s:%d] req: %s ,resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}public String process(String request) {return request;}public static void main(String[] args) throws Exception {UdpEchoServer server = new UdpEchoServer(9000);server.start();}
}

重写process

public class UdpDictServer extends UdpEchoServer{private HashMap<String,String> dict = new HashMap<>();public UdpDictServer(int port) throws Exception {super(port);//初始话字典dict.put("hello","你好");dict.put("world","世界");dict.put("book","书");dict.put("apple","苹果");}@Overridepublic String process(String request) {return dict.getOrDefault(request, "词典无此单词");}public static void main(String[] args) throws Exception {UdpEchoServer server = new UdpDictServer(9000);server.start();}

TCP流套接字编程

它就像打电话一样,需要先建立连接,然后才能传输数据。

TCP的特点

  • 面向连接:通信前需要建立连接(三次握手)
  • 可靠传输:保证数据不丢失、不重复、按序到达
  • 面向字节流:数据像水流一样连续传输
  • 一对一通信:一个连接只能在两个端点之间通信

服务端

  • ServerSocket:用于监听客户端连接请求
  • Socket:用于与客户端通信

服务端工作流程

  • 创建 ServerSocket 并绑定端口
  • 调用 accept() 等待客户端连接
  • 客户端连接后获得 Socket 对象
  • 通过 Socket 的输入输出流进行数据传输
  • 关闭连接

客户端

  • Socket:用于连接服务器

客户端工作流程

  • 创建 Socket 并连接服务器
  • 通过 Socket 的输入输出流进行数据传输
  • 关闭连接

简单客服端示例

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.rmi.RemoteException;
import java.util.Calendar;
import java.util.Scanner;public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws Exception {//这里直接设置//创建socket对象就会在底层建立tcp连接,就不需要直接保存了socket = new Socket(serverIp, serverPort);}public void start() throws IOException {Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {// 为了使用方便, 套壳操作Scanner scannerNet = new Scanner(inputStream);PrintWriter writer = new PrintWriter(outputStream);//从控制读取请求发送给服务器while (true) {System.out.println("请输入请求数据");//读取用户输入String request = scanner.next();//发送给服务器writer.println(request);//缓冲区刷新才可以真正发的发送数据writer.flush();//读取返回的响应String response = scannerNet.next();//打印System.out.println(response);}}catch (IOException e ){throw new RuntimeException(e);}}public static void main(String[] args) throws Exception {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9000);client.start();}
}

简单服务端示例

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;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("服务器启动");//创建线程池ExecutorService executorService = Executors.newCachedThreadPool();//处理连接,可能有多个连接while(true){//先处理客户端发来的连接,如果没有客户端发起连接,此时accept就会阻塞Socket clientSocket = serverSocket.accept();//处理连接//processConnection(clientSocket);//采用多线程的方式调整可以进行多个用户同时进行
//            Thread t= new Thread(()->{
//                try {
//                    processConnection(clientSocket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            t.start();//采用线程池的方式executorService.submit(() -> {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});}}private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {//针对inputStream套了一层Scanner scanner = new Scanner(inputStream);//针对outputStreamPrintWriter writer = new PrintWriter(outputStream);//分成三个步骤while (true){//读取请求并解析if(!scanner.hasNext()){System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}String request = scanner.next();//根据请求计算响应String response = Process(request);//返回客户端writer.println(response);//缓冲区刷新才可以真正发的发送数据writer.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(9000);server.start();}
}

http://www.lryc.cn/news/617467.html

相关文章:

  • 【13-向量化-高效计算】
  • 《番外:Veda的备份,在某个未联网的旧服务器中苏醒……》
  • 飞算 JavaAI 智能进阶:从技术工具到金融科技开发范式的革新
  • 文件操作:fgets与gets区别+fread/fwrite +流定位接口
  • 【图像处理基石】PCA图像压缩与还原:基于OpenCV的Lena图实验
  • 2025 算法面试试题-阿里面试题分析
  • 【算法专题训练】11、字符串中的变位词
  • PyTorch基础(使用Tensor及Antograd实现机器学习)
  • GraalVM !拥抱云原生的 JVM
  • foreach 块并行加速
  • docker compose和docker-compose命令的区别
  • 力扣164:最大间距
  • 大数据系统架构模式:驾驭海量数据的工程范式
  • React(四):事件总线、setState的细节、PureComponent、ref
  • LeetCode 2438.二的幂数组中查询范围内的乘积:模拟(前缀和可选)
  • C++项目实战(日期类的实现)
  • MFC C++ 使用ODBC方式调用Oracle数据库的详细步骤
  • 重学React(五):脱围机制一
  • 金蝶云星辰:赋能企业数据管理
  • spring boot 整合redis教程
  • 带简易后台管理的米表系统 域名出售系统 自适应页面
  • 帝国理工学院团队研发:Missense3D-PTMdb—— 解析遗传变异与翻译后修饰的交互式工具
  • 计算机网络---交换机
  • 套接字技术、视频加载技术、断点续传技术
  • Horse3D引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
  • 2025 年国内可用 Docker 镜像加速器地址
  • Rust面试题及详细答案120道(19-26)-- 所有权与借用
  • 《基于Pytorch实现的声音分类 :网页解读》
  • YOLOv8 训练报错:PyTorch 2.6+ 模型加载兼容性问题解决
  • 【JavaEE】(12) 创建一个 Sring Boot 项目