JavaSE进阶--网络编程

news2024/11/27 0:20:19

文章目录

  • 前言
  • 一、网络编程
  • 二、通信
    • 1、两个重要的要素
    • 2、通信协议
  • 三 、Socket
  • 四、基于TCP的网络编程
    • 1、单向通信
      • 1.1 服务端
      • 1.2 客户端
    • 2、双向通信
      • 2.1 服务端
      • 2.2 客户端
    • 3、传输对象
      • 3.1 服务端
      • 3.2 客户端
    • 4、保持通信
      • 4.1 服务端
      • 4.2 客户端
  • 五、基于UDP的网络编程
    • 1、单向通信
      • 1.1 发送方
      • 1.2 接收方
    • 2、双向通信
      • 2.1 发送方
      • 2.2 接收方
    • 3、保持通信
      • 3.1 发送方
      • 3.2 接收方
  • 六、 总结

前言

📢 大家好,我是程序员Forlan,本篇内容主要分享网络编程的知识,属于基础内容,说实话,这块在大部分公司中,使用很少甚至可能用不上,游戏行业、视频行业可能使用多一些,可以根据情况学习,作一个知识补充~

一、网络编程

把分布在不同地方的计算机,用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源

计算机在网络中进行数据的传输,发送/接收数据

二、通信

1、两个重要的要素

IP+端口号

  • 通过IP可以定位到每台机器的唯一IP(IP定位机器)
  • 通过端口号可以定位到机器中的应用程序(端口号定位应用程序)

InetAddress:封装了IP

InetAddress ia2 = InetAddress.getByName("localhost");// 本地ip地址
System.out.println(ia2);
InetAddress ia3 = InetAddress.getByName("127.0.0.1");// 本地ip地址
System.out.println(ia3);
InetAddress ia4 = InetAddress.getByName("Forlan");// 计算机名
System.out.println(ia4); // 计算机名+ip
InetAddress ia5 = InetAddress.getByName("www.baidu.com");// 域名
System.out.println(ia5); // 域名+ip

InetSocketAddress:封装了IP,端口号

InetSocketAddress isa = new InetSocketAddress("127.0.0.1",8080);
System.out.println(isa);
System.out.println(isa.getHostName());
System.out.println(isa.getPort());

2、通信协议

表面看来,计算机之间的通信,是应用层之间的通信,但实际传输需要经过多层,如下图:

在这里插入图片描述
主要看的是传输层的协议,有TCP和UDP,两者的一个区别就是可不可靠,TCP需要三次握手和四次挥手,是比较可靠的,后面我们也会演示下不同的编程方式

三 、Socket

一般网络编程也叫Socket编程,Socket就是套接字,中文意思是插座

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。

Socket是由IP地址和端口结合的,它存在于通信区域,其实就是处理应用层和传输层,获取传输协议

  • 应用层:程序员写的代码,我们写的IO流,们最直接的感受,就是IO流的传输
  • 传输层:TCP或UDP传输

四、基于TCP的网络编程

1、单向通信

客户端给服务端发送一句话
注:先启动服务端,否则会报错Connection refused: connect

1.1 服务端

ServerSocket ss = null;
Socket s = null;
InputStream is = null;
DataInputStream dis = null;
try {
	// 1、创建套接字: 指定服务器的端口号
	ss = new ServerSocket(8888);
	// 2、阻塞等待接收客户端的数据,会返回客户端的Socket,才真正连接
	s = ss.accept();
	// 3、得到输入流,接收信息
	is = s.getInputStream();
	dis = new DataInputStream(is);
	System.out.println("收到客户端的信息:" + dis.readUTF());
} catch (IOException e) {
	e.printStackTrace();
} finally {
	try {
		if (null != ss) {
			ss.close();
		}
		if (null != s) {
			s.close();
		}
		if (null != is) {
			is.close();
		}
		if (null != dis) {
			dis.close();
		}
	} catch (IOException e) {
		e.printStackTrace();
	}

1.2 客户端

Socket s = null;
OutputStream os = null;
DataOutputStream dos = null;
try {
	// 1、创建套接字Socket,指定ip和端口号
	s = new Socket("127.0.0.1", 8888);
	// 2、得到输出流
	os = s.getOutputStream();
	// 转为处理流DataOutputStream,方面我们发文本
	dos = new DataOutputStream(os);
	dos.writeUTF("你好,我是程序员Forlan");
} catch (IOException e) {
	e.printStackTrace();
} finally {
	try {
		if (null != s) {
			s.close();
		}
		if (null != os) {
			os.close();
		}
		if (null != dos) {
			dos.close();
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
}

2、双向通信

客户端给服务端发送一句话,服务端回话
在单向通信的基础上,进行了优化简写,利用try(),无需关闭资源了

2.1 服务端

try (ServerSocket ss = new ServerSocket(8888);
	 Socket s = ss.accept();
	 InputStream is = s.getInputStream();
	 DataInputStream dis = new DataInputStream(is);
	 OutputStream os = s.getOutputStream();
	 DataOutputStream dos = new DataOutputStream(os);) {
	System.out.println("收到客户端的信息:" + dis.readUTF());
	dos.writeUTF("服务器已经收到啦~");
} catch (IOException e) {
	e.printStackTrace();
}

2.2 客户端

try (Socket s = new Socket("127.0.0.1", 8888);
	 OutputStream os = s.getOutputStream();
	 DataOutputStream dos = new DataOutputStream(os);
	 InputStream is = s.getInputStream();
	 DataInputStream dis = new DataInputStream(is);) {
	dos.writeUTF("你好,我是程序员Forlan");
	System.out.println("收到服务端的信息:" + dis.readUTF());
} catch (IOException e) {
	e.printStackTrace();
}

3、传输对象

定义Money对象,实现Serializable接口,进行传输

3.1 服务端

try (ServerSocket ss = new ServerSocket(8888);
	 Socket s = ss.accept();
	 InputStream is = s.getInputStream();
	 ObjectInputStream ois = new ObjectInputStream(is);
	 OutputStream os = s.getOutputStream();
	 DataOutputStream dos = new DataOutputStream(os);) {
	String msg = "转账成功";
	Money money = (Money) ois.readObject();
	System.out.println("收到客户端的信息:" + money);
	BigDecimal zero = new BigDecimal("0.0");
	if (null == money || money.getAmout().compareTo(zero) < 0) {
		msg = "转账失败";
	}
	dos.writeUTF(msg);
} catch (Exception e) {
	e.printStackTrace();
}

3.2 客户端

try (Socket s = new Socket("127.0.0.1", 8888);
	 OutputStream os = s.getOutputStream();
	 ObjectOutputStream oos = new ObjectOutputStream(os);
	 InputStream is = s.getInputStream();
	 DataInputStream dis = new DataInputStream(is);) {
	// 录入信息,发给服务端
	Scanner sc = new Scanner(System.in);
	System.out.println("请输入账户:");
	String account = sc.next();
	System.out.println("请输入金额:");
	BigDecimal amout = sc.nextBigDecimal();
	Money money = new Money(account, amout);
	oos.writeObject(money);
	// 接收服务端信息
	System.out.println("收到服务端的信息:" + dis.readUTF());
} catch (IOException e) {
	e.printStackTrace();
}

4、保持通信

前面实现的服务器,是针对一个请求服务,之后服务器就关闭了,想让服务器必须一直在监听 ,一直开着,等待客户端的请求

4.1 服务端

try (ServerSocket ss = new ServerSocket(8888);
	 Socket s = ss.accept();
	 InputStream is = s.getInputStream();
	 ObjectInputStream ois = new ObjectInputStream(is);
	 OutputStream os = s.getOutputStream();
	 DataOutputStream dos = new DataOutputStream(os);) {
	while (true) {
		String msg = "转账成功";
		Money money = (Money) ois.readObject();
		System.out.println("收到客户端的信息:" + money);
		BigDecimal zero = new BigDecimal("0.0");
		if (null == money || money.getAmout().compareTo(zero) < 0) {
			msg = "转账失败";
		}
		dos.writeUTF(msg);
	}
} catch (Exception e) {
	e.printStackTrace();
}

4.2 客户端

try (Socket s = new Socket("127.0.0.1", 8888);
	 OutputStream os = s.getOutputStream();
	 ObjectOutputStream oos = new ObjectOutputStream(os);
	 InputStream is = s.getInputStream();
	 DataInputStream dis = new DataInputStream(is);) {
	while (true) {
		// 录入信息,发给服务端
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入账户:");
		String account = sc.next();
		if (Objects.equals("退钱", account)) {
			System.out.println("告辞");
			break;
		}
		System.out.println("请输入金额:");
		BigDecimal amout = sc.nextBigDecimal();
		Money money = new Money(account, amout);
		oos.writeObject(money);
		// 接收服务端信息
		System.out.println("收到服务端的信息:" + dis.readUTF());
	}
} catch (IOException e) {
	e.printStackTrace();
}

五、基于UDP的网络编程

1、单向通信

1.1 发送方

// 1、创建套接字,指定我方的端口号
try (DatagramSocket ds = new DatagramSocket(1111);) {
	// 2、准备数据包,需要四个参数:数据的字节数组、字节数组长度、接收方的ip、接收方的端口号
	String str = "hello";
	byte[] bytes = str.getBytes();
	DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 2222);
	// 3、发送数据包
	ds.send(dp);
} catch (IOException e) {
	e.printStackTrace();
}

1.2 接收方

// 1、创建套接字,指定我方的端口号
try (DatagramSocket ds = new DatagramSocket(2222);) {
	// 2、准备空的数据包,用来接收其它地方传过来的
	byte[] b = new byte[1024];
	DatagramPacket dp = new DatagramPacket(b, b.length);
	// 3、接收对方的数据包,填充到dp中
	ds.receive(dp);
	// 4、取出数据
	byte[] data = dp.getData();
	String s = new String(data, 0, dp.getLength());
	System.out.println("程序员B说:" + s);
} catch (IOException e) {
	e.printStackTrace();
}

不需要存在接收方也不会报错

2、双向通信

2.1 发送方

try (Socket s = new Socket("127.0.0.1", 8888);
	 OutputStream os = s.getOutputStream();
	 ObjectOutputStream oos = new ObjectOutputStream(os);
	 InputStream is = s.getInputStream();
	 DataInputStream dis = new DataInputStream(is);) {
	// 录入信息,发给服务端
	Scanner sc = new Scanner(System.in);
	System.out.println("请输入账户:");
	String account = sc.next();
	System.out.println("请输入金额:");
	BigDecimal amout = sc.nextBigDecimal();
	Money money = new Money(account, amout);
	oos.writeObject(money);
	// 接收服务端信息
	System.out.println("收到服务端的信息:" + dis.readUTF());
} catch (IOException e) {
	e.printStackTrace();
}

2.2 接收方

// 1、创建套接字,指定我方的端口号
try (DatagramSocket ds = new DatagramSocket(2222);) {
	// 2、准备空的数据包,用来接收其它地方传过来的
	byte[] b = new byte[1024];
	DatagramPacket dp = new DatagramPacket(b, b.length);
	// 3、接收对方的数据包,填充到dp中
	ds.receive(dp);
	// 4、取出数据
	byte[] data = dp.getData();
	String s = new String(data, 0, dp.getLength());
	System.out.println("程序员B说:" + s);
	// 5、回复信息
	String str = "hi";
	byte[] bytes = str.getBytes();
	DatagramPacket dp2 = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 1111);
	ds.send(dp2);
} catch (IOException e) {
	e.printStackTrace();
}

3、保持通信

下面实现一种可以保持通信的UDP,发送方发送的时候,接收方要启动,不然发送方一直等着,接收方也一直等着

3.1 发送方

// 1、创建套接字,指定我方的端口号
try (DatagramSocket ds = new DatagramSocket(1111);) {
	while (true) {
		// 2、准备数据包,需要四个参数:数据的字节数组、字节数组长度、接收方的ip、接收方的端口号
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入消息:");
		String msg = sc.next();
		byte[] bytes = msg.getBytes();
		DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 2222);
		// 3、发送数据包
		ds.send(dp);
		if (Objects.equals("bye", msg)) {
			System.out.println("溜了~");
			break;
		}
		// 4、接收回复
		byte[] b = new byte[1024];
		DatagramPacket dp2 = new DatagramPacket(b, b.length);
		ds.receive(dp2);
		byte[] data = dp2.getData();
		String s = new String(data, 0, dp2.getLength());
		System.out.println("程序员A说:" + s);
	}
} catch (IOException e) {
	e.printStackTrace();
}

3.2 接收方

// 1、创建套接字,指定我方的端口号
try (DatagramSocket ds = new DatagramSocket(2222);) {
	while (true) {
		// 2、准备空的数据包,用来接收其它地方传过来的
		byte[] b = new byte[1024];
		DatagramPacket dp = new DatagramPacket(b, b.length);
		// 3、接收对方的数据包,填充到dp中
		ds.receive(dp);
		// 4、取出数据
		byte[] data = dp.getData();
		String msg = new String(data, 0, dp.getLength());
		System.out.print("程序员B说:" + msg);
		if (Objects.equals("bye", msg)) {
			System.out.println("程序员B开心去了");
			break;
		}
		// 5、回复信息
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入消息:");
		String str = sc.next();
		byte[] bytes = str.getBytes();
		DatagramPacket dp2 = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 1111);
		ds.send(dp2);
	}
} catch (IOException e) {
	e.printStackTrace();
}

六、 总结

TCP和UDP网络编程的区别:

  • TCP

客户端: 使用Socket,发送使用输出流,接收使用输入流
服务端: 使用ServerSocket监听得到Socket,接收使用输入流,发送使用输出流
客户端和服务端地位不平等
由客户端主动发起,和服务端建立连接,完成通信
服务端得先启动,不然客户端会报错

  • UDP

发送方和接收方,都是使用DatagramSocket 发送和接收的是DatagramPacket(数据包)
发送方和接收方的地位是平等的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/647217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解深度学习——Transformer:解码器(Decoder)的多头注意力层(Multi-headAttention)

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;基础知识 注意力机制&#xff08;Attention Mechanism&#xff09;&#xff1a;注意力汇聚与Nadaraya-Watson核回归 注意力机制&…

AI 绘画(1):生成一个图片的标准流程

文章目录 文章回顾感谢人员生成一个图片的标准流程前期准备&#xff0c;以文生图为例去C站下载你需要的绘画模型导入参数导入生成结果&#xff1f;可能是BUG事后处理 图生图如何高度贴合原图火柴人转角色 涂鸦局部重绘 Ai绘画公约 文章回顾 AI 绘画&#xff08;0&#xff09;&…

Fluent基于profile定义变量

1 概述 Profile中文可称呼为数据表&#xff0c;是Fluent中一种定义边界条件和体积域条件的方式。数据表主要用于将实验、第三方软件等其他数据源的物理场分布数据传递给Fluent。 Profile文件为CSV或PROF格式的文本文件&#xff0c;记录了物理场分布规律。 profile文件示意&…

智警杯初赛复现

eee考核的时候搭建环境出了问题。。虽然有点久远&#xff0c;但还能看看 1.克隆centos 先查看第一台的ip ifconfig 编辑另外两台 进入根目录 cd/ 编辑 vim /etc/sysconfig/network-scripts/ifcfg-ens33 更改项 IPADDR192.168.181.4 # 设置为想要的固定IP地址重启 2.…

K8S 基本概念

功能 1. 自动装箱 基于容器对应用运行环境的资源配置要求自动部署应用容器 2. 自我修复(自愈能力) 当容器失败时&#xff0c;会对容器进行重启。 当所部署的 Node 节点有问题时&#xff0c;会对容器进行重新部署和重新调度 当容器未通过监控检查时&#xff0c;会关闭此容器直到…

从零开始理解Linux中断架构(2)-朴素的中断管理设计理念

既然是从零开始,我们先从最为简单的中断逻辑处理架构开始,这个逻辑结构跟CPU架构没有关系,纯逻辑上的。纯逻辑是跨越系统和应用的,不管对于应用程序员还是系统程序员,逻辑推导是基本的工具,设计原型是基本的出发点。 中断发起的时候,PC指针被设置为中断向量表中相对应的…

轻量云服务器远程连接不了怎么办?

​  轻量云服务器为轻量级云计算服务&#xff0c;其可满足低需求、轻体验的个人和企业用户。但是&#xff0c;有时候我们会遇到轻量云服务器远程连接不了的问题&#xff0c;这对于需要远程管理服务器的用户来说是非常困扰的。本文展示了轻量云服务器无法正常远程连接的一些排…

测试老鸟总结,性能测试监控的关键指标(详全)你要的都有...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 稳定性测试的要点…

测试外包公司的妹子每天干15小时,被开发怼了几句,直接提桶跑路了。。。

最近我们公司的测试任务比较重&#xff0c;特别是我们组&#xff0c;每天都要加班两三个小时。我们组还有一个来公司才两三个月的妹子&#xff0c;工作挺认真的&#xff0c;每天加班两三个小时也没有抱怨什么&#xff0c;前几天看她每天太累了&#xff0c;要她放松一下别加那么…

编程示例: 计算CRC校验码

编程示例&#xff1a; 计算CRC校验码 循环冗余检查&#xff08;CRC&#xff09;是一种数据传输检错功能&#xff0c;对数据进行 多项式计算&#xff0c;并将得到的结果附在帧的后面&#xff0c;接收设备也执行 类似的算法&#xff0c;进而可以保证在软件层次上数据传输的正确性…

[golang 微服务] 6. GRPC微服务集群+Consul集群+grpc-consul-resolver案例演示

一. GRPC微服务集群概念 上一节讲解了consul集群: [golang 微服务] 5. 微服务服务发现介绍,安装以及consul的使用,Consul集群,这样的话,当一台server挂掉之后,集群就会从另一台server中获取服务,这就保证了客户端访问consul集群的负载均衡性. 这里还有一个问题: 就是当终端的对…

opencv初学记录

准备工作&#xff1a; 1.找一张图片 2.准备python运行环境&#xff0c;并导入库&#xff0c;pip install opencv-python 读取文件&#xff0c;并打印维度 import cv2 #为什么是cv2不是cv呢&#xff0c;这个2指的是c的api&#xff0c;是为了兼容老板&#xff0c;cv指的就是c&am…

设计模式(十七):行为型之状态模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

强化学习笔记-12 Eligibility Traces

前篇讨论了TD算法将MC同Bootstrap相结合&#xff0c;拥有很好的特性。本节所介绍的Eligibility Traces&#xff0c;其思想是多个TD(n)所计算预估累积收益按权重进行加权平均&#xff0c;从而得到更好的累积收益预估值。 价值预估模型的参数更新式子可以调整为&#xff1a; 1. O…

Vue CLI $nextTick 过渡与动画

3.12.$nextTick 这是一个生命周期钩子 **this.$nextTick(回调函数)**在下一次DOM更新结束后执行其指定的回调 什么时候用&#xff1a;当改变数据后&#xff0c;要基于更新后的新DOM进行某些操作时&#xff0c;要在nextTick所指定的回调函数中执行 使用 $nextTick 优化 Todo…

【UE 从零开始制作坦克】2-控制坦克移动(简单的移动效果)

效果 步骤 1. 新建蓝图类&#xff0c;父类选择“VehicleWheel&#xff08;载具车轮&#xff09;” 这里就命名为“TankWheel” 双击打开“TankWheel”&#xff0c;设置形状半径为40 2. 打开 “BP_West_Tank_M1A1Abrams” 选中“网格体&#xff08;VehicleMesh&#xff09;&…

DeepSurvk部署教程

DeepSurvk部署教程 作者:千树、Totoro github项目地址 https://github.com/arturomoncadatorres/deepsurvk Pypi项目地址 https://pypi.org/project/deepsurvk/ 一、DeepSurvk简介 项目作者原话(翻译) DeepSurv 是一种 Cox 比例风险深度神经网络&#xff0c;用于模拟患者协变…

某网站指纹反爬处理

一、问题分析 【疑惑】&#xff1a;使用python的requests库发起get或post请求返回403代码错误&#xff0c;使用postman发起请求发现状态码<200>竟然成功了。这是什么原因&#xff1f;首先排除ip问题&#xff0c;ip有问题的话postman也访问不了。难道是headers出现了问题…

VanillaNet实战:使用VanillaNet实现图像分类

文章目录 摘要安装包安装timm安装 grad-cam 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集 摘要 论文翻译&#xff1a;https://blog.csdn.net/m0_47867638/article/details/131057152 官方源码&#xff1a;https://github.com/huawei-noah/VanillaNet VanillaNet…

【送书福利-第十二期】机工社Python与AI好书来袭!~

大家好&#xff0c;我是洲洲&#xff0c;欢迎关注&#xff0c;一个爱听周杰伦的程序员。关注公众号【程序员洲洲】即可获得10G学习资料、面试笔记、大厂独家学习体系路线等…还可以加入技术交流群欢迎大家在CSDN后台私信我&#xff01; 本文目录 一、前言二、书籍介绍1、认识AI…