当前位置: 首页 > 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.dtcms.com/a/325454.html

相关文章:

  • 套接字技术、视频加载技术、断点续传技术
  • 前端执行上下文(简版)
  • 2025.8.6 图论(1)Solution
  • 大模型提示词工程实践:聊天机器人定制与实践-打造个性化任务助手
  • Oracle 19C 配置TAF
  • 投资光伏怕成本超标?鹧鸪云系统配置最优方案
  • 微算法科技(NASDAQ:MLGO)通过蚁群算法求解资源分配的全局最优解,实现低能耗的区块链资源分配
  • 【深度学习计算性能】03:自动并行
  • Apache Ignite 生产级的线程池关闭工具方法揭秘
  • 【C++】封装哈希表模拟实现unordered_set和unordered_map
  • 【10】微网优联——微网优联 嵌入式技术一面,校招,面试问答记录
  • 【Linux让旧电脑重获新生的奇妙魔法】
  • 【k8s】k8s安装与集群部署脚本
  • Godot ------ 平滑拖动03
  • 量子神经网络:从NISQ困境到逻辑比特革命的破局之路
  • Day 37:早停策略和模型权重的保存
  • C语言指针(四):字符指针、数组指针与函数指针的实战指南
  • Unity大型场景性能优化全攻略:PC与安卓端深度实践 - 场景管理、渲染优化、资源调度 C#
  • 在Mac 上生成GitLab 的SSH 密钥并将其添加到GitLab
  • 在 .NET Core 5.0 中启用 Gzip 压缩
  • AI时代基于云原生的 CI/CD 基础设施 Tekton
  • Redis Sentinel 中 `sentinel resolve-hostnames yes` 的必要性解析
  • C#图形库SciChart与ScottPlot及LiveCharts2对比
  • Linux客户端利用MinIO对服务器数据进行同步
  • 掌握while循环:C语言编程基础
  • Unity跨平台性能优化全攻略:PC与安卓端深度优化指南 - CPU、GPU、内存优化 实战案例C#
  • 《番外:Veda的备份,在某个未联网的旧服务器中苏醒……》
  • 扩展运算符...作用介绍
  • 关系型数据库:原理、演进与生态全景——从理论基石到云原生的深度巡礼
  • 国内 Mac 开启 Apple Intelligence 教程