设计一个简单的文件传输程序,服务器接受文件,客户端发送文件,设计一个简单的文件传输协议,比如,先传输文件名,再传输文件大小,再传输文件内容。
设计不合理。
一个文件信息,不需要分成几个包来来回回请求应答。
协议格式类似如下:
8位数据包总长+3位文件名长度+文件名+ 8位文件内容长度+文件内容
以上为变长报文格式,举例如下:
00001048+008+test.txt+00001024+文件内容
要么像2L所定义的协议那样发送,简单
要么就像你期望的那样,定义协议位 数据长度(固定长度)+数据类型(固定长度)+数据
第一次传文件名 比如8位长度(String.format("%08d", filename.getBytes().length).getByes())+数据类型("01".getBytes())+数据(filename.getBytes())
第二次传文件大小 8位长度+数据类型("02")+file.getLength()
第三次以后 8位长度+数据类型("03")+file.read(buf) //最后要check和第二次传送的文件长度一致
如果是基于tcp的长连接进行传输,最好先把文件名、文件大小等文件信息进行加密传输,然后再传输实际的文件流,这样接收方可以先解密文件报文,再取根据报文内容来解析文件流。这样一是可以保证文件安全,排除非法文件传输,二是可以让接收方有据可依。
怎么用多线程完成这个任务啊
这个问题,相当于一个问题终结者。资源代下载99dxz
楼主的协议太墨迹了,我写了一个简单的demo,和楼主共同探讨一下。
我觉得没有必要多次交互,服务端只需要被动的接受就好了。
如果需要交互行为的话,服务端和客户端的编程模式就会复杂一些,建议使用netty进行开发。
这个是服务端的demo,接收一个文件。
package houlei.net.tcp;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
public class FileServer {
private final File tmpPath;
private final File targetPath;
private final int port;
private final LinkedList<Worker> workers = new LinkedList<Worker>();
private ServerSocket serverSocket;
private class Worker extends Thread {
private final Socket socket;
private Worker(Socket socket) {
this.socket = socket;
}
public void run(){
try {
InputStream is = socket.getInputStream();
byte[] nameLen = new byte[4];
if (is.read(nameLen) == 4) {
int nameLength = (nameLen[0]&0xFF)<<24 | (nameLen[1]&0xFF)<<16 | (nameLen[2]&0xFF)<<8 | (nameLen[3]&0xFF)<<0;
byte[] name = new byte[nameLength];
if (nameLength == is.read(name)) {
String fileName = new String(name, Charset.forName("UTF-8"));
byte[] length = new byte[8];
if (is.read(length) == 8) {
long fileLength = (length[0]&0xFF)<<56 | (length[1]&0xFF)<<48 | (length[2]&0xFF)<<40 | (length[3]&0xFF)<<32 |
(length[4]&0xFF)<<24 | (length[5]&0xFF)<<16 | (length[6]&0xFF)<<8 | (length[7]&0xFF)<<0;
readFile(fileName, fileLength, is);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
workers.remove(Worker.this);
System.out.println("bye : "+socket.getRemoteSocketAddress());
}
}
private void readFile(String fileName, long fileLength, InputStream is) throws IOException {
String prefix = "trans-" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
if (tmpPath.getUsableSpace() > fileLength && targetPath.getUsableSpace() > fileLength) {
File tempFile = File.createTempFile(prefix, "tmp", tmpPath);
OutputStream os = new FileOutputStream(tempFile);
transform(os, is);
os.close();
File targetFile = new File(targetPath, fileName);
if (tempFile.renameTo(targetFile)) {
// succeed.
}
}
}
private void transform(OutputStream os, InputStream is) throws IOException {
byte[] buffer = new byte[4096];
int length = 0;
while((length = is.read(buffer))>0) {
os.write(buffer, 0, length);
}
os.flush();
}
}
public FileServer(File tmpPath, File targetPath, int port) {
if (tmpPath == null) {
tmpPath = new File(System.getProperty("java.io.tmpdir"));
}
if (!tmpPath.exists()) {
tmpPath.mkdirs();
}
if (targetPath == null || !targetPath.exists()) {
throw new IllegalArgumentException("targetPath does not exists.");
}
this.tmpPath = tmpPath;
this.targetPath = targetPath;
this.port = port;
}
public void start() throws IOException {
if (serverSocket == null) {
serverSocket = new ServerSocket(port);
Socket socket;
while((socket = serverSocket.accept()) != null) {
System.out.println("accept : "+ socket.getRemoteSocketAddress());
Worker worker = new Worker(socket);
workers.add(worker);
worker.start();
}
}
}
public static void main(String[] args) throws IOException {
File targetFolder = new File("/Users/naver/target");
targetFolder.mkdirs();
FileServer server = new FileServer(null, targetFolder, 6606);
server.start();
}
}
这个是客户端的demo,和服务端配合,将客户端的文件传输到服务端。
package houlei.net.tcp;
import java.io.*;
import java.net.Socket;
import java.nio.charset.Charset;
public class FileClient {
private final String serverIp;
private final int serverPort;
private Socket socket;
public FileClient(String serverIp, int serverPort) {
this.serverIp = serverIp;
this.serverPort = serverPort;
}
public void connect() throws IOException {
if (socket == null) {
socket = new Socket(serverIp, serverPort);
}
}
public void sendFile(File file) throws IOException {
if (!file.exists() || !file.isFile()) {
throw new IllegalArgumentException("file ("+file.getName()+") does not exists.");
}
String fileName = file.getName();
long fileLength = file.length();
InputStream inputStream = new FileInputStream(file);
sendFile(fileName, fileLength, inputStream);
}
private void sendFile(String fileName, long fileLength, InputStream inputStream) throws IOException {
byte[] name = fileName.getBytes(Charset.forName("UTF-8"));
byte[] nameLen = new byte[4];
nameLen[0] = (byte) ((name.length>>>24)&0xFF);nameLen[1] = (byte) ((name.length>>>16)&0xFF);
nameLen[2] = (byte) ((name.length>>> 8)&0xFF);nameLen[3] = (byte) ((name.length>>> 0)&0xFF);
byte[] length = new byte[8];
length[0] = (byte) ((fileLength>>>56)&0xFF);length[1] = (byte) ((fileLength>>>48)&0xFF);
length[2] = (byte) ((fileLength>>>40)&0xFF);length[3] = (byte) ((fileLength>>>32)&0xFF);
length[4] = (byte) ((fileLength>>>24)&0xFF);length[5] = (byte) ((fileLength>>>16)&0xFF);
length[6] = (byte) ((fileLength>>> 8)&0xFF);length[7] = (byte) ((fileLength>>> 0)&0xFF);
if (socket.isConnected()) {
OutputStream os = socket.getOutputStream();
os.write(nameLen);
os.write(name);
os.write(length);
os.flush();
transform(os, inputStream);
}
}
private void transform(OutputStream os, InputStream is) throws IOException {
byte[] buffer = new byte[4096];
int length = 0;
while((length = is.read(buffer))>0) {
os.write(buffer, 0, length);
}
os.flush();
}
public static void main(String[] args) throws IOException {
FileClient client = new FileClient("127.0.0.1", 6606);
client.connect();
client.sendFile(new File("/Users/naver/helper.js"));
}
}