网络
- 架构
C/S结构: 全称为Client/Server结构, 是指 客户端 和 服务器 结构
B/S结构: 全称为Browser/Server结构, 是指 浏览器 和 服务器 结构
- 网络协议
tcp 传输控制协议
有连接可靠的协议,无限制,效率低
udp 用户数据报文协议
无连接,64k一个包,速率快,易丢失
- tcp三次握手
TCP通信的三次握手: TCP协议中, 在发送数据的准备阶段, 客户端与服务器之间的三次交互, 以保证连接的可靠性
1. 客户端向服务端发送验证信息, 等待服务器确认
2. 服务端收到验证信息后, 回复客户端验证信息, 同时发送自己的一条验证信息
3. 客户端收到服务端回复的信息, 确认自己之前发的信息无误, 并再次向服务器发回服务端的验证信息
socket
getOutputStream() 获取网络字节输出流OutputStream对象
getInputStream() 获取网络字节输入流InputStream对象
accept()监听数据, 会阻塞. 收到数据后返回Socket对象
shutdownOutput();完毕后发送结束标记
- 使用ServerSocket实现Web服务器
// 等待客户端连接
System.out.println("图片上传服务端已启动, 等待客户端连接...");
// 优化2: 让服务端循环accept, 能够反复接收客户端的连接
while (true) {
Socket clientSocket = server.accept();
// 优化3: 将连接上客户端后的文件读写耗时操作, 让在子线程中执行, 提高程序效率
executorService.submit(new Runnable() {
@Override
public void run() {
try {
// 创建保存图片的upload目录
File uploadDir = new File("day11\\upload");
if (!uploadDir.exists()) {
uploadDir.mkdirs(); // 如果目录不存在, 则创建目录
}
// 优化1: 文件路径避免重名
String filename = "itheima" + System.currentTimeMillis() + new Random().nextInt(99999) + ".jpg";
// 创建FileOutputStream流对象, 用于保存图片
FileOutputStream fos = new FileOutputStream(uploadDir + "\\" + filename);
// 获取客户端的网络输入流, 用于读取客户端发来的消息
InputStream is = clientSocket.getInputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1) {
// 读到多少数据, 就写多少到磁盘
fos.write(bytes, 0, len);
}
// 向客户端回写结果
OutputStream os = clientSocket.getOutputStream();
os.write("上传成功!".getBytes());
// 释放资源
fos.close();
clientSocket.close();
} catch (IOException e) {
System.out.println(e);
}
}
});
}
客户端
/* (发送)上传图片文件 */
// 先获取Socket对象的网络输出字节流
OutputStream os = socket.getOutputStream();
// 循环读写文件: 一次读写一个byte[]数组
byte[] bytes = new byte[1024];
int len;
// 使用FileInputStream读取硬盘上的图片
while ((len = fis.read(bytes)) != -1) { // 98 != -1 true -1 != -1 false
// 将读取到的图片数据, 通过网络流写出
os.write(bytes, 0, len); // 读到多少就写多少 不会写结束标记-1
}
// 上传完毕后发送结束标记
socket.shutdownOutput();
/* (接收)读取服务端的响应结果 */
// 获取Socket对象的网络输入字节流
InputStream is = socket.getInputStream();
// 循环读取, 可以直接利用上面代码创建的byte[]数组和len变量, 也可以自己单独再定义新的
while ((len = is.read(bytes)) != -1) {
// 将读取到的字节转换为字符串, 打印到控制台
System.out.println(new String(bytes, 0, len));
}
// 释放资源
fis.close();
socket.close();
}