#博学谷IT学习技术支持
目录
前言
个人学习笔记,欢迎指出任何错误,留言意见。
我的文章都将随着个人学习深入而定期更新。
以最简洁的风格,记录概念和方法
-
需求
客户端:数据来自于本地文件,接收服务器反馈
服务器:接收到的数据写入本地文件,给出反馈
-
分析
创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束
创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后。使用输出流给客户端反馈信息
客户端接受服务端的回馈信息
相关方法:
方法名 | 说明 |
---|---|
void shutdownInput() | 将此套接字的输入流放置在“流的末尾” |
void shutdownOutput() | 禁止用此套接字的输出流 |
先看基础实现代码 :
// 客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10000);
//是本地的流,用来读取本地文件的.
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("socketmodule\\ClientDir\\1.jpg"));
//写到服务器 --- 网络中的流
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
int b;
while((b = bis.read())!=-1){
bos.write(b);//通过网络写到服务器中
}
bos.flush();
//给服务器一个结束标记,告诉服务器文件已经传输完毕
socket.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while((line = br.readLine()) !=null){
System.out.println(line);
}
bis.close();
socket.close();
}
}
// 服务器
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
Socket accept = ss.accept();
//网络中的流,从客户端读取数据的
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//本地的IO流,把数据写到本地中,实现永久化存储
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("socketmodule\\ServerDir\\copy.jpg"));
int b;
while((b = bis.read()) !=-1){
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
bos.close();
accept.close();
ss.close();
}
}
优化方案一
-
需求
服务器只能处理一个客户端请求,接收完一个图片之后,服务器就关闭了。
-
解决方案
使用循环
-
代码实现
// 服务器代码如下,客户端代码同上个案例,此处不再给出
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
while (true) {
Socket accept = ss.accept();
//网络中的流,从客户端读取数据的
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//本地的IO流,把数据写到本地中,实现永久化存储
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("optimizeserver\\ServerDir\\copy.jpg"));
int b;
while((b = bis.read()) !=-1){
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
bos.close();
accept.close();
}
//ss.close();
}
}
优化方案二
-
需求
第二次上传文件的时候,会把第一次的文件给覆盖。
-
解决方案
UUID. randomUUID()方法生成随机的文件名
-
代码实现
// 服务器代码如下,客户端代码同上个案例,此处不再给出
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
while (true) {
Socket accept = ss.accept();
//网络中的流,从客户端读取数据的
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//本地的IO流,把数据写到本地中,实现永久化存储
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("optimizeserver\\ServerDir\\" + UUID.randomUUID().toString() + ".jpg"));
int b;
while((b = bis.read()) !=-1){
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
bos.close();
accept.close();
}
//ss.close();
}
}
优化方案三
-
需求
使用循环虽然可以让服务器处理多个客户端请求。但是还是无法同时跟多个客户端进行通信。
-
解决方案
开启多线程处理
-
代码实现
// 线程任务类
public class ThreadSocket implements Runnable {
private Socket acceptSocket;
public ThreadSocket(Socket accept) {
this.acceptSocket = accept;
}
@Override
public void run() {
BufferedOutputStream bos = null;
try {
//网络中的流,从客户端读取数据的
BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
//本地的IO流,把数据写到本地中,实现永久化存储
bos = new BufferedOutputStream(new FileOutputStream("optimizeserver\\ServerDir\\" + UUID.randomUUID().toString() + ".jpg"));
int b;
while((b = bis.read()) !=-1){
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (acceptSocket != null){
try {
acceptSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 服务器代码
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
while (true) {
Socket accept = ss.accept();
ThreadSocket ts = new ThreadSocket(accept);
new Thread(ts).start();
}
//ss.close();
}
}
优化方案四
-
需求
使用多线程虽然可以让服务器同时处理多个客户端请求。但是资源消耗太大。
-
解决方案
加入线程池
-
代码实现
// 服务器代码如下,线程任务类代码同上,此处不再给出 public class ServerDemo { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(10000); ThreadPoolExecutor pool = new ThreadPoolExecutor( 3,//核心线程数量 10, //线程池的总数量 60, //临时线程空闲时间 TimeUnit.SECONDS, //临时线程空闲时间的单位 new ArrayBlockingQueue<>(5),//阻塞队列 Executors.defaultThreadFactory(),//创建线程的方式 new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略 ); while (true) { Socket accept = ss.accept(); ThreadSocket ts = new ThreadSocket(accept); //new Thread(ts).start(); pool.submit(ts); } //ss.close(); } }