[JAVAee]网络编程-套接字Socket
目录
基本概念
发送端与接收端
请求与响应
编辑客户端与服务器
Socket套接字
分类
数据报套接字
流套接字传输模型
UDP数据报套接字编程
DatagramSocket API
DatagramPacket API
InetSocketAddress API
示例一:
示例二:
TCP流数据报套接字编程
ServerSocket API
Socket API
示例一:
网络编程指的是,网络上的主机的不同进程通过编程的方式实现网络通信.同一主机下只要满足不同进程间的通信就可以成为"网络通信"
基本概念
发送端与接收端
在网络通信中:
作为发送数据的进程称为"发送端",发送端主机即网络通信中的"源主机"
作为接收数据的进程称为"接收端",接收端主机即网络通信中的"目的主机"
注意:网络通信中的发送端与接收端都是相对的.
请求与响应
一般来说,一次网络通信中设计到两次数据传输:
- 第一次:A端向B端发送的请求
- 第二次:B端向A端发送的响应
客户端与服务器
服务器:在网络通信下,提供服务的一端.(服务可以指:响应一定的要求)
客户端:获取服务的一端
Socket套接字
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元.基于Socket套接字的网络程序开发就是网络编程.
分类
套接字根据传输层协议主要分成:
- 数据报套接字:使用传输层UDP协议(User Datagram Protocol)用户数据报协议
- 流套接字:使用传输层TCP协议(Transmission Control Protocol)传输层控制协议
- 原始套接字:用于自定义传输层协议
数据报套接字
数据报固定每次传输的字节,更像是写信,有来有回的.
流套接字传输模型
面对的是字节流.
打电话一般,接通后就可以无节制的传输.
UDP数据报套接字编程
DatagramSocket API
构造方法
方法签名 | 方法说明 |
DatagramSocket() | 创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口 (一般用于客户端) |
DatagramSocket(int port) | 创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用 于服务端) |
常用方法
方法 | 方法说明 |
void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该方法会阻 塞等待) |
void send(DatagramPacket p) | 从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
DatagramPacket API
构造方法
方法签名 | 方法说明 |
DatagramPacket(byte[] buf, int length) | 构造一个DatagramPacket以用来接收数据报,接收的数据保存在 字节数组(第一个参数buf)中,接收指定长度(第二个参数 length) |
DatagramPacket(byte[] buf, int length, SocketAddress address) | 构造一个DatagramPacket以用来发送数据报,发送的数据为字节 数组(第一个参数buf)中,从0到指定长度(第二个参数 length)。address指定目的主机的IP和端口号 |
常用方法
方法签名 | 方法说明 |
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取 接收端主机IP地址 |
int getPort() | 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获 取接收端主机端口号 |
byte[] getData() | 获取数据报中的数据 |
InetSocketAddress API
InetSocketAddress是ScketAddress的一个子类,用来包装IP与端口号
方法 | 方法说明 |
InetSocketAddress(InetAddress addr, int port) | 创建一个Socket地址,包含IP地址和端口号 |
示例一:
客户端像服务器发出请求,但服务器无响应版本
服务器:
public class UdpServer {private DatagramSocket socket= null;public UdpServer(int port) throws SocketException {//构造方法this.socket = new DatagramSocket(port);}public void start() throws IOException {//作为启动服务器的方法while(true){//因为不知道什么时候客户端会发送请求//作为服务器,需要不停的接收客户端的请求//创建packetbyte[] bytes = new byte[1024];DatagramPacket packet = new DatagramPacket(bytes,bytes.length);//用bytes作为接收,使用的长度为bytes的长度System.out.println("等待接收数据中...");socket.receive(packet);//还没收到之前会进行阻塞等待//此处的版本没有作出响应//我们可以打印出收到的packet中的数据看看有什么东西System.out.println("IP: " + packet.getAddress().getHostAddress());System.out.println("端口号: " + packet.getPort());System.out.printf("文本数据为: " + new String(packet.getData()));System.out.println("原始数据为: " + Arrays.toString(packet.getData()));}}public static void main(String[] args) throws IOException {UdpServer udpServer = new UdpServer(1024);udpServer.start();}
}
客户端:
方法一:
public class UdpClient {public static void main(String[] args) throws IOException {//创建SocketDatagramSocket socket = new DatagramSocket();//创建一个socket,端口号为系统随机分配//构建Packetbyte[] bytes = "Hello World".getBytes();//字符串转换成byte再塞进数组SocketAddress address = new InetSocketAddress("localhost",1024);//目的IP为本地地址,端口号为1024DatagramPacket packet = new DatagramPacket(bytes,bytes.length,address);//构建packetsocket.send(packet);//发送System.out.println("发送完成");}
}
方法二:
public class UdpClient {private DatagramSocket socket = null;//socketprivate String serverIp;private int serverPort;public UdpClient(String serverIp,int serverPort) throws SocketException {this.socket = new DatagramSocket();this.serverIp = serverIp;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while(true){System.out.println("输入:");String text = scanner.next();if(text.equals("exit")){System.out.println("再见");break;}//需要用InetAddress将字符串钟的IP转换成地址形式//SocketAddress address = new InetSocketAddress("localhost",1024);//也可以创建一个实例进行包装IP与端口号//此处的长度是字节的长度噢,注意单位DatagramPacket packet = new DatagramPacket(text.getBytes(),text.getBytes().length,InetAddress.getByName(serverIp),serverPort);socket.send(packet);System.out.println("发送成功");}}public static void main(String[] args) throws IOException {UdpClient client = new UdpClient("127.0.0.1",1024);client.start();}
先启动服务器后启动客户端发送.
记得打开IDEA可以同时运行两个进程的选项噢!
服务器接收到的信息为:
示例二:
做一个服务器对客户端有响应的版本
简单的英汉翻译
服务器:
public class UdpServerResponse{private DatagramSocket socket= null;public UdpServerResponse(int port) throws SocketException {//构造方法this.socket = new DatagramSocket(port);}public void start() throws IOException {//启动服务器while(true){byte[] bytes = new byte[1024];DatagramPacket receivePacket = new DatagramPacket(bytes,bytes.length);//创建包来接收System.out.println("等待接收数据中...");socket.receive(receivePacket);//接收包String request = new String(receivePacket.getData(),0,receivePacket.getLength());//根据接收到的包转换成字符串String response = process(request);//对请求进行分析//记得是getSocketAddress噢里面通常包含了IP与端口号DatagramPacket sendPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,receivePacket.getSocketAddress());socket.send(sendPacket);//对客户端作出响应System.out.println("客户端IP: " + receivePacket.getAddress());System.out.println("客户端端口号: " + receivePacket.getPort());System.out.println("收到的文本: " + request);System.out.println("返回的文本: " + response);}}public String process(String request){//解析请求,看看要做什么//这里就做一个英汉翻译吧HashMap<String,String> map = new HashMap<>();map.put("人","human");map.put("猫","cat");map.put("狗","dog");return map.getOrDefault(request,"查阅失败");}public static void main(String[] args) throws IOException {UdpServerResponse udpServerResponse = new UdpServerResponse(1024);udpServerResponse.start();}
}
客户端:
public class UdpClientResponse {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpClientResponse(String serverIp,int serverPort) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;socket = new DatagramSocket();}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while (true) {System.out.print("输入: ");String request = scanner.next();if(request.equals("exit")){System.out.println("再见!");break;}//根据请求创建包DatagramPacket sendPacket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName("127.0.0.1"),1024);socket.send(sendPacket);System.out.println("发送成功");DatagramPacket receivePacket = new DatagramPacket(new byte[1024],1024);//创建接收包socket.receive(receivePacket);String receive = new String(receivePacket.getData(),0,receivePacket.getLength());System.out.println(receive);}}public static void main(String[] args) throws IOException {UdpClientResponse udpClientResponse = new UdpClientResponse("127.0.0.1",1024);udpClientResponse.start();}
}
服务器的打印
客户端的打印
TCP流数据报套接字编程
ServerSocket API
创建TCP服务端的API
构造方法
构造方法 | 方法说明 |
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口 |
方法
方法签 名 | 方法说明 |
Socket accept() | 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket 对象,并基于该Socket建立与客户端的连接,否则阻塞等待 |
void close() | 关闭此套接字 |
Socket API
用来建立链接后保存对方的信息
构造方法:
方法 | 方法说明 |
Socket(String host, int port) | 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的 进程建立连接 |
常用方法
方法签名 | 方法说明 |
InetAddress getInetAddress() | 返回套接字所连接的地址 |
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
在TCP协议中的连接还分为长连接与短链接.
- 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据
- 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据
示例一:
一请求一响应
此处为长连接(把代码里的while(true)去掉就是短连接啦!只进行一次请求响应)
服务器:
对于服务器来说,每次与客户端连接后会创建一个socket来暂时存储客户端的信息数据
断开连接后,记得要将这个存储客户端数据的socket进行close释放掉
在服务器进程中,一个客户端socket会占用文件描述符的一个位置,一个服务器可能会要与成千上万个客户端进行通信,不释放就会将文件描述符的位置沾满造成泄露.
而服务器的serverSocket的生命周期与整个进程相当,且只有一个.所以可以不进行释放
使用线程池,用多线程的方式来运行服务器达到同时与多个客户端进行通信的功能.
public class TcpServer {private ServerSocket socket = null;public TcpServer(int port) throws IOException {socket = new ServerSocket(port);}public void start() throws IOException {//尝试链接ExecutorService threadPool = Executors.newCachedThreadPool();//创建一个线程池,一个线程对应一个客户端进行通信while (true) {Socket clientSocket = socket.accept();//会阻塞等待接受threadPool.submit(() -> {//向线程提供任务try {processConnect(clientSocket);} catch (IOException e) {e.printStackTrace();}});}}public void processConnect(Socket clientSocket) throws IOException {System.out.println("已与客户端进行链接-" + clientSocket.getInetAddress() + clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){while(true){Scanner scanner = new Scanner(inputStream);//读PrintWriter printWriter = new PrintWriter(outputStream);//写if(!scanner.hasNext()){//客户端不再传输数据就断开链接System.out.println("结束");break;}String request = scanner.next();//接收请求String response = process(request);//处理请求printWriter.println(response);//向客户端写回响应printWriter.flush();//记得写回后进行刷新缓冲区System.out.println("响应:" + clientSocket.getInetAddress() + clientSocket.getPort() + "文本: "+ response);}} catch (IOException e) {e.printStackTrace();}finally {clientSocket.close();//记得要关闭}}public String process(String request){HashMap<String,String> map = new HashMap<>();map.put("人","human");map.put("猫","cat");map.put("狗","dog");return map.getOrDefault(request,"查阅失败");}public static void main(String[] args) throws IOException {TcpServer tcpServer = new TcpServer(1024);tcpServer.start();}
}
客户端:
public class TcpClient {private Socket socket = null;private String serverIp;private int serverPort;public TcpClient(String serverIp,int serverPort) throws IOException {socket = new Socket(serverIp,serverPort);//客户端随机分配端口号this.serverIp = serverIp;this.serverPort = serverPort;}public void start(){try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {//创建流对象进行写与读while(true){Scanner scanner = new Scanner(System.in);//用来写入PrintWriter printWriter = new PrintWriter(outputStream);//包装output流对象String request = scanner.next();//写请求if(request.equals("exit")){System.out.println("结束与服务器连接");break;}//把请求放到流对象中写出去printWriter.println(request);printWriter.flush();//刷新缓冲区Scanner responseScanner = new Scanner(inputStream);String response = responseScanner.next();//读服务器的响应System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpClient tcpClient = new TcpClient("127.0.0.1",1024);tcpClient.start();}
}
服务器打印:
客户端打印:
相关文章:

[JAVAee]网络编程-套接字Socket
目录 基本概念 发送端与接收端 请求与响应 编辑客户端与服务器 Socket套接字 分类 数据报套接字 流套接字传输模型 UDP数据报套接字编程 DatagramSocket API DatagramPacket API InetSocketAddress API 示例一: 示例二: TCP流数据报套接字编程 ServerSock…...

批量导出pdf为zip文件(可以修改zip中pdf名称)
核心代码 public static void compressZip1(HashMap<String,File> map, String rootPath, String zipFileName) throws FileNotFoundException {FileOutputStream fileOutputStream new FileOutputStream(zipFileName);ZipOutputStream zipOutputStream new ZipOutputS…...
[国家集训队] Tree II 题解报告
[国家集训队] Tree II 一道真板子题 就是练习LCT懒标记的题目 除了翻转标记以外还要维护乘法标记和加法标记 注意加法标记和乘法标记的维护!!! 加法标记 因为splay的区间大小不是固定的,所以我们要维护size,并且…...
【redis】docker搭建redis集群
docker搭建redis集群,超级简单方便。 # 1. 拉取redis. 目前我拉取最新的是7.0.12 docker pull redis # 2. 下载配置文件 wget https://raw.githubusercontent.com/redis/redis/7.0/redis.conf # 3. 移到对应目录 mkdir -p /opt/docker/redis mv redis.conf /opt/d…...

前端个人年度工作述职报告(二十篇)
前端个人年度工作述职报告篇1 尊敬的各位领导、各位同仁: 大家好!按照20__年度我公司就职人员工作评估的安排和要求,我认真剖析、总结了自己的工作情况,现将本人工作开展情况向各位领导、同仁做以汇报,有不妥之处,希…...
TypeScript 编译配置
TypeScript的编译配置: 对单独一个ts文件进行监听编译 可使用tsc demo.ts -w 如果想对所有ts文件进行监听编译,监听到变化就自己编译,可以直接创建一个tsconfig.json文件。内容空着也OK:{},执行 tsc 或 tsc -w 如果有…...

使用DMA传输实现单片机高效串口转发——以STM32系列为例
使用DMA传输实现单片机高效串口转发——以STM32系列为例 DateAuthorVersionNote2023.08.06Dog TaoV1.01. 完成了文档的撰写。 文章目录 使用DMA传输实现单片机高效串口转发——以STM32系列为例应用场景实现流程源码示例串口与中断配置DMA外设配置DMA发送数据函数串口中断服务函…...

一文了解 Android Auto 车载开发~
作者:牛蛙点点申请出战 背景 我的的产品作为一个海外音乐播放器,在车载场景听歌是一个很普遍的需求。在用户反馈中,也有很多用户提到希望能在车上播放音乐。同时车载音乐也可以作为提升用户消费时长一个抓手。 出海产品,主要服务…...
Pixel4 安卓源码及内核修改编译教程 | 基于Android12 AOSP
之前整理了 Pixel4上的源码过程,下载的话大家可以去镜像网站下载,可以节约很多时间。 实验设备:Ubuntu18.04 32G2T Pixel4 文章目录 一、安卓源码下载1.准备下载环境(1)安装Python 3.9(2)安装g…...

如何做好Code Review
本文主要从我们为什么需要CR?CR面临哪些挑战?CR的最佳实践几个方面分析,希望可以给读者一些参考。 为什么需要CR? 代码质量 定性来看,大家都认可Code Review(后文简称CR)能显著改善代码质量&…...
Unity技术框架集合、Unity技术栈汇总
引擎技术尝试 [Animancer-Pro] (https://assetstore.unity.com/packages/tools/animation/animancer-pro-116514) (基于Playable的简单强大的动画解决方案)[ProBuilder/UModeler] (https://assetstore.unity.com/packages/tools/modeling/umodeler-80868) (快速关卡原型构建…...
安卓SDK开发的一些疑问
目前,公司需要开发一套iOS和安卓的sdk,主要包含蓝牙管理、网络请求、倒计时等方案执行、蓝牙数据交互等功能。之前没有过开发安卓sdk的经历,写个笔记用以记录。 现在iOS sdk已经写了一部分,安卓开发我也习惯从iOS的角度类比来开发…...

【基础类】—三栏页面布局的方案和优缺点
一、假设高度已知,中间宽度自适应,三栏(列)布局的方案有哪些? float浮动、absolute绝对定位、flex弹性盒子、table表格布局、grid网格布局 浮动 float <style>* {margin: 0;padding: 0;}.container {width: 1…...

OPENCV C++(四)形态学操作+连通域统计
形态学操作 先得到一个卷积核 Mat kernel getStructuringElement(MORPH_RECT,Size(5,5)); 第一个是形状 第二个是卷积核大小 依次为腐蚀 膨胀 开运算 闭运算 Mat erodemat,dilatemat,openmat,closemat;morphologyEx(result1, erodemat, MORPH_ERODE, kernel);morphologyEx…...

tomcat上部署jpress
一.确保有jdk,tomcat和mysql环境 二.新建jpress数据库,新建jpress用户并赋予所有权限 三.将jpress的war上传到tomcat/apache-tomcat-8.5.70/webapps,具体根据你的实际tomcat安装路径为准,上传完成后他会自己解包 四.到浏览器完…...
篇十:外观模式:简化复杂系统
篇十:“外观模式:简化复杂系统” 开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 另外有2本不错的关于设计模式的资料,分…...

linux gcc __attribute__
__attribute__ 1. 函数属性1.1 __attribute__((noreturn))1.2 __attribute__((format))1.3 __attribute__((const)) 2. 变量属性2.1. __attribute__((aligned))2.2. __attribute__((packed)) 3. 类型属性 __attribute__ 是 GCC 编译器提供的一种特殊语法,它可以用于…...

【SpringCloud】RabbitMQ基础
1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式: 同步通讯:就像打电话,需要实时响应。 异步通讯:就像发邮件,不需要马上回复。 两种方式各有优劣,打电话可以立即得到响应,…...

css, resize 拖拉宽度
效果如下: 可直接复制预览查看属性值: 关键样式属性: resize: horizontal; overflow-x: auto; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content…...

Python识别抖音Tiktok、巨量引擎滑块验证码识别
由于最近比较忙,所以本周搞了一个相对简单的验证码,就是抖音Tiktok的滑块验证码,这也是接到客户的一个需求。这种验证码通常在电脑端登录抖音、巨量引擎的的时候出现。 首先看一下最终的效果: 验证码识别过程 1、利用爬虫采集图…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...