01_网络编程_传统IO
网络编程
1.什么是网络编程
在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
如果想把一个计算的结果,或者是电脑上的文件通过网络传递给你的朋友,就需要用到网络编程。
在实际生活中,网络通信无处不在
- **应用场景:**即时通信、网游对战、金融证券、国际贸易、邮件、等等
不管是什么场景,都是 计算机 跟 计算机 之间通过网络进行数据传输。
- Java中可以使用
java.net
包下的技术轻松开发出常见的网络应用程序。
目前市面上常见的软件架构:
- B/S
- C/S
不管是 B/S 架构,还是 C/S 架构,客户端/浏览器负责的仅仅是把数据展示出来,展示给用户去看。在项目中,真正核心的逻辑都是在服务器当中的。
BS架构的优缺点
- 不需要开发客户端,只需要页面 + 服务端
- 用户不需要下载,打开浏览器就能使用
- B/S 的特点主要突出一个:方便
- 如果应用过大,用户体验受到影响
CS架构的优缺点
- 画面可以做的非常精美,用户体验好(因为所有资源都被用户下载到了本地)
- 需要开发客户端,也需要开发服务端(针对公司而言,CS架构的开发、安装、部署、维护非常麻烦)
- 用户需要下载和更新的时候太麻烦
二者都有各自的优缺,具体用哪种,需要结合当前项目的特点来断定。一般而言,是类似于 LOL、王者荣耀这种游戏,它对于画面、音乐都有非常大的要求,就用 CS 架构;如果类似与新闻这种对画面没有太大要求的就可以使用 BS 架构。
2.网络编程三要素
两台计算机只要需要知道哪些东西才能进行数据传输呢?特别是,我想要给一堆电脑中的其中一台发送数据,需要知道哪些参数才可以呢?
- 确定对方电脑在互联网上的地址,这个地址是唯一的——IP
- 确定接收数据的软件,从微信->微信,而不是微信->qq,一个端口号只能被一个软件绑定——端口号
- 确定网络传输的规则,数据在传输的时候,我们不能随便书写它的格式,想怎么写就怎么写——协议
需要知道 IP、端口、协议,才能进行数据的传输。手机、IPAD、笔记本,都是可以上网的,只要上网,都需要有一个 IP,所以此处写的是设备。
IP
全程:Internet Protocol,是互联网协议地址,也称 IP 地址。是分配给上网设备的数字标签。
通俗理解
上网设备在网络中的地址,是唯一的
常见的IP分类为
IPV4、IPV6
IPV4
全称:Internet Protocol version 4,互联网通信协议第四版。
采用 32 位地址长度,分为 4 组
真实的 IP 是 32 bit 的二进制数
因为不好记也不好用,后来采用点分十进制表示法将 8 个 bit 作为一组转化为 10进制,总共分为4组,它们是无符号数,每一组的取值范围是 0 ~ 255。
IPV4 的缺点:在 IPV4 中总共只有不到 43 亿个 IP,IPV4 的数量是有限的,是不够使用的,2019年11月26日全部分配完毕。为了解决 IP 不够用的问题,出现了 IPV6。
IPV6
全称:Internet Protocol version 6,互联网通信协议第六版。
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而 IPV4 的模式下 IP 的总数是有限的。
IPV6 采用 128 位地址长度,分为 8 组,每一组是 16 个 bit。IPV6 可以给地球上每一粒沙子都定义一个 IP。
目前 IPV6 还未普及,在不久的将来,IPV6 会超越 IPV4,成为市场的主流。
IPV4已经分配完了,IPV6还未普及,目前如何解决IP不够用的问题?
IPV4的地址分类形式
- 公网地址(万维网使用)和私有地址(局域网使用)。
- 192.168. 开头的就是私有地址,范围为 192.168.0.0 ~ 192,168.255.255,专门为组织机构内部使用,以此节省 IP
在网吧中所有电脑共享同一个公网 IP,再由路由器给每一台电脑分配局域网 IP,这样就可以实现节约 IP 的效果。
特殊IP地址
127.0.0.1,也可以是 localhost: 是回送地址也称本地回环地址,也称本地本机 IP,永远只会寻找当前所在本机。
疑问: 假设 192.168.1.100 是我电脑的 IP,那么这个 IP 跟 127.0.0.1 是一样的吗?
它们是不一样的。
假设我们现在有一堆电脑,它们的 IP 都是由路由器分配的。
每一个路由器给设备分配的 IP 可能是不一样的,所以会有这么一个情况:当我们换了一个地方上网,我们上网设备的局域网 IP 有可能不一样。
但是,如果我们往 127.0.0.1 发送数据,那么它是不经过路由器的。我们的数据经过网卡的时候,网卡发现,我们要往 127.0.0.1 发送数据,此时,它就把这个数据给我们自己发过来了,不管在哪里上网,永远都是这样的。这就是两者的区别。
建议: 在练习的时候,如果我们是自己给自己发送数据,就写 127.0.0.1 就可以了。
常见 CMD 命令
- ipconfig: 查看本机 IP 地址
- ping: 检查网络是否连通,不仅可以检查局域网是否畅通,还可以检查外网是否畅通。在 ping 的后边,既可以跟随 IP,也可以跟随 网址。
网址的底层逻辑其实也是 ip
InetAddress 的使用
在Java中用来表示 IP 的类:InetAddress
在底层它会进行判断,我们用的是 6 版本的还是 4 版本的,如果是 4 版本的,它其实创建的是它的子类 Inet4Address 的对象并返回;如果是 6 版本的则会创建 Inet6Address 并返回。
由于该类没有对外暴露构造方法,所以我们需要通过它的构造方法 getByName 来获取它的对象。这个方法的底层其实就是判断是 IPV4 和 IPV6,判断完之后会创建对应的子类对象并返回。
public class MyInetAddressDemo1 {public static void main(String[] args) throws Exception {/*** static InetAddress getByName(String host) 确定主机名称的 ip 地址。主机名称可以是及其名称,也可以是 ip 地址* String getHostName() 获取 IP 地址的主机名* String getHostAddress() 返回文本显示中的 IP 地址字符串*/// 1.获取 InetAddress 的对象// IP 的对象 ——> 一台电脑的对象InetAddress address = InetAddress.getByName("192.168.0.105");System.out.println("ipv4 address:" + address); // ipv4 address:/192.168.0.105// 主机名其实就是我们给自己电脑起的名字,如果没起也会有默认的 Win + E 打开我的电脑,右键 + 属性可以查看InetAddress address2 = InetAddress.getByName("DESKTOP-V32JVCD");System.out.println("hostname:" + address2); // hostname:DESKTOP-V32JVCD/192.168.0.105// getHostName 方法的小细节:如果电脑因为网络原因或者局域网中压根就没有这台电脑,此时获取不到主机名,此时以 IP 的形式进行展示String hostName = address.getHostName();System.out.println(hostName); // 192.168.0.105System.out.println(address2.getHostName()); // DESKTOP-V32JVCDString hostAddress = address.getHostAddress();System.out.println(hostAddress); // 192.168.0.105System.out.println(address2.getHostAddress()); // 192.168.0.105/*** 这只是一个前置的代码,一旦我们获取到 IP 之后,我们就可以给某一台电脑发送消息了*/}
}
端口号
应用程序在设备中唯一的标识
端口号:由两个字节表示的整数,取值范围:0~65535
其中 0 ~ 1023 之间的端口号用于一些知名的网络服务或者应用
我们自己使用 1024 以上的端口号就可以了。
注意:一个端口号只能被一个应用程序使用。
端口其实就是电脑往外发送数据的出口,或者说是电脑接收外部数据的入口。
软件一运行就要绑定一个端口,如果没有绑定端口,那么它就是单击的,是无法往外发送数据/接收数据的。
协议
在计算机网络中,连接和通信的规则被称为网络通信协议。协议就是数据传输的规则
在传输数据的时候,国际标准组织定义了一个 OSI 的网络参考模型,把传输数据分成了7层
- OSI 参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广。
- TCP/IP 参考模型(或 TCP/IP 协议):事实上的国际标准。
代码运行在应用层,如果我们想给对方电脑发送数据,则会一层一层的往下,到达物理层,然后转化为二进制数据,再发送给对方电脑。对方电脑接收到数据之后会进行解析,再一层一层的传输给最上方的应用层,我们的程序就可以接收到数据了。
UDP 协议
-
用户数据报协议(User Datagram Protocol)
-
UDP 是 面向无连接 通信协议。
速度快,有大小限制一次最多发送 64 k,数据不安全,易丢失数据
面向无连接:UDP 协议传输数据时,不会管两台设备之间的网络是否畅通,直接发,你能收到就收到,收不到就拉倒。
UDP 适用于丢失一点数据不会产生任何影响的场景,比如:网络会议、语言通话、在线视频
TCP 协议
-
传输控制协议 TCP(Transmission Control Protocol)
-
TCP 协议是 面向连接 的通信协议。
速度慢,没有大小限制,数据安全。
TCP 发送数据之前会先检查两台设置之间的网络畅通。简单来说,就是确保连接成功才会发送数据。
TCP 适用于对数据有非常大的需求,一点都不能丢的情况。比如:下载软件、文字聊天、发送邮件
3.UDP通信程序
UDP 通信程序(发送数据)
UDP 协议发送数据
public class SendMessageDemo {public static void main(String[] args) throws Exception {// 发送数据// 1.创建 DatagramSocket对象(快递公司)// 细节:// 绑定端口:以后我们就是通过这个端口往外发送数据// 空参:所有可用的端口中随机一个进行使用// 有参:指定端口号进行绑定// DatagramSocket socket = new DatagramSocket(8000);DatagramSocket socket = new DatagramSocket();// 2.打包数据String str = "你好威猛啊!!!";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);// 3.发送数据socket.send(dp);// 4.释放资源socket.close();}
}
UDP 通信程序(接收数据)
注意:一定得先运行接收端再运行发送端
public class ReceiveMessageDemo {public static void main(String[] args) throws Exception {// 接收数据// 注意:一定得先运行接收端再运行发送端// 1.创建DatagramSocket对象(快递公司)// 细节:// 在接收的时候,一定要绑定端口// 而且绑定的端口,一定要跟发送的端口保持一直DatagramSocket socket = new DatagramSocket(10086);// 2.接收数据包,既然此处是用来接收数据的,所以只需要传一个数组即可,IP 和 端口就不用了byte[] bytes = new byte[1024];DatagramPacket packet = new DatagramPacket(bytes, bytes.length);// 该方法是阻塞的// 程序执行到这一步的时候,会在这里死等// 等发送端发送消息socket.receive(packet);// 3.解析数据包byte[] data = packet.getData();int length = packet.getLength();InetAddress address = packet.getAddress();int port = packet.getPort();System.out.println("接收到的数据" + new String(data, 0, length));System.out.println("该数据是从" + address + "这台电脑中的" + port + "端口发送过来的");//4.资源释放socket.close();}
}
从哪个端口发出无所谓,只要发送的 ip + port 指向接收端即可。
练习:聊天室
public class SendMessageChat {public static void main(String[] args) throws Exception {DatagramSocket socket = new DatagramSocket(7070);Scanner scanner = new Scanner(System.in);while (true) {System.out.println("请输入您要说的话");String next = scanner.nextLine();byte[] bytes = next.getBytes();DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 7071);socket.send(packet);if (next.equals("886")) {break;}}System.out.println("退出发送端");socket.close();}
}
public class ReceiveMessageChat {public static void main(String[] args) throws Exception {DatagramSocket socket = new DatagramSocket(7071);// 每次接收到数据都会对 bytes 进行覆盖byte[] bytes = new byte[1024];DatagramPacket packet = new DatagramPacket(bytes, bytes.length);while (true) {socket.receive(packet);System.out.println(packet.getAddress().getHostAddress() + ":" + packet.getPort() + "的设备发来数据:" + new String(packet.getData(), 0, packet.getLength()));}}
}
允许某个类可以允许多个
UDP 的三种通信方式
-
单播:一对一,左边的发送端只给右边的一台设备发送消息
以前的代码就是单播
-
组播:可以给一组设备发送消息
组播地址:224.0.0.0 ~ 239.255.255.255
其中 244.0.0.0 ~ 244.0.0.255 为预留的组播地址(我们自己想用只能用这个范围之内的)
之前的 ip 只能表示一台电脑,而这里随便一个组播地址就可以表示多台电脑
组播发送端代码
public class SendMessageDemo {public static void main(String[] args) throws Exception {/*** 组播发送代码*/// 通过 MulticastSocket 对象MulticastSocket ms = new MulticastSocket();// 创建 DatagramPacket 对象String str = "你好,你好!";byte[] bytes = str.getBytes();// 发送时指定 IP 地址一定要指定组播地址InetAddress address = InetAddress.getByName("224.0.0.1");int port = 10000;DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, port);// 调用 MulticastSocket 发送数据方法发送数据ms.send(datagramPacket);// 释放资源ms.close();} }
组播接收端代码
public class ReceiveMessageDemo1 {public static void main(String[] args) throws Exception {/*** 组播接收端代码*/// 1.创建 MulticastSocket 对象MulticastSocket ms = new MulticastSocket(10000);// 2.将当前本机,添加到 224.0.0.1 的这一组当中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);// 3.创建 DatagramPacket 数据包对象byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);// 4.接收数据ms.receive(dp);// 5.解析数据byte[] data = dp.getData();int len = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip 为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));// 6. 释放资源ms.close();} }
-
广播:可以给局域网中所有设备发送消息
广播地址:255.255.255
广播代码几乎和单播一模一样,只需要修改 ip 地址为 255.255.255.255 即可
广播发送端
public class SendMessageDemo {public static void main(String[] args) throws Exception {// 发送数据// 1.创建 DatagramSocket对象(快递公司)// 细节:// 绑定端口:以后我们就是通过这个端口往外发送数据// 空参:所有可用的端口中随机一个进行使用// 有参:指定端口号进行绑定// DatagramSocket socket = new DatagramSocket(8000);DatagramSocket socket = new DatagramSocket();// 2.打包数据String str = "你好威猛啊!!!";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("255.255.255.255");int port = 10000;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);// 3.发送数据socket.send(dp);// 4.释放资源socket.close();}
}
广播接收端:
public class ReceiveMessageDemo {public static void main(String[] args) throws Exception {// 接收数据// 注意:一定得先运行接收端再运行发送端// 1.创建DatagramSocket对象(快递公司)// 细节:// 在接收的时候,一定要绑定端口// 而且绑定的端口,一定要跟发送的端口保持一直DatagramSocket socket = new DatagramSocket(10000);// 2.接收数据包,既然此处是用来接收数据的,所以只需要传一个数组即可,IP 和 端口就不用了byte[] bytes = new byte[1024];DatagramPacket packet = new DatagramPacket(bytes, bytes.length);socket.receive(packet);// 3.解析数据包byte[] data = packet.getData();int length = packet.getLength();InetAddress address = packet.getAddress();int port = packet.getPort();System.out.println("接收到的数据" + new String(data, 0, length));System.out.println("该数据是从" + address + "这台电脑中的" + port + "端口发送过来的");//4.资源释放socket.close();}
}
4.TCP通信程序
TCP 通信协议是一种可靠的网络协议,它在通信的两端各建立一个 Socket 对象
通信之前要保证连接已经建立
通过 Socket 产生 IO 流来进行网络通信
TCP 发送数据
public class Client {public static void main(String[] args) throws Exception {// TCP 协议,发送数据// 1.创建 Socket 对象// 细节:在创建对象的同时会连接服务端,如果连接不上,代码会报错Socket socket = new Socket("127.0.0.1", 10000);// 2.可以从连接通道中获取输入流OutputStream os = socket.getOutputStream();// 写出数据os.write("你好你好".getBytes()); // 字节流输出时只能输出字节数据// 3.释放资源os.close();socket.close();}
}
TCP 读取数据
public class Server {public static void main(String[] args) throws Exception {// TCP 协议,接收数据// 1.创建对象 ServerSocket// 注意:创建对象时一定要绑定一个端口,而且此端口一定要跟客户端连接的端口保持一致// 如果不一致的话,客户端还是连接不上ServerSocket serverSocket = new ServerSocket(10000);// 2.监听客户端的连接Socket socket = serverSocket.accept();// 3.从连接通道中获取输入流读取数据/*InputStream is = socket.getInputStream();// 结局中文乱码问题:写的时候是把一个中文字符分为3个字节来输出,读的时候需要一个字符一个字符的读InputStreamReader isr = new InputStreamReader(is);*/BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int buff;while ((buff = br.read()) != -1) {System.out.print((char) buff);}// 4.释放资源br.close();// 断开于客户端之间的连接socket.close();// 关闭服务器serverSocket.close();}
}
TCP 通信程序(三次握手)
ICMP协议
TCP 通信程序(四次挥手)
ICMP协议
四次回收必须等待服务端把连接通道里的数据处理完毕了连接才能断开
5.综合练习
TCP通信练习1 — 多发多收
客户端:多次发送数据
public class Client {public static void main(String[] args) throws Exception {// 客户端:多次发送数据// 服务器:接收多次接收数据,并打印// 1.创建 Socket 对象并连接服务端Socket socket = new Socket("127.0.0.1", 10000);// 2.写出数据OutputStream outputStream = socket.getOutputStream();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入您要发送的信息");String msg = sc.nextLine();if (msg.equals("886")) {break;}outputStream.write(msg.getBytes());}System.out.println("客户端下线!");// 3.释放资源sc.close();socket.close();}
}
服务端:接收多次接收数据,并打印
public class Server {public static void main(String[] args) throws Exception {// 客户端:多次发送数据// 服务器:接收多次接收数据,并打印// 1. 创建对象绑定 10000 端口ServerSocket serverSocket = new ServerSocket(10000);// 2.等待客户端连接Socket socket = serverSocket.accept();// 3.读取数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int buff;while ((buff = br.read()) != -1) {System.out.print((char) buff);}// 4.释放资源socket.close();serverSocket.close();}
}
TCP通信练习2 — 接收和反馈
客户端:发送一条数据,接收服务端反馈的消息并打印
public class Client {public static void main(String[] args) throws Exception {// 客户端:发送一条数据,接收服务端反馈的消息并打印// 服务端:接收数据并打印,再给客户端反馈消息// 1.创建 Socket 对象连接服务器Socket socket = new Socket("127.0.0.1", 10000);// 2.写出数据String str = "见到你很高兴!";OutputStream os = socket.getOutputStream();os.write(str.getBytes());// 写出一个结束标记socket.shutdownOutput(); // 结束输出流// 3.接收服务端回写的数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int b;while ((b = br.read()) != -1) {System.out.print((char) b);}// 4.释放资源socket.close();}
}
服务端:接收数据并打印,再给客户端反馈消息
public class Server {public static void main(String[] args) throws Exception {// 客户端:发送一条数据,接收服务端反馈的消息并打印// 服务端:接收数据并打印,再给客户端反馈消息// 1.创建对象并绑定 10000 端口ServerSocket ss = new ServerSocket(10000);// 2.等待客户端连接Socket socket = ss.accept();// 3.socket中获取输入流读取数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int b;/*** 细节:* read 方法会从连接通道中读取数据* 但是,需要有一个结束标记,此处的循环才会停止* 否则,程序就会一直停在 read 方法这里,等待读取下面的数据*/while ((b = br.read()) != -1) {System.out.print((char) b);}// 4.回写数据String str = "到底有多开心?";OutputStream os = socket.getOutputStream();os.write(str.getBytes());// 5.释放资源socket.close();ss.close();}
}
TCP通信练习3 — 上传文件
客户端:将本地文件上传到服务器。接收服务器的反馈。
public class Client {public static void main(String[] args) throws Exception {// 客户端:将本地文件上传到服务器。接收服务器的反馈。//服务器:接收客户端上传的文件,上传完毕之后给出反馈。// 1.创建 Socket 对象连接服务器Socket socket = new Socket("127.0.0.1", 10000);// 2.读取本地文件中的数据,并写到服务器中BufferedInputStream bis = new BufferedInputStream(new FileInputStream("./clientdir/a.png"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}// 输出文件结束符socket.shutdownOutput();// 回写数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));System.out.println(br.readLine());// 3.释放资源bis.close();socket.close();}
}
服务器:接收客户端上传的文件,上传完毕之后给出反馈。
public class Server {public static void main(String[] args) throws Exception {// 客户端:将本地文件上传到服务器。接收服务器的反馈。//服务器:接收客户端上传的文件,上传完毕之后给出反馈。// 1.创建对象并绑定 10000 端口ServerSocket ss = new ServerSocket(10000);// 2.等待客户端连接Socket socket = ss.accept();// 3.读取数据并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./serverdir/b.png"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}// 回写数据BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功!");bw.newLine();bw.flush();// 4.释放资源bos.close();socket.close();ss.close();}
}
TCP通信练习4 — 上传文件(文件名重复问题)
解决上一题文件名重复问题
客户端不变,服务端输出文件时文件名使用 UUID 生成
public class Server {public static void main(String[] args) throws Exception {// 客户端:将本地文件上传到服务器。接收服务器的反馈。//服务器:接收客户端上传的文件,上传完毕之后给出反馈。// 1.创建对象并绑定 10000 端口ServerSocket ss = new ServerSocket(8000);// 2.等待客户端连接Socket socket = ss.accept();// 3.读取数据并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());String name = UUID.randomUUID().toString().replace("-", "") + ".png";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./serverdir/" + name));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}// 回写数据BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功!");bw.newLine();bw.flush();// 4.释放资源bos.close();socket.close();ss.close();}
}
TCP通信练习5 — 上传文件(多线程版)
想要服务器不停止,能接收很多用户上传的图片。
该怎么做呢?
提示:可以用循环或者多线程。
但是循环不合理,最优解法是多线程改写。
public class Server {public static void main(String[] args) throws Exception {// 客户端:将本地文件上传到服务器。接收服务器的反馈。// 服务器:接收客户端上传的文件,上传完毕之后给出反馈。// 1.创建对象并绑定 10000 端口ServerSocket ss = new ServerSocket(8000);while (true) {// 2.等待客户端连接Socket socket = ss.accept();// 开启一条线程// 一个用户就对应服务端的一条线程new Thread(new MyRunnable(socket)).start();}}static class MyRunnable implements Runnable {private Socket socket;public MyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {// 3.读取数据并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());String name = UUID.randomUUID().toString().replace("-", "") + ".png";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("serverdir/" + name));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}// 回写数据BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功!");bw.newLine();bw.flush();// 4.释放资源bos.close();} catch (IOException e) {throw new RuntimeException(e);} finally {if (null != socket) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}}
}
TCP通信练习6 — 上传文件(线程池版)
频繁创建并销毁线程非常浪费系统资源,所以需要用线程池优化。
public class Server {public static void main(String[] args) throws Exception {// 客户端:将本地文件上传到服务器。接收服务器的反馈。// 服务器:接收客户端上传的文件,上传完毕之后给出反馈。// 创建线程池对象ThreadPoolExecutor pool = new ThreadPoolExecutor(3, // 核心线程数16, // 线程池总大小60, // 空闲时间TimeUnit.SECONDS, // 空闲时间单位new ArrayBlockingQueue<>(2), // 阻塞队列Executors.defaultThreadFactory(), // 线程工厂:让线程池如何创建线程对象new ThreadPoolExecutor.AbortPolicy() // 拒绝策略);// 1.创建对象并绑定 10000 端口ServerSocket ss = new ServerSocket(8000);while (true) {// 2.等待客户端连接Socket socket = ss.accept();// 开启一条线程// 一个用户就对应服务端的一条线程pool.submit(new MyRunnable(socket));}}static class MyRunnable implements Runnable {private Socket socket;public MyRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {// 3.读取数据并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());String name = UUID.randomUUID().toString().replace("-", "") + ".png";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("serverdir/" + name));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}// 回写数据BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功!");bw.newLine();bw.flush();// 4.释放资源bos.close();} catch (IOException e) {throw new RuntimeException(e);} finally {if (null != socket) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}}
}
TCP通信练习7 — BS(接收浏览器的消息并打印)
客户端:不需要写
服务端:接收数据并打印
public class Server {public static void main(String[] args) throws Exception {// 服务端:BS架构->接收浏览器的消息并打印// 1.创建对象并绑定 10000 端口ServerSocket ss = new ServerSocket(8000);// 2.等待客户端连接Socket socket = ss.accept();// 3.socket中获取输入流读取数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int b;while ((b = br.read()) != -1) {System.out.print((char) b);}// 4.释放资源socket.close();ss.close();}
}
浏览器直接请求 127.0.0.1:8000 即可看到控制台输出:
GET / HTTP/1.1
Host: 127.0.0.1:8000
Connection: keep-alive
sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.76
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
TCP通信练习8 — 网络编程(课后大作业)
相关文章:
01_网络编程_传统IO
网络编程 1.什么是网络编程 在网络通信协议下,不同计算机上运行的程序,进行的数据传输。 如果想把一个计算的结果,或者是电脑上的文件通过网络传递给你的朋友,就需要用到网络编程。 在实际生活中,网络通信无处不在…...
vue 检查指定路由是否存在
今天路由跳转报错了 RangeError: Maximum call stack size exceeded 但显然 我的代码只有一个简单的路由跳转 并没有很大的的堆栈数据操作 所以 我就联想到了 会不会是因为路由不存在 我们可以通过 console.log(this.$router.options.routes)输出整个路由对象类看一下 或者…...
自动化办公更简单了:新版python-office,有哪些更新?
#职场经验谈# 大家好,这里是程序员晚枫,小破站/小红薯都叫这个名。 去年4月开源了一个Python自动化办公项目:python-office,GitHub和Gitee都能看到。1行代码实现复杂的自动化办公任务,帮助不懂代码的小白,…...
windows flask服务卡死的问题
windows flask服务卡死的问题 最近的工作中,需要用python写一个flask服务,供C端调用,但是偶尔服务会卡住,只接收数据但不进行处理,不过CtrlC后又可以继续运行。 查看了网上的一些解决方法,但似乎都没有什…...
项目上线部署--》服务器部署流程(一)
目录 🌟准备工作 服务器购买 域名购买 域名解析(配置 DNS) 🌟服务器环境搭建 配置服务器 安装 CentOS 开发人员相关包 编辑 配置免密登陆 🌟写在最后 🌟准备工作 服务器购买 国内服务器&#x…...
Python:函数调用的实参
相关阅读 Python专栏https://blog.csdn.net/weixin_45791458/category_12403403.html 调用就是附带可能为空的一系列参数来执行一个可调用对象 (例如函数),它的语法的BNF范式如下所示,有关BNF范式的规则,可以参考之前…...
174. 地下城游戏 -- 动规
174. 地下城游戏 class CalculateMinimumHP:"""174. 地下城游戏https://leetcode.cn/problems/dungeon-game/"""def solution(self, dungeon: List[List[int]]) -> int:# 我们想计算左上⻆到右下⻆所需的最⼩⽣命值m, n len(dungeon), len(d…...
js实现websocket服务端和客户端
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
qt qml RadioButton如何设置字体颜色,style提示找不到怎么办?
qt QML中设置RadioButton的字体颜色,可以使用RadioButton的label属性来设置文本的样式。下面是一个示例代码: import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Controls 1.4 as Controls1_4 import QtQuick.Controls.Styles 1.4 import…...
Docker 的使用
一、Docker 的作用和优势 软件集装箱化平台,可让开发者构建应用程序时,将它与环境一起打包到一个容器中,发布应用到任意平台中。 能在单台机器上运行多个Docker微容器,而每个微容器里都有一个微服务或独立应用, 如&am…...
【无公网IP内网穿透】Java支付宝沙箱环境支付,SDK接口远程调试
目录 1.测试环境 2.本地配置 3. 内网穿透 3.1 下载安装cpolar内网穿透 3.2 创建隧道 4. 测试公网访问 5. 配置固定二级子域名 5.1 保留一个二级子域名 5.2 配置二级子域名 6. 使用固定二级子域名进行访问 1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付…...
axios 用formData的方式请求数据
需求:使用axios库用来做http数据传输。 问题:传递数据的时候不是直接通过json的方式来传输的数据,二是通过formData的方式 解决: axios 请求头设置,Content-Type "Content-Type": "application/x-w…...
Mapbox加载arcgis的底图
成果图 这种底图基本上都是按照raster来加载的,主要就是知道地址了,拼参数 具体参数请参考官网 https://developers.arcgis.com/rest/services-reference/enterprise/export-map.htm 源码 我的服务列表是这样的 http://XXXX:XXXX/arcgis/rest/services/…...
(20)线程安全问题:Lock,双锁问题,Monitor,死锁
一、Lock 1、用多线程给变量自增,10000个线程自增 List<Task> tasks new List<Task>();int AsyncNum 0;for (int i 0; i < 10000; i){tasks.Add(Task.Run(() >{AsyncNum;}));}Task.WaitAll(tasks.ToArray());Console.WriteLine($"AsyncNu…...
医院如何实现安全又稳定的跨网文件数据交换呢?
随着医疗信息化的发展,医院之间需要频繁地进行文件数据交换,以实现诊疗、科研、管理等方面的协同和共享。然而,由于医院网络环境的复杂性和敏感性,跨网文件数据交换面临着安全性和稳定性的双重挑战。如何在保证文件数据不被泄露、…...
关于老项目从JDK8升级到JDK17所需要注意的细节
文章目录 ☀️1.关于老项目从JDK8升级到JDK17所需要注意的细节🌸1.1.更新JDK🌸1.2.修改Idea中的JDK版本🌸1.3.关于修改过程中遇到的异常🌸1.4.IDEA工具栏操作Maven正常,但使用mvn命令运行就报错 ☀️1.关于老项目从JDK…...
《C++ primer》练习3.43-3.45: 打印二维数组的元素
文章目录 1. 使用范围for循环2. 使用普通for循环2.1 使用指针2.2 使用数组下标 类型别名的简化 本文来自于《C primer》的练习3.43-3.45,觉得多维数组的遍历有不同的实现方式,于是记录一下。写的可能没有按题目的顺序来。题目大概含义是定义了一个二维数…...
使用电力系统稳定器 (PSS) 和静态 VAR 补偿器 (SVC) 提高瞬态稳定性(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
开源项目-SeaTunnel-UI数据集成系统
哈喽,大家好,今天给大家带来一个开源项目-SeaTunnel-UI数据集成系统 系统主要有任务配置,任务实例,数据源,虚拟表,用户管理等功能 登录 数据源 mysql数据源配置参数说明 kafka参数配置 mysqlcdc配置参数说明 虚拟表...
百度SEO优化策略与经验分享(提升百度排名的8大步骤)
百度关键词优化策略介绍:蘑菇号https://www.mooogu.cn/ 百度搜索引擎优化,简称为百度SEO,是一种通过优化网站结构和内容,提高网站在百度搜索引擎中的排名,从而获得更多有价值的流量和销售机会的行业术语。百度SEO的核…...
【深度学习】- NLP系列文章之 1.文本表示以及mlp来处理分类问题
系列文章目录 1. 文本分类与词嵌入表示,mlp来处理分类问题 2. RNN、LSTM、GRU三种方式处理文本分类问题 3. 评论情绪分类 还是得开个坑,最近搞论文,使用lstm做的ssd的cache prefetching,意味着我不能再划水了。 文章目录 系列文章…...
力扣236 补9.14
做不来,我做中等题基本上都是没有思路,这里需要先遍历祖先节点,那必然用先序遍历,这题还是官方题解容易理解,第二火的题解反而把我弄得脑袋昏昏的。 class Solution { TreeNode ans; public TreeNode lowestCommonAnce…...
一文搞定Postman(菜鸟必看)
什么是Postman? Postman是一个可扩展的 API 测试工具,可以快速集成到 CI/CD 管道中。它于 2012 年作为 Abhinav Asthana 的一个副项目启动,旨在简化测试和开发中的 API 工作流程。API 代表应用程序编程接口,它允许软件应用程序通…...
位图+布隆过滤器+海量数据并查集(它们都是哈希的应用)
一)位图: 首先计算一下存储一下10亿个整形数据,需要多大内存呢,多少个G呢? 2^3010亿,10亿个字节 byte kb mb gb 100000000个字节/1024/1024/10241G 所以10亿个字节就是1G,所以40亿个字节就是4G,也就是10个整…...
MYSQL:Select语句顺序
SELECT子句及其顺序整理表格: 子句 说明是否必须使用SELECT 要返回的列或表达式是FROM 从中检索数据的表仅在从表选择数据使用WHERE 行级过滤否GROUP BY 分组说明仅在按组计算聚…...
Pytest系列-数据驱动@pytest.mark.parametrize(7)
简介 unittest 和 pytest参数化对比: pytest与unittest的一个重要区别就是参数化,unittest框架使用的第三方库ddt来参数化的 而pytest框架: 前置/后置处理函数fixture,它有个参数params专门与request结合使用来传递参数&#x…...
【Qt】QGroundControl入门2:下载、编译、错误处理、运行
1、源码下载 git clone https://github.com/mavlink/qgroundcontrol.git 2、下载依赖库 2.1 查看依赖库的github路径 cat .gitmodules[submodule "src/GPS/Drivers"]path = src/GPS/Driversurl = https://github.com/PX4/GpsDrivers.git [submodule "libs/m…...
【深度学习】Pytorch 系列教程(十):PyTorch数据结构:2、张量操作(Tensor Operations):(4)索引和切片详解
目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量(Tensor) 2、张量操作(Tensor Operations) 1. 数学运算 2. 统计计算 3. 张量变形 4. 索引和切片 使用索引访问单个元素 使用切片访问子集 使用索引和…...
2024字节跳动校招面试真题汇总及其解答(三)
6.jwt与cookie区别 JWT 和 Cookie 都是用于在客户端和服务器之间传输信息的常用方法。但是,它们之间存在一些关键差异。 JWT 是 JSON Web Token 的缩写,它是一种基于 JSON 的加密令牌。JWT 由三部分组成:Header、Payload 和 Signature。Header 包含令牌的类型、加密算法和…...
基于springboot+vue的便利店信息管理系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...
杭州网站开发响应式/手机网站制作教程
木马检测技术旨在验证所设计或者制造的芯片是否感染了硬件木马。 目录 一、流片前检测 1.1 功能验证 1.2 电路设计分析 1.3 形式化验证 二、流片后检测 2.1 破坏性检测方法 2.2 非破坏性检测方法 2.2.1 非破坏性逆向工程 2.2.2 逻辑测试 2.2.3 侧信道分析 主要在两个…...
龙岩网站制作/国内b2b十大平台排名
最近接了个美国的小项目,主要需求是把盘点机导出的数据(DBF格式)和另外的数据(csv格式)合并生成新的数据表,方便查询纠错。对方没有安装ms Access,考虑到对方使用方便,就采用了sqlite࿰…...
二级网站怎么建设/学校网站建设
http://www.yiibai.com/html/testng/2013/0914296.html 本教程介绍了TestNG中执行程序的方法,这意味着该方法被称为第一和一个接着。下面是执行程序的TestNG测试API的方法的例子。 创建一个Java类文件名TestngAnnotation.java在C:\>TestNG_WORKSPACE测试注解。 i…...
网站模板后台怎么做/营销咨询服务
10.3去看了穗港澳动漫展,08年广州难得的一次动漫展......比较近距离地看了下川みくに,气氛很好。贴个相册地址,有兴趣的可以去看下哇。[url]http://photo.163.com/photos/squareram/160820460/[/url]转载于:https://blog.51cto.com/zeroyang/…...
行政机关 网站源码/google搜索关键词热度
一. windows 系统下搭建jenkins环境1.1 jenkins环境搭建和构建job流程图1.2 安装jdkJDK下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html选择对应系统的安装包下载:配置环境变量:新建JAVA_HOME系统环境…...
如皋网站开发/网页免费制作网站
1. 问题:给定一个时间的value:1541059860000,把它转换为东八区的显示格式 let a moment(1541059860000).subtract(moment().utcOffset(), minute).add(480, minute).format(YYYY-MM-DD HH:mm);let b moment(1541059860000).utcOffset(480).format(YYYY…...