一、网络的相关概念
1.1 网络通信
- 概念:两台设备之间通过网络实现数据传输
- 网络通信 :将数据通过网络从一台设备传输到另一台设备
- java.net 包下提供了一系列的类或接口,供程序员使用,完成网络通信
1.2 网络
- 概念:两台或多台设备通过一定物理设备连接起来构成了网络
- 根据网络的覆盖范围不同,对网络进行分类
- 局域网:覆盖范围最小,仅仅覆盖一个教室或者一个机房
- 城域网:覆盖范围较大,可以覆盖一个城市
- 广域网:覆盖范围最大,可以覆盖全国,甚至全球,万维网是广域网的代表
1.3 IP 地址
- 概念:用于唯一标识网络中的每台计算机/主机
- 查看 ip 地址:ipconfig
- ip 地址的表示形式:点分十进制 xx.xx.xx.xx
- 每一个十进制数的范围:0 ~ 255
- ip 地址的组成 = 网络地址 + 主机地址,比如:192.168.16.69
- IPv6 是互联网工程任务组设计的用于替代 IPv4 的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址
- 由于 IPv4 最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6 的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍
1.4 IPv4 地址分类
1.5 域名和端口号
域名:
- 形如:www.baidu.com
- 好处:为了方便记忆,解决记 ip 的困难
- 概念:将 ip 地址映射成域名,这里怎么映射上,HTTP 协议
端口号:
- 概念:用于标识计算机上某个特定的网络程序
- 表示形式:以整数形式,端口号 0 ~ 65535 [ 2个字节表示端口 0 ~2^16 - 1 ]
- 0 ~ 1024 已经被占用,比如 ssh 22, ftp 21,smtp 25,http 80
- 常见的网络程序端口号:
- tomcat:8080
- mysql:3306
- oracle:1521
- sqlserver:1433
1.6 网络通信协议
协议(TCP / IP)
TCP / IP(Transmission Control Protocol / Internet Protocol)的简写,中文名译为 传输控制协议 / 因特网互联协议,又叫网络通讯协议,这个协议是 Internet 最基本的协议,Internet 国际互联网的基础,简单地说,就是由网络层的 IP 协议和传输层的 TCP 协议组成的。
OSI 模型 | TCP / IP 模型 | TCP / IP 模型各层对应协议 |
---|---|---|
应用层 | 应用层 | HTTP、ftp、telnet、DNS…… |
表示层 | ||
会话层 | ||
传输层 | 传输层 | TCP、UDP…… |
网络层 | 网络层 | IP、ICMP、ARP…… |
数据链路层 | 物理 + 数据链路层 | Link |
物理层 |
1.7 TCP 和 UDP
TCP 协议:传输控制协议
- 使用 TCP 协议前,须先建立 TCP 连接,形成传输数据通道
- 传输前,采用“三次握手”方式,是 可靠的
- TCP 协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
举例:模拟三次握手,然后传输数据
汉奸:队长别开枪,是我
队长:原来是你小子,来干什么的?
汉奸:皇军让我给您捎句话
….然后是具体内容…
UDP 协议:用户数据协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据包的大小限制在 64K 以内,不适合传输大数据量
- 因无需连接,所以是不可靠的
- 发送数据结束时无需释放资源(因为不是面向连接的),速度快
举例:
汉奸跑到八路军营地前,
大喊一声:皇军让我给你们捎句话,别再做无谓的抵抗,赶快投降
喊完汉奸就赶紧跑了
二、InetAddress 类
2.1 相关方法
- 获取本机 InetAddress 对象,getLocalHost
- 根据指定主机名 / 域名 获取 ip 地址对象 getByName
- 获取 InetAddress 对象的主机名 getHostName
- 获取 InetAddress 对象的地址 getHostAddress
2.2 应用案例
编写代码,获取计算机的主机名和 IP 地址相关 API
package com.hspedu.api_;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author HarborGao
* @version 1.0
*/
public class API_ {
public static void main(String[] args) throws UnknownHostException {
//1. 获取本机的 InetAddress 对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//2. 根据指定的主机名,获取 InetAddress 对象
InetAddress host1 = InetAddress.getByName("Harvin");
System.out.println("host1=" + host1);
//3. 根据域名返回 InetAddress对象 比如 www.baidu.com 对应的Host
InetAddress host2 = InetAddress.getByName("www.baidu.com");
System.out.println("host2=" + host2);
//4. 通过 InetAddress 对象,获取对应的的地址
String hostAddress = host2.getHostAddress();
System.out.println("host2 对应的 ip=" + hostAddress);
//5. 通过 InetAddress 对象,获取对应的主机名/或者是域名
String hostName = host2.getHostName();
System.out.println("host2 对应的主机名/域名 = " + hostName);
}
}
三、Socket
3.1 基本介绍
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准
- 通信的两端都要有 Socket,是两台机器间通信的端点
- 网络通信其实就是 Socket 间的通信
- Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输
- 一般主动发起通信的应用程序属于客户端,等待通信请求的是服务端
3.2 示意图
四、TCP 网络通信编程
4.1 基本介绍
- 基于客户端 - 服务端的网络通信
- 底层使用的是 TCP / IP 协议
- 应用场景举例:客户端发送数据,服务端接收并显示在控制台
- 基于 Socket 的 TCP 编程
4.2 应用案例1(使用字节流)
- 编写一个服务器端,和一个客户端
- 服务器端在 9999 端口监听
- 客户端连接到服务器端,发送”hello, server”,然后退出
- 服务器端接收到 客户端发送的信息,输出,并退出 ```java package com.hspedu.socket;
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;
/**
- @author HarborGao
- @version 1.0
- 服务端 接收客户端发送的信息,输出,并退出
*/
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
} }//1. 在本机的 9999端口监听,等待连接
//细节说明:要求在本机没有其他服务在监听9999,即9999端口没有被占用
// ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接..");
//2. 当没有客户端连接9999端口时,程序会处于阻塞状态,等待连接
//如果由客户端连接,则会返回一个 Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务器端 socket = " + socket.getClass());
//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,输出显示
InputStream inputStream = socket.getInputStream();
//4. IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.println(new String(buf,0,readLen)); //根据读取到的实际长度显示内容
}
//5.关闭流和 socket
inputStream.close();
socket.close();
serverSocket.close();
import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket;
/**
- @author HarborGao
- @version 1.0
客户端,发送”hello,server”给服务端 */ public class SocketTCP01Client { public static void main(String[] args) throws IOException {
//1. 连接服务端 (ip, 端口)
//解读:连接 InetAddress.getLocalHost()主机的 9999端口,如果连接成功,返回 socket 对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端 socket = " + socket.getClass());
//2. 连接上后,生成 socket ,通过socket.getOutputStream()
// 得到 和 socket 对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流,写入数据到 数据通道
outputStream.write("hello,server".getBytes());
//4. 关闭流对象和 socket
outputStream.close();
socket.close();
System.out.println("客户端退出..");
} } ```
4.3 应用案例2 (使用字节流)
- 编写一个服务器端,和一个客户端
- 服务器端在 9999端口监听
- 客户端连接到服务器端,发送 “hello,server”,并接收服务器端发回的”hello,client”,再退出
- 服务器端接收 客户端发送的信息,输出,并发送”hello,client”,再退出 ```java package com.hspedu.socket;
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;
/**
- @author HarborGao
- @version 1.0
服务器端 */ public class SocketTCP02Server { public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9997);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[100];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.print(new String(buf,0,readLen));
}
//设置结束标记,表示输入结束
socket.shutdownInput();
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,client".getBytes());
socket.shutdownOutput();
inputStream.close();
outputStream.close();
socket.close();
serverSocket.close();
} }
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket;
/**
- @author HarborGao
- @version 1.0
客户端 */ public class SocketTCP02Client { public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),9997);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello.server".getBytes());
//设置结束标记,表示输出结束
socket.shutdownOutput();
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[100];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.print(new String(buf,0,readLen));
}
socket.shutdownInput();
outputStream.close();
inputStream.close();
socket.close();
} } ```
4.4 应用案例3 (使用字符流)
- 编写一个服务端,和一个客户端
- 服务端在9999端口监听
- 客户端连接到服务端,发送”hello, server”,并接收服务端回发的”hello,client”,再退出
- 服务端接收到客户端发送的信息,输出,并发送”hello, client”,再退出 ```java package com.hspedu.socket;
import java.io.*; import java.net.InetAddress; import java.net.Socket;
/**
- @author HarborGao
- @version 1.0
客户端 */ public class SocketTCP03Client { public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),9997);
OutputStream outputStream = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("hello,server服务端");
//也可以是使用 writer.newLine() 设置结束标记 注意要求对方使用readLine()接收
writer.newLine();
writer.flush();
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String s = reader.readLine();
System.out.println(s);
reader.close();
writer.close();
socket.close();
} }
import java.io.*; import java.net.ServerSocket; import java.net.Socket;
/**
- @author HarborGao
- @version 1.0
服务器端 */ public class SocketTCP03Server { public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9997);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String s = reader.readLine();
System.out.println(s);
OutputStream outputStream = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("hello,client客户端");
writer.newLine();
writer.flush();
reader.close();
writer.close();
socket.close();
serverSocket.close();
} } ```
4.5 应用案例4
- 编写个服务端,和一个客户端
- 服务器端在8888端口监听
- 客户端连接到服务端,发送一张图片 e:\img.jpg
- 服务器端接收到客户端发送的图片,保存到src下,发送”收到图片”再退出
- 客户端接收到服务端发送的”收到图片”, 再退出
- 该程序要求使用StreamUtils.java ```java package com.hspedu.upload;
import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader;
/**
此类用于演示关于流的读写方法 / public class StreamUtils { /**
- 功能:将输入流转换成byte[]
- @param is
- @return
- @throws Exception
*/
public static byte[] streamToByteArray(InputStream is) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
byte[] b = new byte[1024];
int len;
while((len=is.read(b))!=-1){
} byte[] array = bos.toByteArray(); bos.close(); return array; } /**bos.write(b, 0, len);
- 功能:将InputStream转换成String
- @param is
- @return
@throws Exception */
public static String streamToString(InputStream is) throws Exception{ BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder builder= new StringBuilder(); String line; while((line=reader.readLine())!=null){ //当读取到 null时,就表示结束
builder.append(line+"\r\n");
} return builder.toString();
}
}
```java
package com.hspedu.upload;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 韩顺平
* @version 1.0
* 文件上传的服务端
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
//1. 服务端在本机监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在8888端口监听....");
//2. 等待连接
Socket socket = serverSocket.accept();
//3. 读取客户端发送的数据
// 通过Socket得到输入流
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//4. 将得到 bytes 数组,写入到指定的路径,就得到一个文件了
String destFilePath = "src\\abc.mp4";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
bos.close();
// 向客户端回复 "收到图片"
// 通过socket 获取到输出流(字符)
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("收到图片");
writer.flush();//把内容刷新到数据通道
socket.shutdownOutput();//设置写入结束标记
//关闭其他资源
writer.close();
bis.close();
socket.close();
serverSocket.close();
}
}
package com.hspedu.upload;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author 韩顺平
* @version 1.0
* 文件上传的客户端
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
//客户端连接服务端 8888,得到Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//创建读取磁盘文件的输入流
//String filePath = "e:\\qie.png";
String filePath = "e:\\abc.mp4";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
//bytes 就是filePath对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
//通过socket获取到输出流, 将bytes数据发送给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道
bis.close();
socket.shutdownOutput();//设置写入数据的结束标记
//=====接收从服务端回复的消息=====
InputStream inputStream = socket.getInputStream();
//使用StreamUtils 的方法,直接将 inputStream 读取到的内容 转成字符串
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
//关闭相关的流
inputStream.close();
bos.close();
socket.close();
}
}
4.6 netstat 指令
- netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
- netstat -an | more 可以分页显示
- 要求在 dos 控制台下执行
说明:
- Listening 表示某个端口在监听
- 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息
- 可以输入 ctrl + c 退出指令
4.7 TCP网络通讯不为人知的秘密
- 当客户端连接到服务器后,实际上客户端也是通过一个端口和服务端进行通讯的,
这个端口是 TCP / IP 来分配的,是不确定的,随机的。 - 示意图
- 程序验证
五、 UDP 网络通信编程 [ 了解 ]
5.1 基本介绍
- 类 DatagramSocket 和 DatagramPacket[数据包/数据报] 实现了基于 UDP 协议网络程序
- UDP 数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP 数据报一定能够安全送到目的地,也不能确定什么时候能够送达
- DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
- UDP协议中每个数据报都给出了完整的地址信息,因此无需建立发送方和接收方的连接
5.2 基本流程
- 核心的两个类/对象 DatagramSocket 与 DatagramPacket
- 建立发送端,接收端(没有服务端和客户端概念)
- 发送数据前,建立数据报/包 DatagramPacket 对象
- 调用 DatagramSocket 的发送、接收方法
- 关闭 DatagramSocket
5.3 应用案例
- 编写一个接收端 A,和一个发送端 B
- 接收端 A 在9999端口等待接收数据(receive)
- 发送端 B 向接收端 A 发送数据”hello,明天吃火锅~”
- 接收端 A 接收到 发送端 B 发送的数据,回复”好的,明天见”,再退出
- 发送端 接收回复的数据,再退出 ```java package com.hspedu.udp;
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;
/**
- @author HarborGao
- @version 1.0
接收端 ==> 也可以变成发送端 */ public class UDPReceiverA { public static void main(String[] args) throws IOException {
//1. 创建一个 DatagramSocket 对象,准备在端口9999发送和接收数据
DatagramSocket socket = new DatagramSocket(9999);
//2. 构建一个 DatagramPacket 对象,准备接收数据
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//3. 调用接收方法,将通过网络传输的 DatagramPacket 对象 填充到 packet 对象
//细节提示:当有数据报发送到本机的9999端口,下面就会接收到,否则就会阻塞等待
System.out.println("接收端A等待接收数据...");
socket.receive(packet);
//4. 可以把 packet 进行拆包,取出数据,并显示
int length = packet.getLength(); //实际接收到的数据字节长度
byte[] data = packet.getData();
String s = new String(data,0,length);
System.out.println(s);
// ===回复===
byte[] data2 = "好的,明天见".getBytes();
packet = new DatagramPacket(data2, data2.length, InetAddress.getByName("192.168.0.182"),9998);
socket.send(packet);
//5.关闭 socket 端口
socket.close();
System.out.println("A端退出...");
} }
import java.io.IOException; import java.net.*;
/**
- @author HarborGao
- @version 1.0
发送端 ==> 也可以变成接收端 */ public class UDPSenderB { public static void main(String[] args) throws IOException {
//1. 创建 DatagramSocket 对象,准备发送和接收数据
DatagramSocket socket = new DatagramSocket(9998);
//2. 将需要发送的数据,封装到 DatagramPacket 对象
byte[] data = "hello,明天吃火锅~".getBytes();
//说明:封装的DatagramPacket 由四部分组成:数据(字节数组),数据长度(大小 <= 64KB),接收端主机地址,接收端接收端口
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.182"),9999);
socket.send(packet);
// ===接收回复===
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
System.out.println("接收端B等待接收数据...");
socket.receive(packet);
int length = packet.getLength(); //实际接收到的数据字节长度
byte[] data2 = packet.getData();
String s = new String(data2,0,length);
System.out.println(s);
//关闭资源
socket.close();
System.out.println("B端退出...");
} } ```
六、本章作业
- 编程题
Homework01Server.java Homework01Client.java com.hspedu.homework
- 使用字符流的方式,编写一个客户端程序和服务器端程序,
- 客户端发送”name”,服务器端接收到后,返回”我是nova”,nova是你自己的名字.
- 客户端发送”hobby”,服务器端接收到后,返回”编写java程序”
- 不是这两个问题,回复”你说啥呢” ```java package com.hspedu.homework;
import java.io.*; import java.net.ServerSocket; import java.net.Socket;
/**
- @author HarborGao
@version 1.0 */ public class Homework01Server { public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("等待接收数据");
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String s = reader.readLine();
System.out.println(s);
String feedback = null;
switch (s) {
case "name":
feedback = "我是 nova";
break;
case "hobby":
feedback = "编写Java程序";
break;
default:
feedback = "你说啥呢";
break;
}
OutputStream outputStream = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write(feedback);
writer.newLine();
writer.flush();
reader.close();
writer.close();
socket.close();
serverSocket.close();
} }
import java.io.*; import java.net.InetAddress; import java.net.Socket;
/**
- @author HarborGao
@version 1.0 */ @SuppressWarnings({“all”}) public class Homework01Client { public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
OutputStream outputStream = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("name");
//writer.write("hobby");
//writer.write("es");
writer.newLine();
writer.flush();
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String s = reader.readLine();
System.out.println(s);
writer.close();
reader.close();
socket.close();
} } ```
- 编程题
Homework02ReceiverA.java Homework02SenderB.java com.hspedu.homework
- 编写一个接收端A,和一个发送端B,使用UDP协议完成
- 接收端在8888端口等待接收数据(receive)
- 发送端向接收端发送数据”四大名著是哪些”
- 接收端接收到发送端发送的问题后,返回”四大名著是《红楼梦》…” 否则返回 what?
- 接收端和发送端程序退出 ```java package com.hspedu.homework;
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;
/**
- @author HarborGao
@version 1.0 */ public class Homework02ReceiverA { public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8888);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
System.out.println("等待接收...");
socket.receive(packet);
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data,0,length);
System.out.println(s);
if ("四大名著是哪些".equals(s)) {
data = "四大名著是《红楼梦》,《三国演义》,《水浒传》,《西游记》".getBytes();
} else {
data = "what?".getBytes();
}
packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(),8887);
socket.send(packet);
socket.close();
} }
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;
/**
- @author HarborGao
@version 1.0 */ public class Homework02SenderB { public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8887);
byte[] data = "四大名著是哪些".getBytes();
data = "???".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(),8888);
socket.send(packet);
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
int length = packet.getLength();
data = packet.getData();
String s = new String(data,0,length);
System.out.println(s);
socket.close();
} } ```
- 编程题
Homework03Server.java Homework03Client.java
- 编写客户端程序和服务器端程序
- 客户端可以输入一个音乐文件名,比如 高山流水,服务端收到音乐名后,可以给客户端返回这个音乐文件,如果服务器没有这个文件,返回一个默认的音乐即可.
- 客户端收到文件后,保存到本地 e:\
- 提示:该程序可以使用 StreamUtils.java
本质:其实就是指定下载文件的应用,先自己结合前面讲的文件上传来做.
package com.hspedu.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author HarborGao
* @version 1.0
*/
public class Homework03Server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(7777); //开通服务器端监听端口
System.out.println("等待接收信息...");
Socket socket = serverSocket.accept(); //监听接入的端口
//接收其他用户发送来的请求信息
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); //用字符流读入
String s = reader.readLine(); //读入数据
System.out.println("接收到请求的歌名是 " + s);
//根据用户请求选择相应的 mp3文件
String filePath = "src\\无名.mp3"; //初始化服务器上的本地文件,默认是 无名.mp3
if ("高山流水".equals(s)) {
filePath = "src\\高山流水.mp3"; //如果请求的是高山流水,就将文件地址指向 高山流水.mp3,否则保持默认
}
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath)); //读入本地文件
byte[] data = StreamUtils.streamToByteArray(bis); //将文件保存到 data[]
//发送文件
OutputStream outputStream = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
bos.write(data);
socket.shutdownOutput(); //结束标识
//关闭相关接口
reader.close();
bis.close();
bos.close();
socket.close();
serverSocket.close();
System.out.println("服务器端关闭.");
}
}
package com.hspedu.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* @author HarborGao
* @version 1.0
*/
public class Homework03Client {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//连接服务器端
Socket socket = new Socket(InetAddress.getLocalHost(),7777);
//发送请求
OutputStream outputStream = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
System.out.println("请输入要下载的文件名: ");
String musicName = scanner.next();
writer.write(musicName);
writer.newLine();
writer.flush();
//接收文件
InputStream inputStream = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(inputStream);
byte[] data = StreamUtils.streamToByteArray(bis);
//将文件保存到本地
String filePath = "e:\\" + musicName + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(data);
writer.close();
bis.close();
bos.close();
socket.close();
System.out.println("客户端关闭");
}
}
学习参考(致谢):
- B站 @程序员鱼皮 Java学习一条龙
- B站 @韩顺平 零基础30天学会Java