提示:
文章目录
前言
经过一段时间的Java知识学习,对这一段学习进行检验,因此做一个在线小说阅读系统项目,看自己的知识是否巩固。
随着信息技术水平的空前提高,大众对于获取信息的方式有了越来越高的要求。作为一种新兴的阅读载体,电子书刊因其方便快捷的特性日益普及。图书馆作为搜集、整理图书文化资料的公共文化机构,势必要紧跟这一时代步伐以谋求进一步发展。传统的图书借阅方式虽重要且暂时不可替代,却无法完全满足读者的进一步需求。这时,将电子书纳入日常的借阅体系,为读者提供多样化的选择,不失为一个好的解决办法。
一、项目介绍
1.项目目的
本系统的主要目标是设计并实现一个基于Java的在线阅读小说。项目需要实现关于服务端和客户端的连接,在此基础上,用户可以进行登录注册,并在登录注册后进行如阅读小说、下载小说、上传小说等功能。
2.任务需求
任务1:创建客户端、服务器端,完成简单通信
任务2:完成登录、注册、退出、返回功能
任务3:完成小说查询列表的功能
任务4:完成在线阅读小说功能
任务5:完成下载小说功能
任务6:完成上传小说功能
二、技术介绍
-
应用面向对象的思想编写简单项目
-
熟练操作Socket编程
-
熟练操作文件I/O读写的操作
-
了解配制文件的解析方式
-
了解多线程的应用
-
了解xml文件作为轻量级的存储,以及使用dom4j解析xml文件
三、代码展示
1.文件格式
我的整个项目分为两个部分——Client和Server
Client存放客户端方法
其中Contain方法和MessageEntity方法以及UserEntity方法是用来封装常量和变量的 ClientTest方法是客户端运行的代码
UserService方法用来判断登录与注册的成功与否
ResultUtil方法处理二级菜单
Server存放服务端方法 与Cilent方法的Contain方法和MessageEntity方法以及UserEntity方法作用一样
ServerApp方法是服务端运行的代码
UserService方法用来判断登录与注册的成功与否
XMLUtil方法用来处理xml的相关
2. 封装类
上面提到,项目中有很多共用的封装类,用来封装客户端和服务端都会用到的,或者代码需要经常用到的,就会单独封装
Contain类:用来存放经常使用的常量
//客户端的Contain
public class Contain {
public static final String downloadPath="D:\\feisi_Java\\stream\\book"; //存放下载小说的路径
public static final String bookPath = "D:\\feisi_Java\\stream\\Server\\book"; //存放全部小说
public static final String REGISTERSUCRESULT="100"; //注册成功
public static final String REGISTERFAIRESULT="101"; //注册失败
public static final String LOGINSUCRESULT="200"; //登录成功
public static final String LOGINFAIRESULT="201"; //登录失败
public static final String FLAGSTR = "j#";
}
//服务端的Contain
public class Contain {
//服务器上存放小说的路径
public static final String bookPath = "D:\\feisi_Java\\stream\\Server\\book";
public static final String FLAGSTR = "j#";
}
MessageEntity类:用来存放用户端和服务端都需要用到的交互信息
一定要实现Serializable接口
public class MessageEntity implements Serializable {
private String bookName;
private String content;
private int page;
public int getPage() { return page; }
public void setPage(int page) { this.page = page; }
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
private int oprator;
private UserEntity userEntity;
public int getOprator() {
return oprator;
}
public void setOprator(int oprator) {
this.oprator = oprator;
}
public UserEntity getUserEntity() {
return userEntity;
}
public void setUserEntity(UserEntity userEntity) {
this.userEntity = userEntity;
}
}
UserEntity方法:用户的信息定义
一定要实现Serializable接口
public class UserEntity implements Serializable {
private String username;
private String password;
private Integer id;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
3.客户端特有类
BookClientService类:用来查询服务器上的小说列表
public class BookClientService {
public List<String> queryPrintAllBook(DataUtil dataUtil) throws IOException {
List<String> list = new ArrayList<>();
MessageEntity messageEntity =new MessageEntity();
//只需要带一个操作
messageEntity.setOprator(5);
dataUtil.sendData(messageEntity);
//阻塞
String s = dataUtil.receiveData();
String[] split = s.split("-");
for (String s1 : split) {
list.add(s1);
}
return list;
}
}
DataUtil类:用来接收和发送服务端数据
public class DataUtil {
static byte[] bs = new byte[512];
Socket socket;
ObjectOutputStream oos = null;
public DataUtil(Socket socket){
this.socket=socket;
}
public void sendData(MessageEntity messageEntity) throws IOException {
OutputStream os = socket.getOutputStream();
if(oos==null){
oos= new ObjectOutputStream(os);
}
//写到服务器
oos.writeObject(messageEntity);
}
//接受数据
public String receiveData() throws IOException {
InputStream is = socket.getInputStream();
int total = is.read(bs);
//把服务器相应的消息 判断一下
String result = new String(bs,0,total);
return result;
}
}
UserCilentSercive类:专门用来记录登录和注册的输入
public class UserClientService {
DataUtil dataUtil;
ResultUtil resultUtil;
public UserClientService(DataUtil dataUtil,ResultUtil resultUtil){
this.dataUtil =dataUtil;
this.resultUtil = resultUtil;
}
Scanner sc =new Scanner(System.in);
public void login() throws IOException, InterruptedException {
System.out.println("请输入登录的用户名:");
String username = sc.nextLine();
System.out.println("请输入登录的密码:");
String password = sc.nextLine();
UserEntity userEntity = new UserEntity();
userEntity.setPassword(password);
userEntity.setUsername(username);
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(1);
messageEntity.setUserEntity(userEntity);
dataUtil.sendData(messageEntity);
//接受数据
String s = dataUtil.receiveData();
//根据服务器返回的结果取完成不同的处理
resultUtil.postUserResult(s);
}
public void register() throws IOException, InterruptedException {
System.out.println("请输入注册的用户id:");
String userId = sc.nextLine();
System.out.println("请输入注册的用户账号:");
String username = sc.nextLine();
System.out.println("请输入注册的密码:");
String password = sc.nextLine();
UserEntity userEntity = new UserEntity();
userEntity.setUsername(username);
userEntity.setId(Integer.parseInt(userId));
userEntity.setPassword(password);
MessageEntity messageEntity= new MessageEntity();
messageEntity.setOprator(2);
messageEntity.setUserEntity(userEntity);
dataUtil.sendData(messageEntity);
String s = dataUtil.receiveData();
resultUtil.postUserResult(s);
}
}
ResultUtil类:客户端的二级菜单代码
public class ResultUtil {
ClientTest ct;
DataUtil dataUtil;
byte[] bs = new byte[512];
BookClientService bookClientService = new BookClientService();
Scanner sc = new Scanner(System.in);
public ResultUtil(ClientTest ct, DataUtil dataUtil) {
this.ct = ct;
this.dataUtil = dataUtil;
}
public void postUserResult(String result) throws IOException, InterruptedException {
if (result.equals(Contain.LOGINSUCRESULT)) {
System.out.println("登录成功");
String info = ct.menu();
postBookResult(info);
} else if (result.equals(Contain.LOGINFAIRESULT)) {
System.out.println("登录失败--重写操作");
ct.welcome();
} else if (result.equals(Contain.REGISTERSUCRESULT)) {
System.out.println("注册成功");
String info = ct.menu();
postBookResult(info);
} else if (result.equals(Contain.REGISTERFAIRESULT)) {
System.out.println("注册失败");
ct.welcome();
}
}
//统一处理二级菜单的 操作序号
public void postBookResult(String info) throws IOException {
if (info.equals("1")) {
//查询小说列表
//提示--输入小说名字进行阅读
//把小说名字发送给服务器
//服务器:通过IO流读取小说内容---字符流
List<String> list = bookClientService.queryPrintAllBook(dataUtil);
list.stream().forEach(s -> System.out.println(s));
System.out.println("请选择你要阅读的小说:");
//输入小说名
String bookName = sc.nextLine();
//用来记录有页数
int page = 1;
while (true) {
//每一次都向服务器发送要执行的操作和书的页码,让服务器根据页码来读取相应的内容
MessageEntity messageEntity = new MessageEntity();
messageEntity.setBookName(bookName);
messageEntity.setOprator(6);
messageEntity.setPage(page);
//向服务器发送书名,和阅读小说的操作
dataUtil.sendData(messageEntity);
//接受读取到的内容
String content = dataUtil.receiveData();
//打印到控制台
System.out.println(content);
System.out.println("第"+page+"页");
System.out.println("1.上一页 2.下一页");
System.out.println("其他数字退出");
String choose = sc.nextLine();
if (choose.equals("2")){//如果客户端选择下一页,就把页码数加一
page++;
}else if(choose.equals("1")){//如果客户端要阅读上一页,就把页码数减一
//先要判断当前页数是不是第一页
if(page == 1){
System.out.println("当前已经为第一页");
}else{
page--;
}
}else if (page!=1 &&page!=2){
break;
}
if(content.equals("end")){
break;
}
}
String s = ct.menu();
postBookResult(s);
} else if (info.equals("2")) {
System.out.println("请输入小说路径和名字");
//D:\feisi_Java\stream\book\\天龙八部.txt
String bookPathName = sc.nextLine();
//为了获取文件的大小 ---百分比
File file = new File(bookPathName);
//整个文件的字节数
long length = file.length();
System.out.println("文件长度=" + length + "个字节");
//上传----先读到内容---写出去网络
FileInputStream fis = new FileInputStream(file);
//服务器那边不知道你的文件名 ---告诉服务器文件名
String bookName = bookPathName.substring(bookPathName.lastIndexOf("\\\\"));
int total = 0;//每次读取的字节数---读到文件末尾-1
double temp = 0.0;//累计读了多少
boolean flag = true;
while ((total = fis.read(bs)) != -1) {
temp += total;
try {
//为了效果----模拟网络延迟
//本机不存在网络延迟----没有效果
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(3);
if (flag) {
messageEntity.setBookName(bookName);
flag = false;
}
messageEntity.setContent(new String(bs, 0, total));
dataUtil.sendData(messageEntity);
//如果接受成功 这一次读取的内容上传成功
String s = dataUtil.receiveData();
System.out.print("已经完成:" + String.format("%.1f", (temp / length) * 100) + "%\r");
}
System.out.println("上传进度=100%");
System.out.println("上传完成");
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(3);
messageEntity.setContent("end");
dataUtil.sendData(messageEntity);
String r = ct.menu();
postBookResult(r);
} else if (info.equals("3")) {
//下载之前先要做查询
List<String> list = bookClientService.queryPrintAllBook(dataUtil);
System.out.println("请输入下面显示的小说名字进行下载");
//遍历输出所有的小说名字
list.stream().forEach(s -> System.out.println(s));
String bookName = "";
while (true) {
bookName = sc.nextLine();
String finalBookName = bookName;
//遍历查找list中是否存在输入的书名
long count = list.stream().filter(s -> s.equals(finalBookName)).count();
if (count == 0) { //输入的小说名字不存在
System.out.println("请输入合理的小说名字");
} else {
break;
}
}
//收集到用户输入的小说名字,告诉服务器操作为
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(4);
messageEntity.setBookName(bookName);
dataUtil.sendData(messageEntity);
File file = new File(Contain.downloadPath + "\\" + bookName);
if (!file.exists()) {
//当小说不存在是,创建一个小说文件
file.createNewFile();
} else {
//当小说存在时
file.delete(); //先删除原有小说文件
file.createNewFile(); //再创建新的小说文件
}
while (true) {
//接收到的数据
String downLoadContent = dataUtil.receiveData();
if (downLoadContent.endsWith("end")) {
//在上一步的最后,小说末尾有end,表示这里为小说末尾
System.out.println("下载完成!!!!!!!!!!!!!!!");
FileOutputStream fos = new FileOutputStream(file, true);
//这里把所有的end替换成无内容,实际上是删除所有end
fos.write(downLoadContent.replaceAll("end", "").getBytes());
break;
}
//写出接收到的内容到小说文件中
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(downLoadContent.getBytes());
}
//返回二级菜单
String s = ct.menu();
postBookResult(s);
}
}
}
CilentTest类:客户端的运动代码
public class ClientTest {
static Socket socket=null;
Scanner sc =new Scanner(System.in);
static UserClientService userClientService;
public static void main(String[] args) throws IOException, InterruptedException {
ClientTest clientTest = new ClientTest();
clientTest.clientInit();
//封装了接收数据和发送数据的api 功能
DataUtil dataUtil = new DataUtil(socket);
userClientService= new UserClientService(dataUtil,new ResultUtil(clientTest,dataUtil));
clientTest.welcome();
}
//初始化---连接服务器
public void clientInit() throws IOException {
//连接服务器
socket = new Socket();
socket.connect(new InetSocketAddress(8080));
}
//欢迎界面
public void welcome() throws IOException, InterruptedException {
System.out.println("欢迎来到在线小说阅读系统");
System.out.println("1、登录系统");
System.out.println("2、注册用户");
System.out.println("3、退出系统");
System.out.println("输入序号进行操作");
String no = sc.nextLine();
if(no.equals("1")){
userClientService.login();
} else if (no.equals("2")) {//注册
userClientService.register();
}else {
System.exit(0);
}
}
//登录之后的二级菜单
public String menu(){
System.out.println("选择序号操作");
System.out.println("1、阅读小说");
System.out.println("2、上传小说");
System.out.println("3、下载小说");
System.out.println("4、退出");
String info = sc.nextLine();
return info;
}
}
4.服务端特有类
UserService类:验证客户端输入的登录信息和注册信息
public class UserService {
public String login(UserEntity entity) throws DocumentException {
List<UserEntity> userEntities = XMLUtil.parseXml();
//通过stream流来判断用户名和密码是否合格
//解析xml得到的数据----2条
//count=1 表示有一条数据
//else 表示没有数据或者数据大于一条,登录失败
long count = userEntities.stream()
.filter(s -> s.getUsername().equals(entity.getUsername()))
.filter(s -> s.getPassword().equals(entity.getPassword())).count();
if (count == 1){
//登录成功
return ServerApp.LOGINSUCRESULT;
}else {
//登录失败
return ServerApp.LOGINFAIRESULT;
}
}
public String register(UserEntity userEntity) {
try {
XMLUtil.updateXml(userEntity);
//注册成功
return ServerApp.REGISTERSUCRESULT;
} catch (Exception e) {
e.printStackTrace();
//注册失败
return ServerApp.REGISTERFAiRESULT;
}
}
}
XMLUtil类:用来处理xml的相关(例如读取和修改xml文件)
public class XMLUtil {
static List<UserEntity> list = new ArrayList<>();
public static List<UserEntity> getList(){
return list;
}
static String xmlFilePath = "D:\\feisi_Java\\stream\\Server\\src\\Users.xml";
static Document document = null;
/**
* 获取所有的XML当中的元素
*/
public static List<UserEntity> parseXml() throws DocumentException {
Element rootElement = init();
//遍历根节点下面所有的节点
Iterator<Element> iterator = rootElement.elementIterator();
while (iterator.hasNext()){
//一个子元素---更元素下面的子元素
Element element = iterator.next();
//获取元素的属性
Element username = element.element("username");
String usernameValue = username.getStringValue();
Element pwd = element.element("pwd");
String pwdValue = pwd.getStringValue();
UserEntity userEntity = new UserEntity();
userEntity.setUsername(usernameValue);
userEntity.setPassword(pwdValue);
list.add(userEntity);
}
return list;
}
public static Element init() throws DocumentException {
List<UserEntity> list = new ArrayList<>();
File file = new File(xmlFilePath);
//实例化SAXReader对象 读取xml
SAXReader saxReader = new SAXReader();
//整个xml的内容----Document
document = saxReader.read(file);
//根元素节点
Element rootElement = document.getRootElement();
return rootElement;
}
//更新
public static void updateXml(UserEntity userEntity) throws DocumentException, IOException {
Element rootElement = init();
//往根元素下面添加一个属性 user
Element element = rootElement.addElement("user");
//给先添加的user元素添加一个属性 userId
element.addAttribute("userId",userEntity.getId() + "");
element.addElement("username").setText(userEntity.getUsername());
element.addElement("pwd").setText(userEntity.getPassword());
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
FileWriter fw = new FileWriter(xmlFilePath);
XMLWriter xw = new XMLWriter(fw,format);
xw.write(document);
xw.close();
fw.close();
}
public static boolean isEmpty(String s){
if (s==null){
return true;
}else if (s.equals("")){
return true;
}
return false;
}
}
Users.xml文件:存放用户的信息
任务一:客户端和服务器端通信连接
分析
创建服务器端线程类,并循环监听状态
创建客户端,请求服务器并发送消息
服务器端响应客户端
//服务端
public void init() throws IOException, ClassNotFoundException, DocumentException {
//监听是否有人来连接
ServerSocket serverSocket = new ServerSocket();
//绑定端口号
serverSocket.bind(new InetSocketAddress(8080));
System.out.println("服务器已启动,等待客户端连接...");
//监听
socket = serverSocket.accept();
System.out.println("客户端已连接到服务器..."+socket.getInetAddress());
postClientMessage();
}
//客户端
public void clientInit() throws IOException {
//连接服务器
socket = new Socket();
socket.connect(new InetSocketAddress(8080));
}
任务二:登录、注册、退出功能
分析
1. 创建用于保存登录信息的文件
2. 接收用户登录信息并查找登录信息文件,判断是否登录成功
3. 接收用户注册信息并保存至登录信息文件
//服务端判定客户端输入内容
if (m.getOprator() == 1) { //登录
//客户端输入的用户名,密码
String result = userService.login(m.getUserEntity());
//把登录结果write给客户端
os.write(result.getBytes());
}else if (m.getOprator() == 2){
//客户端输入的用户id,用户名,密码
String register = userService.register(m.getUserEntity());
//把注册结果write给客户端
os.write(register.getBytes());
}
任务三:小说查询列表功能
else if (m.getOprator()==5){ //查询小说列表
String bookList = "";
File file = new File(Contain.bookPath);
String[] list = file.list();
for (String s : list) {
bookList += s+"-";
}
os.write(bookList.getBytes());
}
任务四:在线阅读小说功能
分析
添加用于存放各类小说文件地址的配制项
根据配制文件和小说列表xml文件将所有小说对象添加到List中
根据用户选择的小说名,从List中查找小说地址并显示内容
if (info.equals("1")) { //阅读小说
List<String> list = bookClientService.queryPrintAllBook(dataUtil);
list.stream().forEach(s -> System.out.println(s));
System.out.println("请选择你要阅读的小说:");
//输入小说名
String bookName = sc.nextLine();
//用来记录有页数
int page = 1;
while (true) {
//每一次都向服务器发送要执行的操作和书的页码,让服务器根据页码来读取相应的内容
MessageEntity messageEntity = new MessageEntity();
messageEntity.setBookName(bookName);
messageEntity.setOprator(6);
messageEntity.setPage(page);
//向服务器发送书名,和阅读小说的操作
dataUtil.sendData(messageEntity);
//接受读取到的内容
String content = dataUtil.receiveData();
//打印到控制台
System.out.println(content);
System.out.println("第"+page+"页");
System.out.println("1.上一页 2.下一页");
System.out.println("其他数字退出");
String choose = sc.nextLine();
if (choose.equals("2")){//如果客户端选择下一页,就把页码数加一
page++;
}else if(choose.equals("1")){//如果客户端要阅读上一页,就把页码数减一
//先要判断当前页数是不是第一页
if(page == 1){
System.out.println("当前已经为第一页");
}else{
page--;
}
}else if (page!=1 &&page!=2){
break;
}
if(content.equals("end")){
break;
}
}
String s = ct.menu();
postBookResult(s);
}
任务五:上传小说功能
分析
根据用户输入的小说路径,读取源文件
根据配制文件的各类小说路径,将读取的源文件写入相应位置
根据用户输入的小说信息:小说名,保存至小说列表xml文件
else if (info.equals("2")) {
System.out.println("请输入小说路径和名字");
//D:\feisi_Java\stream\book\\天龙八部.txt
String bookPathName = sc.nextLine();
//为了获取文件的大小 ---百分比
File file = new File(bookPathName);
//整个文件的字节数
long length = file.length();
System.out.println("文件长度=" + length + "个字节");
//上传----先读到内容---写出去网络
FileInputStream fis = new FileInputStream(file);
//服务器那边不知道你的文件名 ---告诉服务器文件名
String bookName = bookPathName.substring(bookPathName.lastIndexOf("\\\\"));
int total = 0;//每次读取的字节数---读到文件末尾-1
double temp = 0.0;//累计读了多少
boolean flag = true;
while ((total = fis.read(bs)) != -1) {
temp += total;
try {
//为了效果----模拟网络延迟
//本机不存在网络延迟----没有效果
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(3);
if (flag) {
messageEntity.setBookName(bookName);
flag = false;
}
messageEntity.setContent(new String(bs, 0, total));
dataUtil.sendData(messageEntity);
//如果接受成功 这一次读取的内容上传成功
String s = dataUtil.receiveData();
System.out.print("已经完成:" + String.format("%.1f", (temp / length) * 100) + "%\r");
}
System.out.println("上传进度=100%");
System.out.println("上传完成");
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(3);
messageEntity.setContent("end");
dataUtil.sendData(messageEntity);
String r = ct.menu();
postBookResult(r);
}
任务六:下载小说功能
分析
在配制文件添加下载路径的配制项
根据用户选择的小说读取小说源文件
把读取的文件写到对应下载路径中
else if (info.equals("3")) {
//下载之前先要做查询
List<String> list = bookClientService.queryPrintAllBook(dataUtil);
System.out.println("请输入下面显示的小说名字进行下载");
//遍历输出所有的小说名字
list.stream().forEach(s -> System.out.println(s));
String bookName = "";
while (true) {
bookName = sc.nextLine();
String finalBookName = bookName;
//遍历查找list中是否存在输入的书名
long count = list.stream().filter(s -> s.equals(finalBookName)).count();
if (count == 0) { //输入的小说名字不存在
System.out.println("请输入合理的小说名字");
} else {
break;
}
}
//收集到用户输入的小说名字,告诉服务器操作为
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(4);
messageEntity.setBookName(bookName);
dataUtil.sendData(messageEntity);
File file = new File(Contain.downloadPath + "\\" + bookName);
if (!file.exists()) {
//当小说不存在是,创建一个小说文件
file.createNewFile();
} else {
//当小说存在时
file.delete(); //先删除原有小说文件
file.createNewFile(); //再创建新的小说文件
}
while (true) {
//接收到的数据
String downLoadContent = dataUtil.receiveData();
if (downLoadContent.endsWith("end")) {
//在上一步的最后,小说末尾有end,表示这里为小说末尾
System.out.println("下载完成!!!!!!!!!!!!!!!");
FileOutputStream fos = new FileOutputStream(file, true);
//这里把所有的end替换成无内容,实际上是删除所有end
fos.write(downLoadContent.replaceAll("end", "").getBytes());
break;
}
//写出接收到的内容到小说文件中
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(downLoadContent.getBytes());
}
//返回二级菜单
String s = ct.menu();
postBookResult(s);
}
5.错误提示
提示:所有的功能中,向服务端传送的数据的oprator数字,必须和对应功能一样,否则可能会出现Exception in thread “main” java.net.SocketException: Connection reset(线程“main”java.net.SocketException异常:连接重置)的错误。一般出现这个错误说明你客户端或者服务端有一端的读写出错了,或者有一端连接断开,可以使用debug一步步查看。
6.效果展示
总结
经过这一次的在线小说阅读系统,我对很多知识有了更全面的了解,不再只停留在之前固定的几种方式中。例如I/O流,在项目之前,做的最复杂的也就是文件的复制,而且有具体的模版,所以我对I/O流没有很熟悉,但是这次项目,结合Socket编程一起,不再只是简单的拿名字或者复制,而是实现了客户端和服务端内容的交互,服务端的内容可以写出到客户端中,客户端的内容也可以写入到服务端中进行判断。
对于Socket编程,更加体验到了它的难点,尤其是关于客户端和服务端两边的信息交互,它们之间是如何输入输出的,又用什么连接起来,这也是我需要继续去努力学习的地方,在编程中遇到的错误也大部分出自于有关Socket的地方,都努力去解决了。
总的来说,这个项目让我对这一阶段的知识有了更全面、深刻的认识,更加意识到自己在哪些方面有不足,需要继续努力的。