目录
实现客户端与服务端的文件传输
该案例需要一个客户端和一个服务端;其本质和文件的复制十分相似,但在客户端本地文件的发送和服务端文件的接收需要使用socket网络流进行传输
Server服务端代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8889);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
//这个用于在本地盘中创建文件夹来存放图片
File file = new File("D:\\桌面\\接收");
if (!file.exists()) {
file.mkdirs();
}
//进行文件的下载(相当于复制)
FileOutputStream fos = new FileOutputStream(file+"\\接收的图片.jpg");
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
//回写信息
socket.getOutputStream().write("上传成功".getBytes(StandardCharsets.UTF_8));
fos.close();
socket.close();
server.close();
}
}
Client客户端代码:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端:读取本地文件 ,上传到服务器,读取服务器回写的数据
*
* 实现步骤:
* 创建一个本地字节输入流读取本地的数据源。创建一个客户端socket绑定服务器的ip和端口号。
* 用socket中方法getOutputStream获取网络字节输出流;输出读取的本地数据到服务端
* 用socket中方法getInputStream获取网络字节输入流;输入服务端回写的数据
* 释放资源
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("D:\\桌面\\发送\\上传图片.jpg");//本地读取文件
Socket socket=new Socket("127.0.0.1",8889);//创建客户端套接字
//进行文件上传
OutputStream os=socket.getOutputStream();
int len=0;
byte[]bytes=new byte[1024];
while ((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//由于socket的os流的结束标记是读取到-1结束,而while循环又始终不会读取到-1,所以其os流会进入堵塞状态,无法终止
//因而需要给服务器一个结束的标记;用 socket.shutdownOutput()方法,禁用套接字的os流;
// 对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常终结序列
socket.shutdownOutput();
//读取服务端回写数据
InputStream is=socket.getInputStream();
while ((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
fis.close();
socket.close();
}
}
文件传输案例的优化
在刚才的案例中服务端又以下几个问题:1、仅传输一次服务便终止,无法满足多次传输的;2、接收文件的命名唯一,会造成文件的覆盖问题;3.当多个文件同时上传,服务端一直处于循环状态,会导致效率低下
下面我们将针对这三点进行优化:
第一个问题可以用一个while死循环,让服务端一个保存开启状态;第二个可以设定一个文件命名格式,保证文件名不重复;第三个可以通过多线程的方式解决
优化后Server服务端代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Random;
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
/**
* 让服务器一直处于监听的状态(死循环accept),同时server.close()也不用在写
*/
while (true) {
Socket socket = server.accept();
/**
* 使用多线程技术,提高程序的效率
* 有一个客户端上传文件,就开启一个线程,完成文件的上传
*/
//完成文件的上传
new Thread(() -> {
try {
InputStream is = socket.getInputStream();
//这个用于在本地盘中创建文件夹来存放图片
File file = new File("D:\\桌面\\接收");
if (!file.exists()) {
file.mkdirs();
}
//自定义一个文件命名规则,防止同名的文件被覆盖:域名+毫秒值+随机数
String fileName = "yz" + System.currentTimeMillis() + new Random().nextInt(10000) + ".jpg";
//进行文件的下载(相当于复制)
FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
//回写信息
socket.getOutputStream().write("上传成功".getBytes(StandardCharsets.UTF_8));
fos.close();
socket.close();
} catch (IOException e) {
System.out.println(e);
}
}).start();//注意要开启线程,否则线程会一直处于堵塞状态
}
}
}