java文件的Socket傳輸是怎么傳輸呢?前段時(shí)間的項(xiàng)目中需要實(shí)現(xiàn)網(wǎng)絡(luò)硬盤的功能, 所以整理了Java的Socket文件傳輸, 方便以后重用!
大家都知道Java語(yǔ)言功能強(qiáng)大, 對(duì)網(wǎng)絡(luò)傳輸?shù)闹С指鼜?qiáng), Socket和多線程是程序員必備知識(shí).
為了方便項(xiàng)目布署, 服務(wù)器沒有使用FTP服務(wù)器, 全是由純Java所寫.
除了文件傳輸外, 自定義了傳輸協(xié)議, 即在同一個(gè)流中, 增加了文件的一些屬性.
服務(wù)器端核心代碼:
Java代碼
Thread fileThread = new Thread(){
public void run(){
try {
ServerSocket ss = new ServerSocket(port, maxConnected);
System.out.println("文件傳輸服務(wù)啟動(dòng)成功!");
while(true){
Socket socket = ss.accept();
Thread trFile = new TrFile(socket);
//trFile.setDaemon(true);
trFile.start();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
class TrFile extends Thread{
private Socket socket;
private String UPLOAD_TYPE = "/example"; // value = /gamesave or /webdisk
private String USER_DIR = "/example"; // value = /username
private String childFilename = null;
private String childFileaddr = null;
private String childGame = null;
private String childFiletype = null;
private String childUserid = null;
private String childFilesize = null;
public TrFile(Socket socket){
this.socket = socket;
}
public void run(){
try{
InputStream in =
socket.getInputStream();
PrintWriter out =
new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())),true);
while(true)
{
//第一個(gè)參數(shù)為命令
String cmds = getFileInfo(in, 128);
/*
if("exit".equals(cmds)){
System.exit(0);
} else */
if("cp".equals(cmds)){
//獲得用戶名
childUserid = getFileInfo(in, 30);
//獲得網(wǎng)吧硬盤目錄
childFiletype = getFileInfo(in, 128);
//獲得游戲
childGame = getFileInfo(in, 128);
//獲得文件名
childFilename = getFileInfo(in, 256);
//獲得文件大小
childFilesize = getFileInfo(in, 128);
//獲得其它屬性...
//做一些目錄的處理
USER_DIR = "/" + childUserid;
if (childGame.equals("")){
//網(wǎng)絡(luò)硬盤
USER_DIR += "/"+childFiletype;
UPLOAD_TYPE = "/webdisk";
}else{
//游戲存檔
USER_DIR = USER_DIR + "/" + childGame;
UPLOAD_TYPE = "/gamesave";
}
//在服務(wù)器創(chuàng)建目錄
File folder = new File(APP_CONTEXT+UPLOAD_ROOT+UPLOAD_TYPE+USER_DIR);
if (!folder.exists()){
folder.mkdirs();
}
File fileout = new File(folder, childFilename);
//如果文件已存在, 則在文件名尾追加(i)命名.
int fileEndIndex = 0;
while(fileout.exists()){
String[] newFileNames = FileUtil.splitFileNameHasDot(childFilename);
String newFileName = newFileNames[0] + "(" + (++fileEndIndex) + ")" + newFileNames[1];
fileout = new File(folder,newFileName);
}
if (fileEndIndex!=0){
String[] newFileNames = FileUtil.splitFileNameHasDot(childFilename);
childFilename = newFileNames[0] + "(" + fileEndIndex + ")" + newFileNames[1];
}
//創(chuàng)建新文件
fileout.createNewFile();
FileOutputStream fos = new FileOutputStream(fileout);
int ta = Integer.parseInt(childFilesize);
byte[] buf = new byte[1024*10];
//InputStream ins = socket.getInputStream();
while(true){
if(ta==0){
break;
}
int len = ta;
if(len>buf.length){
len = buf.length;
}
int rlen = in.read(buf, 0, len);
//int rlen = ins.read(buf, 0, len);
ta -= rlen;
if(rlen>0){
fos.write(buf,0,rlen);
fos.flush();
}
else{
break;
}
}
out.println("cp finish!");
fos.close();
System.out.println("服務(wù)器端已存儲(chǔ)文件: " + fileout.getPath());
childFileaddr = "/"+UPLOAD_ROOT+UPLOAD_TYPE+USER_DIR+"/"+childFilename;
if (childGame.equals("")){
WebdiskLog wl = new WebdiskLog();
wl.setUsername(childUserid);
wl.setFilename(childFileaddr);
wl.setFilesize(childFilesize);
wl.setUploadtime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new GregorianCalendar().getTime()));
new WebdiskLogDAO().add(wl, null);
System.out.println("服務(wù)器端已寫入webdisk上傳日志數(shù)據(jù)庫(kù): " + childFileaddr);
}else{
}
break;
}
else{
System.out.println("err command!");
out.println("err command!");
break;
}
}
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
String getFileInfo(InputStream in, int len){
String result = null;
try{
byte cmd[] = new byte[len];
int b = 0;
while(b<cmd.length){
b += in.read(cmd, b, cmd.length-b);
}
int ends = 0;
for(int i=0;i<cmd.length;i++){
if(cmd==0x00000000){
ends = i;
break;
}
}
result = new String(cmd,0,ends);
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
}
};
fileThread.setDaemon(true);
fileThread.start();
客戶端核心代碼:
Java代碼
Thread uploadThread = new Thread(){
final String localPath = newItemTableItem.getText(0);
final String realFilename = newItemTableItem.getText(3);
final String uploadFolder = newItemTableItem.getText(2);
final TableItem childTi = newItemTableItem;
final TableEditor te = (TableEditor)childTi.getData();
final ProgressBar pb = (ProgressBar)te.getEditor();
public void run(){
try {
InetAddress addr = InetAddress.getByName(Config.getInstance().getProperty("inner_web_ip"));
Socket socket =
new Socket(addr, Integer.valueOf(Config.getInstance().getProperty("webdisk_savegame_port")).intValue());
OutputStream out = socket.getOutputStream();
File filein = new File(localPath);
//發(fā)送命令
sendFileInfo(out, 128, "cp");
//發(fā)送用戶名
sendFileInfo(out, 30, AppManager.user.getUsername());
//發(fā)送網(wǎng)吧硬盤目錄
sendFileInfo(out, 128, uploadFolder);
//發(fā)送游戲
sendFileInfo(out, 128, "");
//發(fā)送文件名
sendFileInfo(out, 256, realFilename);
//發(fā)送文件大小
sendFileInfo(out, 128, ""+filein.length());
//發(fā)送其它信息...
FileInputStream fis = null;
byte[] buf = new byte[1024*10];
//char[] bufC = new char[1024*10];
fis = new FileInputStream(filein);
int readsize = 0;
int countNum = 0;
//OutputStream ops = socket.getOutputStream();
while((readsize = fis.read(buf, 0, buf.length))>0){
out.write(buf,0,readsize);
out.flush();
countNum+=readsize;
final int progress = countNum;
Display.getDefault().asyncExec(new Runnable(){
public void run(){
//更新進(jìn)度
pb.setSelection(progress);
//pb.redraw();
}
});
}
out.close();
socket.close();
fis.close();
Display.getDefault().asyncExec(new Runnable(){
public void run(){
pb.setSelection(pb.getMaximum());
childTi.setImage(0, ImageManager.getInstance().getInterfaceImage(display, "udload_susseful.gif"));
getFileList(null, null, null, null, null);
}
});
} catch (Exception ex) {
ex.printStackTrace();
if (pb.getSelection()==pb.getMaximum()){
childTi.setImage(0, ImageManager.getInstance().getInterfaceImage(display, "udload_susseful.gif"));
}else{
childTi.setImage(0, ImageManager.getInstance().getInterfaceImage(display, "udload_failed.gif"));
}
}
}
void sendFileInfo(OutputStream out, int len, String content){
try{
byte[] cmd = new byte[len];
byte[] tcmd = content.getBytes();
for(int i=0;i<tcmd.length;i++){
cmd = tcmd;
}
cmd[tcmd.length] = 0x00000000;
out.write(cmd,0,cmd.length);
}catch(Exception ex){
ex.printStackTrace();
}
}
};
//uploadThread.setDaemon(true);
uploadThread.start();
這里要注意的是, 既然是自定義的傳輸協(xié)議, 在文件流之前傳輸?shù)淖止?jié)必須是事先定義好的, 例如: 客戶端向服務(wù)器發(fā)送了5個(gè)文件額外屬性, 標(biāo)識(shí)此文件信息, 則服務(wù)器讀取時(shí)要先將這5個(gè)屬性讀出來, 而且客戶端寫入時(shí)每個(gè)屬性的字節(jié)長(zhǎng)度必須和服務(wù)器讀取時(shí)使用的字節(jié)長(zhǎng)度相同, 否則便失敗了! 另外, 每個(gè)屬性之間的字節(jié)間隔我使用了16進(jìn)制的 0x00000000 來標(biāo)識(shí), 以便服務(wù)器端讀取時(shí)分隔.