java文件的Socket傳輸是怎么傳輸呢?前段時間的項目中需要實現網絡硬盤的功能, 所以整理了Java的Socket文件傳輸, 方便以后重用!
大家都知道Java語言功能強大, 對網絡傳輸的支持更強, Socket和多線程是程序員必備知識.
為了方便項目布署, 服務器沒有使用FTP服務器, 全是由純Java所寫.
除了文件傳輸外, 自定義了傳輸協議, 即在同一個流中, 增加了文件的一些屬性.
服務器端核心代碼:
Java代碼
Thread fileThread = new Thread(){
public void run(){
try {
ServerSocket ss = new ServerSocket(port, maxConnected);
System.out.println("文件傳輸服務啟動成功!");
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)
{
//第一個參數為命令
String cmds = getFileInfo(in, 128);
/*
if("exit".equals(cmds)){
System.exit(0);
} else */
if("cp".equals(cmds)){
//獲得用戶名
childUserid = getFileInfo(in, 30);
//獲得網吧硬盤目錄
childFiletype = getFileInfo(in, 128);
//獲得游戲
childGame = getFileInfo(in, 128);
//獲得文件名
childFilename = getFileInfo(in, 256);
//獲得文件大小
childFilesize = getFileInfo(in, 128);
//獲得其它屬性...
//做一些目錄的處理
USER_DIR = "/" + childUserid;
if (childGame.equals("")){
//網絡硬盤
USER_DIR += "/"+childFiletype;
UPLOAD_TYPE = "/webdisk";
}else{
//游戲存檔
USER_DIR = USER_DIR + "/" + childGame;
UPLOAD_TYPE = "/gamesave";
}
//在服務器創建目錄
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];
}
//創建新文件
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("服務器端已存儲文件: " + 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("服務器端已寫入webdisk上傳日志數據庫: " + 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);
//發送命令
sendFileInfo(out, 128, "cp");
//發送用戶名
sendFileInfo(out, 30, AppManager.user.getUsername());
//發送網吧硬盤目錄
sendFileInfo(out, 128, uploadFolder);
//發送游戲
sendFileInfo(out, 128, "");
//發送文件名
sendFileInfo(out, 256, realFilename);
//發送文件大小
sendFileInfo(out, 128, ""+filein.length());
//發送其它信息...
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(){
//更新進度
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();
這里要注意的是, 既然是自定義的傳輸協議, 在文件流之前傳輸的字節必須是事先定義好的, 例如: 客戶端向服務器發送了5個文件額外屬性, 標識此文件信息, 則服務器讀取時要先將這5個屬性讀出來, 而且客戶端寫入時每個屬性的字節長度必須和服務器讀取時使用的字節長度相同, 否則便失敗了! 另外, 每個屬性之間的字節間隔我使用了16進制的 0x00000000 來標識, 以便服務器端讀取時分隔.