1. 编程题
基于学生信息管理系统增加以下两个功能:
a.自定义学号异常类和年龄异常类,并在该成员变量不合理时产生异常对象并抛出。
b.当系统退出时将 List 集合中所有学生信息写入到文件中,当系统启动时读取文件中所 有学生信息到 List 集合中。
1.1 知识点
- 在Student类中修改setId与setAge方法,当值不合理时抛出异常。
- 自定义异常类需序列化版本号
- 在ManageStudent类中增加无参构造方法默认从文件中读取学生信息
- 用户退出时写入学生信息到文件中
1.3 code
```java package com.lagou.part4homework.manageStudent;
/**
- @author 西风月
- @date 2020/8/31
@description */ public class AgeException extends Exception { private static final long serialVersionUID = -5708679320894004827L;
public AgeException() { }
public AgeException(String message) {
super(message);
} }
/**
- @author 西风月
- @date 2020/8/31
@description */ public class IDException extends Exception { private static final long serialVersionUID = -3636235950083905131L;
public IDException() { }
public IDException(String message) {
super(message);
} }
```java public void setId(int id) throws IDException { if(id > 0){ this.id = id; } else{ System.out.println("学号不合理哦!!!"); throw new IDException("学号不合理哦!!!"); } } public void setAge(int age) throws AgeException { if(age >= 4 && age <= 60){ this.age = age; } else{ System.out.println("年龄不合理哦!!!"); throw new AgeException("年龄不合理哦!!!"); } }
```java /**
- 定义无参构造方法实现从f:/student.dat中读取文件
*/
public ManageStudent() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“F:/student.dat”));
Object object = ois.readObject();
this.studentList = (List
) object; System.out.println(“Onload Student Info from [F:/student.dat] Suceess!”); } ```java public void saveToFile() throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:/student.dat")); oos.writeObject(studentList); System.out.println("写入文件成功!"); }
1.4 截图
```java “C:\Program Files\Java\jdk-11.0.2\bin\java.exe” “-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=46830:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin” -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.manageStudent.MainTest Onload Student Info from [F:/student.dat] Suceess!
学生信息管理系统
[1] 增加学生信息 [2] 删除学生信息 [3] 修改学生信息 [4] 查找学生信息
[5] 显示学生信息 [0] 退出学生系统
请选择具体的业务编号:
5
目前所有的学生信息是: Student [id=1001, name=aaa, age=24] Student [id=1002, name=bbb, age=24]
Student [id=8880, name=测试, age=30]
学生信息管理系统
[1] 增加学生信息 [2] 删除学生信息 [3] 修改学生信息 [4] 查找学生信息
[5] 显示学生信息 [0] 退出学生系统
请选择具体的业务编号: 2 请输入要删除的学生学号: 1002 删除成功,被删除的学生信息是:Student [id=1002, name=bbb, age=24]
学生信息管理系统
[1] 增加学生信息 [2] 删除学生信息 [3] 修改学生信息 [4] 查找学生信息
[5] 显示学生信息 [0] 退出学生系统
请选择具体的业务编号:
5
目前所有的学生信息是: Student [id=1001, name=aaa, age=24]
Student [id=8880, name=测试, age=30]
学生信息管理系统
[1] 增加学生信息 [2] 删除学生信息 [3] 修改学生信息 [4] 查找学生信息
[5] 显示学生信息 [0] 退出学生系统
请选择具体的业务编号: 0 写入文件成功! 谢谢使用,再见! Process finished with exit code 0
<a name="AhWvi"></a>
# 2. 编程题
实现将指定目录中的所有内容删除,包含子目录中的内容都要全部删除。
<a name="LONNR"></a>
## 2.1 知识点
1. File类的使用
1. 递归
<a name="Kj9Xc"></a>
## 2.2 代码说明
1. 如果文件类型是文件则删除
1. 文件类型是目录则删除目录中的文件
<a name="jvNEa"></a>
## 2.3 code
```java
package com.lagou.part4homework;
import java.io.File;
/**
* @author 西风月
* @date 2020/9/1
* @description
*/
public class DeleteDirFile {
private static void deleteDirFile(File[] files) {
if(null == files) return;
//foreach遍历目录元素并删除
for(File file : files) {
if(file.isFile()) {
//如果文件类型是文件则删除
file.delete();
System.out.println("删除文件["+ file.getAbsolutePath() + "]成功!");
} else if(file.isDirectory()) {
//文件类型是目录则删除目录中的文件
deleteDirFile(file.listFiles());
}
}
}
public static void main(String[] args) {
File file = new File("F:/捣乱");
deleteDirFile(file.listFiles());
}
}
2.4 截图
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=46964:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.DeleteDirFile
删除文件[F:\捣乱\猜猜我是谁\test.txt]成功!
删除文件[F:\捣乱\猜猜我是谁\你猜我猜不猜\888.txt]成功!
删除文件[F:\捣乱\猜猜我是谁\你猜我猜不猜\999.txt]成功!
删除文件[F:\捣乱\猜猜我是谁\你猜我猜不猜\死鬼\111.txt]成功!
Process finished with exit code 0
3. 编程题
使用线程池将一个目录中的所有内容拷贝到另外一个目录中,包含子目录中的内容。
3.1 知识点
- 线程池
- 使用Files工具类的copy方法复制文件
- Path类的使用
3.2 代码说明
多线程+递归方式深度拷贝目录。3.3 code
```java package com.lagou.part4homework;
import java.io.IOException; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Paths;
/**
- @author 西风月
- @date 2020/9/3
@description */ public class ThreadPoolCopy implements Runnable { //实现Runnable接口 String fromFile; String toFile; //构造函数传递文件路径信息 public ThreadPoolCopy(String fromFile, String toFile) {
this.fromFile = fromFile; this.toFile = toFile;
}
@Override public void run() {
try { //使用Files工具类的copy方法复制文件或目录 System.out.println(Thread.currentThread().getName() +":"+"CP "+fromFile+"-->"+toFile); Files.copy(Paths.get(fromFile), Paths.get(toFile)); //当目标文件已存在则会文件已存在异常,这是由于多线程调用拷贝函数时出现后进先执行的原因导致的。 } catch (FileAlreadyExistsException e) { System.out.println(Thread.currentThread().getName() +":"+"File Already Exsited!"); } catch (IOException e) { e.printStackTrace(); }
} }
```java
package com.lagou.part4homework;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author 西风月
* @date 2020/9/3
* @description
*/
public class ThreadPoolCopyTest {
static ExecutorService executorService = Executors.newCachedThreadPool();
//递归+多线程的方式拷贝目录
private static void fileCopy(String fileFrom, String fileTo) {
if(fileFrom.equalsIgnoreCase(fileTo)) return;
File f1 = new File(fileFrom);
File f2 = new File(fileTo);
if(!f1.exists()) return; //如果源文件不存在则直接退出
if(!f2.exists()) f2.mkdirs(); //如果目标目录不存在则新建目录
File[] files = f1.listFiles();
//遍历目录中的元素
for(File tf : files) {
if(tf.isFile()) { //文件
executorService.submit(new ThreadPoolCopy(fileFrom+"/"+tf.getName(), fileTo+"/"+tf.getName()));
} else if(tf.isDirectory()) { //子目录
executorService.submit(new ThreadPoolCopy(fileFrom+"/"+tf.getName(), fileTo+"/"+tf.getName())); // 开辟新线程拷贝目录
fileCopy(fileFrom+"/"+tf.getName(), fileTo+"/"+tf.getName()); //随后拷贝目录中的文件
}
}
}
public static void main(String[] args){
String fileFrom = "F:/捣乱";
String fileTo = "F:/测试";
fileCopy(fileFrom, fileTo);
}
}
3.4 截图
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=4839:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.ThreadPoolCopyTest
pool-1-thread-5:CP F:/捣乱/猜猜我是谁/你猜我猜不猜-->F:/测试/猜猜我是谁/你猜我猜不猜
pool-1-thread-7:CP F:/捣乱/猜猜我是谁/你猜我猜不猜/死鬼-->F:/测试/猜猜我是谁/你猜我猜不猜/死鬼
pool-1-thread-6:CP F:/捣乱/猜猜我是谁/你猜我猜不猜/bbb.xml-->F:/测试/猜猜我是谁/你猜我猜不猜/bbb.xml
pool-1-thread-3:CP F:/捣乱/猜猜我是谁/1.jpg-->F:/测试/猜猜我是谁/1.jpg
pool-1-thread-2:CP F:/捣乱/猜猜我是谁-->F:/测试/猜猜我是谁
pool-1-thread-8:CP F:/捣乱/猜猜我是谁/你猜我猜不猜/死鬼/1.txt-->F:/测试/猜猜我是谁/你猜我猜不猜/死鬼/1.txt
pool-1-thread-1:CP F:/捣乱/new.doc-->F:/测试/new.doc
pool-1-thread-4:CP F:/捣乱/猜猜我是谁/C++.proc-->F:/测试/猜猜我是谁/C++.proc
pool-1-thread-5:File Already Exsited!
pool-1-thread-2:File Already Exsited!
pool-1-thread-7:File Already Exsited!
4. 编程题
使用基于 tcp 协议的编程模型实现将 UserMessage 类型对象由客户端发送给服务器;
服 务 器接 收到 对象 后判 断 用户 对象 信息 是否 为 “admin” 和 “123456”, 若 是则 将 UserMessage 对象中的类型改为”success”,否则将类型改为”fail”并回发给客户端,客户 端接收到服务器发来的对象后判断并给出登录成功或者失败的提示。
其中 UserMessage 类的特征有:类型(字符串类型) 和 用户对象(User 类型)。
其中 User 类的特征有:用户名、密码(字符串类型)。
如:
UserMessage tum = new UserMessage(“check”, new User(“admin”, “123456”));
4.1 知识点
- 对象输入输出流
- 网络编程模型
4.2 代码说明
4.3 code
**
package com.lagou.part4homework.homework4;
import java.io.Serializable;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class UserMessage implements Serializable {
private static final long serialVersionUID = 5596033846618252122L;
public String type;
private User user;
public UserMessage(String type, User user) {
setType(type);
setUser(user);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
package com.lagou.part4homework.homework4;
import java.io.Serializable;
import java.util.Objects;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class User implements Serializable {
private static final long serialVersionUID = -4388952945901863002L;
private String userName;
private String PassWord;
public User(String userName, String passWord) {
setUserName(userName);
setPassWord(passWord);
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return PassWord;
}
public void setPassWord(String passWord) {
PassWord = passWord;
}
//重写equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(userName, user.userName) &&
Objects.equals(PassWord, user.PassWord);
}
@Override
public int hashCode() {
return Objects.hash(userName, PassWord);
}
}
package com.lagou.part4homework.homework4;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class ClientClass {
public static void main(String[] args) {
Socket s = null;
Scanner sc = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
// (1) 创建Socket类型的对象并提供服务器IP地址和端口号
s = new Socket("127.0.0.1", 8888);
// (2) 使用输入输出流进行通信
sc = new Scanner(System.in);
System.out.println("=======欢迎登录=======");
System.out.println("请输入用户名:");
String userName = sc.next();
System.out.println("请输入密码:");
String password = sc.next();
UserMessage um = new UserMessage("check", new User(userName, password));
oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(um);
ois = new ObjectInputStream(s.getInputStream());
Object object = ois.readObject();
UserMessage resp = (UserMessage) object;
System.out.println("服务器返回:" + resp.type);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
// (3) 关闭Socket
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
sc.close();
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.lagou.part4homework.homework4;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 西风月
* @date 2020/9/6
* @description
* 使用基于 tcp 协议的编程模型实现将 UserMessage 类型对象由客户端发送给服务器;
* 服 务 器接 收到 对象 后判 断 用户 对象 信息 是否 为 "admin" 和 "123456",
* 若 是则 将 UserMessage 对象中的类型改为"success",否则将类型改为"fail"并回发给客户端,客户 端接收到服务器发来的对象后判断并给出登录成功或者失败的提示。
* 其中 UserMessage 类的特征有:类型(字符串类型) 和 用户对象(User 类型)。
* 其中 User 类的特征有:用户名、密码(字符串类型)。
* UserMessage tum = new UserMessage("check", new User("admin", "123456"));
*/
public class ServerClass {
public static void main(String[] args) {
ServerSocket sc = null;
Socket s = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
// (1) 创建ServerSocket类型的对象并提供端口号
sc = new ServerSocket(8888);
// (2) 等待客户端的连接请求,调用accept方法
System.out.println("等待客户端连接....");
s = sc.accept();
System.out.println("客户端" + s.getInetAddress() + "连接成功!");
// (3) 使用输入输出流进行通信
//使用ObjectInputStream对象输入流接收客户端发来的消息
ois = new ObjectInputStream(s.getInputStream());
Object object = ois.readObject();
UserMessage um = (UserMessage) object;
if(um.getUser().equals(new User("admin", "123456"))) {
um.type = "success";
System.out.println("客户端用户名、密码校验成功!");
} else {
um.type = "fail";
System.out.println("客户端用户名、密码校验失败!");
}
//返回给客户端校验信息
oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(um);
System.out.println("服务器发送回执消息成功!");
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
///(4) 关闭Socket
assert oos != null;
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.4 截图
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=5890:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework4.ClientClass
=======欢迎登录=======
请输入用户名:
admin
请输入密码:
123456
服务器返回:success
Process finished with exit code 0
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=5883:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework4.ServerClass
等待客户端连接....
客户端/127.0.0.1连接成功!
客户端用户名、密码校验成功!
服务器发送回执消息成功!
Process finished with exit code 0
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=5982:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework4.ClientClass
=======欢迎登录=======
请输入用户名:
admin
请输入密码:
888888
服务器返回:fail
Process finished with exit code 0
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=5974:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework4.ServerClass
等待客户端连接....
客户端/127.0.0.1连接成功!
客户端用户名、密码校验失败!
服务器发送回执消息成功!
Process finished with exit code 0
5. 编程题
使用基于 tcp 协议的编程模型实现多人同时在线聊天和传输文件,要求每个客户端将发 送的聊天内容和文件发送到服务器,服务器接收到后转发给当前所有在线的客户端。
5.1 知识点
网络编程模型
输入/出流的使用
java.io.StreamCorruptedException: invalid type code: AC问题解决
5.2 代码说明
- 客户端开辟两个线程,分别是发送线程以及接收线程,保证通信的全双工
2. 客户端发送线程与接收线程采用死循环保持会话
3. 服务端开辟新线程处理客户端请求并转发
4. 服务端采用List数据结构记录所有接入的Socket连接
重写ObjectOutputSream的writeStreamHeader()方法
向同一个Soclet中写入序列化对象,每次都会向文件中序列化一个header。在反序列化的时候每个 ObjectInputStream 对象只会读取一个header,那么当遇到第二个的时候就会报错,导致出现异常
java.io.StreamCorruptedException: invalid type code: AC
5.3 code
package com.lagou.part4homework.homework5;
import java.io.Serializable;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class AMessage implements Serializable {
private static final long serialVersionUID = -2083775012764186780L;
public String type; //消息类型:chat file
private String filename; //文件名称
private final byte[] buffer; //消息内容
public AMessage(String type, String filename, byte[] buffer) {
this.type = type;
this.filename = filename;
this.buffer = buffer;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public byte[] getBuffer() {
return buffer;
}
}
package com.lagou.part4homework.homework5;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class ClientClass1 {
public static void main(String[] args) {
//(1) 与服务器建立连接
Socket s = null;
try {
s = new Socket("127.0.0.1", 8888);
} catch (IOException e) {
e.printStackTrace();
}
//(2) 开辟线程接收来自服务器的广播消息
new ClientRecvThread(s).start();
//(3) 开辟线程发送消息到服务器
new ClientSendThread(s).start();
}
}
package com.lagou.part4homework.homework5;
import java.io.IOException;
import java.net.Socket;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class ClientClass2 {
public static void main(String[] args) {
//(1) 与服务器建立连接
Socket s = null;
try {
s = new Socket("127.0.0.1", 8888);
} catch (IOException e) {
e.printStackTrace();
}
//(2) 开辟线程接收来自服务器的广播消息
new ClientRecvThread(s).start();
//(3) 开辟线程发送消息到服务器
new ClientSendThread(s).start();
}
}
package com.lagou.part4homework.homework5;
import java.io.EOFException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.nio.file.Files;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class ClientRecvThread extends Thread {
Socket socket;
public ClientRecvThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
ObjectInputStream ois = null;
FileOutputStream fileOutputStream = null;
try {
ois = new ObjectInputStream(socket.getInputStream());
while (true) { //保持当前会话
Object obj = ois.readObject();
AMessage message = (AMessage) obj;
if ("chat".equals(message.type)) {
System.out.println("接收到来自服务器的消息:[" + new String(message.getBuffer()) + "]!");
} else if ("file".equals(message.type)) {
//截取文件名称
String path = message.getFilename();
String[] sp = path.split("/");
String filename = sp[sp.length - 1];
System.out.println("Received Filename=["+filename+"]");
//保存文件到本地
String fullName = "F:/tmp/" + filename;
fileOutputStream = new FileOutputStream(fullName);
fileOutputStream.write(message.getBuffer());
System.out.println("保存[" + filename + "]到本地成功");
} else if ("bye".equals(message.type)) {
System.out.println("客户端接收线程退出!");
break;
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
//release
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
assert ois != null;
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.lagou.part4homework.homework5;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class ClientSendThread extends Thread {
private Socket socket;
private static int cnt = 0;
public ClientSendThread(Socket socket) {
this.socket = socket;
}
private void showMenu() {
System.out.println("==========欢迎登录客户端!===========");
System.out.println("1-发送消息(default)");
System.out.println("2-发送文件");
System.out.println("0-退出");
}
@Override
public void run() {
FileInputStream fis = null;
Scanner sc = null;
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(socket.getOutputStream());
while(true) {
showMenu();
System.out.println("请选择指令:");
sc = new Scanner(System.in);
String opt = sc.next();
if("2".equals(opt)) {
System.out.println("请输入您需发送文件的绝对路径!");
String path = sc.next();
fis = new FileInputStream(path);
int length = fis.available();
byte[] bytes = new byte[length];
if(fis.read(bytes) != -1) {
oos.writeObject(new AMessage("file", path, bytes));
System.out.println("发送文件 [" + path + "] 成功");
} else {
System.out.println("读取文件失败!");
}
} else if("0".equals(opt)){
System.out.println("客户端发送线程退出!");
oos.writeObject(new AMessage("bye",null,null));
Thread.sleep(1000);
return;
} else {
System.out.println("请输入您想发送的聊天内容:");
String str = sc.next();
oos.writeObject(new AMessage("chat", null, str.getBytes()));
System.out.println("发送消息成功!");
}
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
assert sc != null;
sc.close();
try {
if (null != fis) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.lagou.part4homework.homework5;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
/**
* @author 西风月
* @date 2020/9/7
* @description
*/
public class MyObjectOutputStream extends ObjectOutputStream {
public MyObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
return;
}
}
package com.lagou.part4homework.homework5;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
/**
* @author 西风月
* @date 2020/9/6
* @description
*/
public class ServerThread extends Thread {
private Socket s;
private static ArrayList<Socket> clients = new ArrayList<>(); //保存已有的Socket连接,类层级的变量
public ServerThread(Socket s) {
this.s = s;
clients.add(s);
System.out.println("从连接池添加客户端Socket成功!,当前的深度是:" + clients.size());
}
@Override
public void run() {
System.out.println("[" + Thread.currentThread().getName() + "]:客户端:[" + s.getInetAddress() + "]连接成功!");
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
ObjectOutputStream oosTmp = null;
try {
//1. 接收
ois = new ObjectInputStream(s.getInputStream());
oos = new ObjectOutputStream(s.getOutputStream());
while (true) { //保持会话
Object object = ois.readObject();
AMessage message = (AMessage) object;
//2. 转发
if ("chat".equals(message.type)) {
System.out.println("[" + Thread.currentThread().getName() + "]:" + "服务器收到消息["+ new String(message.getBuffer()) +"],开始转发!");
} else if ("file".equals(message.type)) {
System.out.println("[" + Thread.currentThread().getName() + "]:" + "服务器收到文件["+ message.getFilename() +"],开始转发!");
} else if ("bye".equals(message.type)) { //当客户端发送线程输入退出指令后,相应的服务器线程退出
oos.writeObject(message); //发送退出指令到客户端接收线程
System.out.println("[" + Thread.currentThread().getName() + "]:" + "客户端[" + s.getLocalAddress() + "]退出!");
break; //退出线程
}
//分发消息或文件到其他客户端
for (Socket socket : clients) {
if (s == socket) continue;
oosTmp = new MyObjectOutputStream(socket.getOutputStream()); //打开该输出流
oosTmp.writeObject(message);
System.out.println("[" + Thread.currentThread().getName() + "]:" + "转发到client[" + socket.getLocalAddress() + "]消息成功!");
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
//3. 关闭Socket并释放相关资源
clients.remove(s); //从连接池删除当前连接
System.out.println("[" + Thread.currentThread().getName() + "]:" + "从连接池删除客户端Socket成功!,当前的深度是:" + clients.size());
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.lagou.part4homework.homework5;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 西风月
* @date 2020/9/6
* @description 服务器主处理模块:
*/
public class ServerClass {
public static void main(String[] args) {
ServerSocket ss = null;
try {
//1. 创建ServerSocket对象并指定端口
ss = new ServerSocket(8888);
//2. 等待客户端的请求,调用accept方法
while (true) {
System.out.println("等待客户端连接......");
Socket accept = ss.accept();
//3. 新启动线程处理接入的请求
new ServerThread(accept).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 关闭Socket并释放相关资源
try {
if (ss != null) {
ss.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.4 截图
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=8790:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework5.ClientClass1
==========欢迎登录客户端!===========
1-发送消息(default)
2-发送文件
0-退出
请选择指令:
1
请输入您想发送的聊天内容:
在吗
发送消息成功!
==========欢迎登录客户端!===========
1-发送消息(default)
2-发送文件
0-退出
请选择指令:
接收到来自服务器的消息:[不是本人]!
1
请输入您想发送的聊天内容:
88
发送消息成功!
==========欢迎登录客户端!===========
1-发送消息(default)
2-发送文件
0-退出
请选择指令:
2
请输入您需发送文件的绝对路径!
F:/a.txt
发送文件 [F:/a.txt] 成功
==========欢迎登录客户端!===========
1-发送消息(default)
2-发送文件
0-退出
请选择指令:
0
客户端发送线程退出!
客户端接收线程退出!
Process finished with exit code 0
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=8801:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework5.ClientClass2
==========欢迎登录客户端!===========
1-发送消息(default)
2-发送文件
0-退出
请选择指令:
接收到来自服务器的消息:[在吗]!
1
请输入您想发送的聊天内容:
不是本人
发送消息成功!
==========欢迎登录客户端!===========
1-发送消息(default)
2-发送文件
0-退出
请选择指令:
接收到来自服务器的消息:[88]!
Received Filename=[a.txt]
保存[a.txt]到本地成功
0
客户端发送线程退出!
客户端接收线程退出!
Process finished with exit code 0
"C:\Program Files\Java\jdk-11.0.2\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=8778:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\IdeaProjects\javase\out\production\javase com.lagou.part4homework.homework5.ServerClass
等待客户端连接......
从连接池添加客户端Socket成功!,当前的深度是:1
等待客户端连接......
[Thread-0]:客户端:[/127.0.0.1]连接成功!
从连接池添加客户端Socket成功!,当前的深度是:2
等待客户端连接......
[Thread-1]:客户端:[/127.0.0.1]连接成功!
[Thread-0]:服务器收到消息[在吗],开始转发!
[Thread-0]:转发到client[/127.0.0.1]消息成功!
[Thread-1]:服务器收到消息[不是本人],开始转发!
[Thread-1]:转发到client[/127.0.0.1]消息成功!
[Thread-0]:服务器收到消息[88],开始转发!
[Thread-0]:转发到client[/127.0.0.1]消息成功!
[Thread-0]:服务器收到文件[F:/a.txt],开始转发!
[Thread-0]:转发到client[/127.0.0.1]消息成功!
[Thread-0]:客户端[/127.0.0.1]退出!
[Thread-0]:从连接池删除客户端Socket成功!,当前的深度是:1
[Thread-1]:客户端[/127.0.0.1]退出!
[Thread-1]:从连接池删除客户端Socket成功!,当前的深度是:0