首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

TCP 圖片上傳實現:Java Socket 文件傳輸與多線程併發

     編輯:C++ 入門

基本流程

客戶端讀取文件 → 輸出流發送 → 關閉輸出流通知結束 → 讀取服務端回應。服務端接受連接 → 輸入流寫入文件 → 返回成功信息。

單線程版核心代碼

// Client
Socket s = new Socket("10.152.79.174", 1004);
FileInputStream fis = new FileInputStream("d:\\015.jpg");
OutputStream os = s.getOutputStream();
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) os.write(buf, 0, len);
s.shutdownOutput(); // 關鍵:告知服務端發送完畢
InputStream in = s.getInputStream();
len = in.read(buf);
System.out.println(new String(buf, 0, len));
fis.close(); s.close();

// Server
ServerSocket ss = new ServerSocket(1004);
Socket s = ss.accept();
InputStream is = s.getInputStream();
FileOutputStream fos = new FileOutputStream("d:\\pic\\" + s.getInetAddress().getHostName() + ".jpg");
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1) fos.write(buf, 0, len);
s.getOutputStream().write("上傳成功!".getBytes());
fos.close(); s.close(); ss.close();

多線程併發版

// Server 主循環
ServerSocket ss = new ServerSocket(10006);
while (true) {
    Socket s = ss.accept();
    new Thread(new UploadTask(s)).start();
}

// UploadTask.run()
public void run() {
    String ip = s.getInetAddress().getHostAddress();
    File dir = new File("c:\\pic"); if (!dir.exists()) dir.mkdirs();
    File file = new File(dir, ip + ".jpg");
    int cnt = 0;
    while (file.exists()) file = new File(dir, ip + "(" + (++cnt) + ").jpg"); // 避免覆蓋
    FileOutputStream fos = new FileOutputStream(file);
    InputStream in = s.getInputStream();
    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) != -1) {
        fos.write(buf, 0, len);
        if (file.length() > 2*1024*1024) { // 限制 2MB
            fos.close(); s.close(); file.delete(); return;
        }
    }
    s.getOutputStream().write("上傳成功".getBytes());
    fos.close(); s.close();
}

關鍵點總結

  • shutdownOutput() 發送 FIN 包,讓服務端 read() 返回 -1,否則服務端會阻塞等待更多數據。
  • 多線程隔離客戶端,避免單線程阻塞。
  • 文件名衝突處理、大小限制、異常捕獲是生產級代碼必備。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved