nodejs如何实现简单的文件服务器
文件名的长度(两个字节)
文件名(长度不定,由前两个字节决定)
文件内容的长度(8个字节)
内容 (长度不定,由前8个字节决定)
使用nodejs 实现服务端
var net = require("net");var fs = require( "fs" );var server = net.createServer();server.on("connection", function(client){
console.log("client connected to server。IP:%s,port%s", client.remoteAddress, client.remotePort);
var isFirst = true ;
var fd ;
var contentLength = 0 ;
var dataTotalLength =0;
var receiveData = Buffer.alloc(0);
// data长度不可控,需要自己合并多个data直至指定的要求或者发送的socket发送FIN
client.on("data", function(data){
if (isFirst) {
receiveData = Buffer.concat([receiveData, data]);
if (receiveData.length < 2) {
console.error("奇葩,data长度为%s", data.length)
return ;
}else {
var start = 0;
var end = 2;
var buffer = Buffer.from(receiveData.slice(start, end));
var filenamelength = buffer.readInt16BE();
console.log("文件名长度为:%s" , filenamelength);
}
if (receiveData.length < filenamelength + 10) {
console.error("奇葩,data长度为%s", data.length)
return;
}
var start = end;
var end = end + filenamelength;
var buffer = Buffer.from(receiveData.slice(start, end));
var filename = buffer.toString();
console.log("文件名为:%s" ,filename);
var start = end;
var end = end + 8;
var buffer = Buffer.from(receiveData.slice(start, end));
contentLength = buffer.readBigInt64BE();
console.log("文件长度为:%s" , contentLength);
var newfilename = "data/" + filename;
fd = fs.openSync(newfilename, "w+");
isFirst = false;
var var1 = receiveData.slice(end)
fs.writeFileSync(fd, var1);
dataTotalLength += receiveData.length - end;
}else {
fs.writeFileSync(fd, data);
dataTotalLength += data.length;
}
if(dataTotalLength == contentLength){
console.log("文件传输完毕");
}
});
client.on("end", function () {
console.log(dataTotalLength);
console.log(contentLength);
console.log("关闭socket!")
});
client.on("error",function (e) {
console.error(e);
})
});
server.listen(7251, "0.0.0.0");
虽然不是很喜欢这种弱类型的语言,但是nodejs与生俱来的的多线程特性还是让人震惊,以上实现中没有出现任何与Thread相关的关键词,但这却是一个支持多线程上传的服务。
java 客户端(多线程上传)
package test;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.net.Socket;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.atomic.AtomicInteger;public class FileTransferClient{
public static final String SERVER_IP = "127.0.0.1"; // 服务端IP
public static final int SERVER_PORT = 7251; // 服务端端口
public static void main(String[] args) throws Exception{
String datadir = "C:\Users\who\Desktop\testdata\data\face" ;
File directory = new File(datadir) ;
assert directory.isDirectory() ;
ExecutorService executor = Executors.newFixedThreadPool(10);
int count = 0 ;
for (File file : directory.listFiles()) {
if(file.isFile()) {
Task task = new Task(file.getAbsolutePath());
executor.submit(task);
count ++ ;
}
}
while (true) {
if (aCount.get() == count) {
System.out.println("end");
executor.shutdown();
break;
}
Thread.sleep(1000);
}
}
public static AtomicInteger aCount = new AtomicInteger(0);
}
class Task implements Runnable {
private String filename;
public Task(String filename){
this.filename = filename ;
}
@Override
public void run() {
try {
Socket socket = new Socket(FileTransferClient.SERVER_IP, FileTransferClient.SERVER_PORT);
FileInputStream fis = null;
DataOutputStream dos = null;
File file = new File(filename);
if (file.exists()) {
fis = new FileInputStream(file);
dos = new DataOutputStream(socket.getOutputStream());
// 文件名和长度
byte[] namebytes = file.getName().getBytes();
dos.writeShort(namebytes.length);
dos.write(namebytes);
dos.writeLong(file.length());
dos.flush();
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes, 0, bytes.length)) != -1) {
dos.write(bytes, 0, length);
dos.flush();
}
}
if (fis != null)
fis.close();
if (dos != null)
dos.close();
if (!socket.isClosed()) {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
FileTransferClient.aCount.addAndGet(1);
}
}
nodejs 客户端
var net = require("net");var fs = require("fs");function sendfile(filename) {
console.log(filename);
var socket = new net.Socket();
socket.on("ready",function () {
var contentSize = 0 ;
fs.stat(filename,function(error,stats){
if(error){
console.error(error)
}else{
contentSize = stats.size ;
console.log(contentSize) ;
}
var length = 2 + filename.length + 8 ;
var buffer = Buffer.alloc(length) ;
buffer.writeInt16BE(filename.length,0);
buffer.write(filename,2);
var bigInt = BigInt(contentSize);
var start = Number(2 + filename.length);
buffer.writeBigInt64BE(bigInt,start);
socket.write(buffer.slice(0,length)) ;
// 大文件应该一次读取不了,不想写了
var data = fs.readFileSync(filename);
socket.write(data);
}) ;
}) ;
socket.on("error",function (e) {
console.error(e)
}) ;
socket.connect(7251, "localhost");
}
sendfile("app.js");
sendfile("client.js");
nodejs 的 socket在处理字节流时不能主动的去read, 只能靠data事件来触发回调函数,但是data并不是一次能接收到所有的字节流,因此在处理时需要自己合并多个data才行,以下是一个小小的使用建议。
var net = require("net");var client = new net.Socket();
var receiveData = Buffer.alloc(0);
client.connect(8899, "localhost");
client.on("data", function (data) {
// 这里只是合并data
receiveData = Buffer.concat([receiveData, data]);
});
client.on("error", function (e) {
console.error(e)
});
client.on("end", function (e) {
// 接收完所有data再处理
console.log(receiveData.toString());
});
以上是 nodejs如何实现简单的文件服务器 的全部内容, 来源链接: utcz.com/z/514338.html