用socket自定義簡單協議實現檔案上傳與接受
阿新 • • 發佈:2019-01-05
一個上傳的資料包,主要包含檔案頭和檔案內容倆部分,主要按下面的格式,傳送:
"File-Name:xxxxxx.zip;File-Type:exe;File-Length:1029292\r\n"
------檔案內容---------
1、服務端的檔案接受服務 MySockerServer
package com.my.socket.server; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.my.socket.constant.MyServerConstant; import com.my.socket.util.StreamUtil; public final class MySockerServer { private ServerSocket myServerSocket = null; private File savedir = null; public static void main(String[] args) { new MySockerServer().start(); } private void start() { this.savedir = new File(MyServerConstant.SAVE_DIRECTORY); if (!savedir.exists()) savedir.mkdir(); try { this.myServerSocket = new ServerSocket(MyServerConstant.PORT, 50); while (true) { Socket mySocket = myServerSocket.accept(); ExecutorService executorService = Executors .newFixedThreadPool(8); executorService.execute(new ServerHander(mySocket, savedir)); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("啟動檔案接受服務出錯!", e); } finally { if (this.myServerSocket != null) { try { this.myServerSocket.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("檔案接受服務關閉出錯!", e); } } } } private final class ServerHander implements Runnable { private Socket mySocket = null; private File saveFileDirectory = null; public ServerHander(Socket mySocket, File saveFileDirectory) { super(); this.mySocket = mySocket; this.saveFileDirectory = saveFileDirectory; } @Override public void run() { try { InputStream in = mySocket.getInputStream(); byte[] headData = StreamUtil.readHead(in); Map<String, String> headParamter = this.pareHeader(new String( headData, MyServerConstant.UTF_8)); File saveFile = new File(this.saveFileDirectory, headParamter.get(MyServerConstant.FILE_NAME)); if (!saveFile.exists()) saveFile.createNewFile(); OutputStream fos = new FileOutputStream(saveFile); byte[] buffer = new byte[1024]; int len = 0; while ((len = in.read(buffer, 0, 1024)) != -1) { fos.write(buffer, 0, len); } fos.flush(); fos.close(); if (mySocket != null) mySocket.close(); } catch (IOException e) { e.printStackTrace(); } } private Map<String, String> pareHeader(String param) { Map<String, String> headParamter = new HashMap<String, String>(); if (param == null || "".endsWith(param)) throw new RuntimeException("上傳的包格式錯誤的!"); String[] params = param.split(";"); for (String s : params) { String[] entry = s.split(":"); headParamter.put(entry[0], entry[1]); } return headParamter; } } }
2、服務端的輔助類StreamUtil,用於讀取檔案頭資訊,在出現"\r\n"後,認為是頭資訊結束位置。
package com.my.socket.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; public final class StreamUtil { private StreamUtil() { } public static byte[] readHead(InputStream in) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); char c; StringBuffer sb = new StringBuffer(); try { while ((c = (char) in.read()) != -1) { if (c == '\r') { sb.append(c); continue; } if (c == '\n') { if (sb.charAt(0) == '\r') break; else { byteArrayOutputStream.write(sb.charAt(0)); byteArrayOutputStream.write(c); sb.delete(0, sb.length()); } } byteArrayOutputStream.write(c); } } catch (IOException e) { e.printStackTrace(); } return byteArrayOutputStream.toByteArray(); } }
3、服務端啟動的引數設定類MyServerConstant:
package com.my.socket.constant; public final class MyServerConstant { public final static String UTF_8 = "UTF-8"; public final static String FILE_NAME = "File-Name"; public final static int PORT = 10243; public final static String SAVE_DIRECTORY = "C:\\save"; }
4、客戶端的實現主要是啟動倆個執行緒來完成,當連線到伺服器後,啟動一執行緒用於組裝資料包並負責傳送,
另一執行緒負責監聽傳送任務是否完成,當發現傳送任務完成立即退出並關閉連線。
5、客戶端類 MySockerClient
package com.my.socket.client;
import java.io.File;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.my.socket.constant.MyClientConstant;
public final class MySockerClient {
private static boolean finish = false;
public static boolean isFinish() {
return finish;
}
public static void setFinish(boolean finish) {
MySockerClient.finish = finish;
}
public static void main(String[] args) {
try {
Socket mySocket = new Socket(
InetAddress.getByName(MyClientConstant.HOST_URL),
MyClientConstant.HOST_PORT);
File sendFile = new File(MyClientConstant.SEND_FILE);
if (!sendFile.exists())
throw new RuntimeException("傳送的檔案不存在,請檢查輸入的路徑");
else {
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new SendFileHander(mySocket, sendFile));
service.execute(new SendFinishListenerHander(mySocket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
6、負責傳送的執行緒 SendFileHander
package com.my.socket.client;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import com.my.socket.constant.MyClientConstant;
public class SendFileHander implements Runnable {
private Socket mySocket = null;
private File sendFile = null;
public SendFileHander(Socket mySocket, File sendFile) {
this.mySocket = mySocket;
this.sendFile = sendFile;
}
@Override
public void run() {
FileInputStream fos = null;
try {
fos = new FileInputStream(this.sendFile);
byte[] buffer = new byte[1024];
int len = 0;
OutputStream outputStream = mySocket.getOutputStream();
Map<String, String> headParamter = new HashMap<String, String>();
headParamter.put(MyClientConstant.FILE_NAME,
this.sendFile.getName());
outputStream.write(this.getHeadBytes(headParamter).getBytes(
MyClientConstant.UTF_8));
while ((len = fos.read(buffer, 0, 1024)) != -1) {
outputStream.write(buffer, 0, len);
}
outputStream.flush();
MySockerClient.setFinish(true);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getHeadBytes(Map<String, String> headParamter) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : headParamter.entrySet())
sb.append(entry.getKey() + ":" + entry.getValue() + ";");
sb.append("\r\n");
return sb.toString();
}
}
7、負責監聽的執行緒 SendFinishListenerHander
package com.my.socket.client;
import java.io.IOException;
import java.net.Socket;
public class SendFinishListenerHander implements Runnable {
private Socket mySocket = null;
public SendFinishListenerHander(Socket mySocket) {
super();
this.mySocket = mySocket;
}
@Override
public void run() {
while (true) {
if (MySockerClient.isFinish()) {
if (mySocket != null)
try {
mySocket.close();
} catch (IOException e) {
e.printStackTrace();
}
MySockerClient.setFinish(false);
break;
}
}
}
}
8、啟動客服端的配置資訊類 MyClientConstant
package com.my.socket.constant;
public final class MyClientConstant {
public final static String SEND_FILE = "C:\\jboss-4.2.3.GA-jdk6.zip";
public final static String HOST_URL = "192.168.2.92";
public final static int HOST_PORT = 10243;
public static final String UTF_8 = "UTF-8";
public static final String FILE_NAME = "File-Name";
public static final String FILE_TYPE = "File-Type";
public static final String FILE_LENGTH = "File-Length";
}