有子曰:“其为人也孝弟,而好犯上者,鲜矣;不好犯上,而好作乱者,未之有也。君子务本,本立而道生。孝弟也者,其为仁之本与!”
项目介绍:基于TCP协议实现多文件传输
将F盘test文件加下的所有文件发送到D盘下的FTP文件夹里
思路:socket发送单个文件,然后通过for循环来实现多文件传输。
简单做法(这里就简单说下思路,没实现):
_1) socket与服务器建立连接
_2) 然后发送一个文件
_3) socket断开
_4) 循环第一步
以上做法非常简单,但是socket建立连接时非常耗费资源的,如果有1000个文件要同时上传,那么socket就要与服务器建立1000次连接和1000次断开连接。写到这里我突然想到连接池,连接池也是一种提高的方法,虽然没有频繁的创建销毁,但是初始化的时候就占用了系统的资源,我何不创建一个socket用到系统报废呢。
高端做法:
所以如果你还不知道IO流的概念,那你就不能算是一个合格的程序员
我这里简单的说一下,大神绕道
当客户端想服务端发送数据的时候,是以byte[]的形式传输的,byte[]数组存放的是ASCII码
比如第一次发送的是"ABC",然后紧接着又发送"abcd"
那么服务端接受接受到的就是"ABCabcd"
所以流是不会断开的,既然是连在一起的,那么怎么区分呢?
那就要同时向服务端传一个长度
比如第一次发送的是"ABC",那么在发送"ABC"之前要让服务器知道我发送的内容长度,这里发送一个int类型的3
同理发送"abcd"之前也要发一个int类型的4,这是长度让,让服务器截取内容用的。
然后服务器解析的时候先获取前4个字节解析长度,然后通过长度来获取内容
_1) socket与服务器建立连接
_2) 然后for循环发送多个文件
_3) socket断开
从建立连接到发送完毕断开连接,从始至终都是只有一个socket。
先画一个流程图。(好丑啊)
OK不废话了,开始上代码
1.启动服务,等待客户端连接
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
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.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MoveAction;
public class TcpSendFileServer {
@SuppressWarnings("resource")
public static void main(String[] args) {
int port = 5555;
ServerSocket server = null;
Socket socket = null;
try {
server = new ServerSocket(port);
System.out.println("======启动服务=======");
String pathname = "D:\\FTP\\";
File d = new File(pathname);
if(!d.exists()){
d.mkdir();
}
//使用线程池
ExecutorService threadPool = Executors.newFixedThreadPool(100);
while(true){
socket = server.accept();
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
int fileNum = dis.readInt();
System.out.println("传输的文件总个数:"+fileNum);
String[] fileNames = new String[fileNum];
long[] fileSizes = new long[fileNum];
for (int i = 0; i < fileNum; i++) {
fileNames[i] = dis.readUTF();
fileSizes[i] = dis.readLong();
System.out.println("文件名:"+fileNames[i]);
System.out.println("文件大小:"+fileSizes[i]);
}
int byteNum = 1024;
Runnable runnable = () -> {
FileOutputStream fos = null;
try {
byte[] bytes = new byte[byteNum];
//储存剩下的字节
byte[] surplusbytes = new byte[byteNum];
int length = 0;
//文件剩余大小
int leftLen = 0;
int writeLen = 0;
boolean flog = true;
int num = 0;
long totalWriteLens = 0;
//没用的变量
int testLen = 0;
int pointLen = 0;
while(((length = dis.read(bytes, 0, bytes.length)) != -1 || surplusbytes[0] != 0) && num < fileNum){
if(flog){
System.out.println("开始接受文件"+(num+1));
File file = new File(pathname+fileNames[num]);
fos = new FileOutputStream(file);
totalWriteLens = 0;
testLen = 0;
flog = false;
if((num+1) == 6){
System.out.println("=-----------------");
}
}
if(length >= (int)fileSizes[num] || surplusbytes[0] != 0){
if(surplusbytes[0] != 0){
testLen = surplusbytes.length - pointLen;
if((int)fileSizes[num] >= testLen){
fos.write(surplusbytes, 0, testLen);
fos.flush();
surplusbytes = new byte[byteNum];
totalWriteLens += testLen;
}else{
fos.write(surplusbytes, 0, (int)fileSizes[num]);
fos.flush();
leftLen = surplusbytes.length - (int)fileSizes[num];
move(surplusbytes, surplusbytes, (int)fileSizes[num] , leftLen);
testLen = 0;
flog = true;
}
}
if(length >= (int)fileSizes[num] - testLen){
fos.write(bytes, 0, (int)fileSizes[num] - testLen);
fos.flush();
pointLen = (int)fileSizes[num] - testLen;
leftLen = bytes.length - (int)fileSizes[num];
move(surplusbytes, bytes, (int)fileSizes[num] , leftLen);
}else{
if(surplusbytes[0] != 0 && !flog){
fos.write(surplusbytes, 0, (int)fileSizes[num]);
surplusbytes = new byte[byteNum];
}
if(!flog){
fos.write(bytes);
surplusbytes = new byte[byteNum];
}
fos.flush();
totalWriteLens += length;
}
if(surplusbytes[0] != 0 || num >= fileNum){
flog = true;
num ++;
}
}else{
if((fileSizes[num] - totalWriteLens) / length < 1){
length = (int)(fileSizes[num] - totalWriteLens);
}
if(surplusbytes[0] != 0){
fos.write(surplusbytes, 0, leftLen);
fos.flush();
surplusbytes = new byte[byteNum];
}
fos.write(bytes, 0, length);
fos.flush();
leftLen = bytes.length - length;
pointLen = length;
move(surplusbytes, bytes, length, leftLen);
if(surplusbytes[0] != 0){
flog = true;
num ++;
}
totalWriteLens += length;
}
}
System.out.println("==========文件传输完毕===========");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos != null){
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
threadPool.execute(runnable);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
/**
*
* @param surplusbytes
* @param bytes
* @param length 已经使用的个数
* @param leftLen 剩下需要转移的数组个数
*/
public static void move(byte[] surplusbytes, byte[] bytes, int length, int leftLen){
for (int i = 0; i < leftLen; i++) {
if(bytes[length+i] != 0){
surplusbytes[i] = bytes[length+i];
}
}
}
}
2.客户端建立一个连接发送多文件
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
public class TcpSendFileClient {
public static int port = 5555;
public static String host = "localhost";
public static Socket socket = null;
@SuppressWarnings("resource")
public static void main(String[] args) {
//创建socket连接
createSocket();
try {
//发送文件的发放,需要文件价路径
sendMultipleFile( "F:\\Test");
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭socket连接
closeSocket();
}
}
public static void sendMultipleFile(String path) throws Exception{
String[] fileNames = getFileName(path);
sendSingleFile(path, fileNames);
}
public static String[] getFileName(String path){
File file = new File(path);
return file.list();
}
public static File[] createFile(String path, String[] pathname){
File[] files = new File[pathname.length];
try {
for (int i = 0; i < pathname.length; i++) {
File file = new File(path+"\\"+pathname[i]);
if(file.exists() && file.isFile()){
file.createNewFile();
files[i] = file;
}
}
return files;
} catch (IOException e) {
e.printStackTrace();
}
return files;
}
public static void sendSingleFile(String path, String[] pathName) throws Exception{
File[] file = createFile(path, pathName);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeInt(file.length);
dos.flush();
//将文件名和文件长度先发送过去
for (int i = 0; i < file.length; i++) {
System.out.println(file.length+"=="+file[i].getName()+"=="+file[i].length());
dos.writeUTF(file[i].getName());
dos.flush();
dos.writeLong(file[i].length());
dos.flush();
}
System.out.println("开始发送文件...");
byte[] bytes = new byte[1024];
int length = 0;
//发送文件内容
for (int i = 0; i < file.length; i++) {
FileInputStream fis = new FileInputStream(file[i]);
while((length = fis.read(bytes, 0, bytes.length)) != -1){
dos.write(bytes, 0, length);
dos.flush();
}
}
System.out.println("文件发送完毕...");
}
public static void createSocket(){
try {
socket = new Socket(host, port);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closeSocket(){
try {
if(socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.运行结果
客户端打印信息
4==1.jpg==161236
4==2.jpg==182327
4==3.jpg==42138
4==4.jpg==73057
开始发送文件...
文件发送完毕...
======== 文件传输结束 ========
服务端打印信息
======启动服务=======
传输的文件总个数:4
文件名:1.jpg
文件大小:161236
文件名:2.jpg
文件大小:182327
文件名:3.jpg
文件大小:42138
文件名:4.jpg
文件大小:73057
开始接受文件1
开始接受文件2
开始接受文件3
开始接受文件4
==========文件传输完毕===========
成功将4个文件传送过去了
作者是一名自由程序员,住在上海,喜欢音乐、小说、旅行、以及编程。
P.S. 如果您喜欢这篇文章并且希望学习编程技术的话,请关注一下
网友评论