Android TCP 文件客戶端與服務(wù)器DEMO介紹
主要功能是:
1、TCP服務(wù)器提供文件下載服務(wù),服務(wù)器支持多線程。
2、TCP Client從服務(wù)器上下載指定的文件,Client也支持多線程。
首先是服務(wù)器,服務(wù)器是在PC機(jī)上,JAVA運(yùn)行環(huán)境,主要參考網(wǎng)上的代碼,自己做了支持多線程處理,代碼如下:
//file:DownloadServer.java
import java.net.*;
import java.io.*;
class ServerOneDownload extends Thread {
private Socket socket = null;
private String downloadRoot = null;
private static final int Buffer = 8 * 1024;
public ServerOneDownload(Socket socket, String downloadRoot) {
super();
this.socket = socket;
this.downloadRoot = downloadRoot;
start();
}
// 檢查文件是否真實(shí)存在,核對(duì)下載密碼,若文件不存在或密碼錯(cuò)誤,則返回-1,否則返回文件長(zhǎng)度
// 此處只要密碼不為空就認(rèn)為是正確的
private long getFileLength(String fileName, String password) {
// 若文件名或密碼為null,則返回-1
if ((fileName == null) || (password == null))
return -1;
// 若文件名或密碼長(zhǎng)度為0,則返回-1
if ((fileName.length() == 0) || (password.length() == 0))
return -1;
String filePath = downloadRoot + fileName; // 生成完整文件路徑
System.out.println("DownloadServer getFileLength----->" + filePath);
File file = new File(filePath);
// 若文件不存在,則返回-1
if (!file.exists())
return -1;
return file.length(); // 返回文件長(zhǎng)度
}
// 用指定輸出流發(fā)送指定文件
private void sendFile(DataOutputStream out, String fileName)
throws Exception {
String filePath = downloadRoot + fileName; // 生成完整文件路徑
// 創(chuàng)建與該文件關(guān)聯(lián)的文件輸入流
FileInputStream in = new FileInputStream(filePath);
System.out.println("DownloadServer sendFile----->" + filePath);
byte[] buf = new byte[Buffer];
int len;
// 反復(fù)讀取該文件中的內(nèi)容,直到讀到的長(zhǎng)度為-1
while ((len = in.read(buf)) >= 0) {
out.write(buf, 0, len); // 將讀到的數(shù)據(jù),按讀到的長(zhǎng)度寫入輸出流
out.flush();
}
out.close();
in.close();
}
// 提供下載服務(wù)
public void download() throws IOException {
System.out.println("啟動(dòng)下載... ");
System.out.println("DownloadServer currentThread--->"
+ currentThread().getName());
System.out.println("DownloadServer currentThread--->"
+ currentThread().getId());
// 獲取socket的輸入流并包裝成BufferedReader
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// 獲取socket的輸出流并包裝成DataOutputStream
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
try {
String parameterString = in.readLine(); // 接收下載請(qǐng)求參數(shù)
// 下載請(qǐng)求參數(shù)字符串為自定義的格式,由下載文件相對(duì)于下載根目錄的路徑和
// 下載密碼組成,兩者間以字符 "@ "分隔,此處按 "@ "分割下載請(qǐng)求參數(shù)字符串
String[] parameter = parameterString.split("@ ");
String fileName = parameter[0]; // 獲取相對(duì)文件路徑
String password = parameter[1]; // 獲取下載密碼
// 打印請(qǐng)求下載相關(guān)信息
System.out.print(socket.getInetAddress().getHostAddress()
+ "提出下載請(qǐng)求, ");
System.out.println("請(qǐng)求下載文件: " + fileName);
// 檢查文件是否真實(shí)存在,核對(duì)下載密碼,獲取文件長(zhǎng)度
long len = getFileLength(fileName, password);
System.out.println("download fileName----->" + fileName);
System.out.println("download password----->" + password);
out.writeLong(len); // 向客戶端返回文件大小
out.flush();
// 若獲取的文件長(zhǎng)度大于等于0,則允許下載,否則拒絕下載
if (len >= 0) {
System.out.println("允許下載 ");
System.out.println("正在下載文件 " + fileName + "... ");
sendFile(out, fileName); // 向客戶端發(fā)送文件
System.out.println(fileName +": "+"下載完畢 ");
} else {
System.out.println("下載文件不存在或密碼錯(cuò)誤,拒絕下載! ");
}
} catch (Exception e) {
System.out.println(e.toString());
} finally {
socket.close(); // 關(guān)閉socket
}
}
@Override
public void run() {
try {
download();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
super.run();
}
}
public class DownloadServer {
private final static int port = 65525;
private static String root = "C:// "; // 下載根目錄
public static void main(String[] args) throws IOException {
String temp = null;
// 監(jiān)聽端口
try {
// 包裝標(biāo)準(zhǔn)輸入為BufferedReader
BufferedReader systemIn = new BufferedReader(new InputStreamReader(
System.in));
while (true) {
System.out.print("請(qǐng)輸入下載服務(wù)器的下載根目錄: ");
root = systemIn.readLine().trim(); // 從標(biāo)準(zhǔn)輸入讀取下載根目錄
File file = new File(root);
// 若該目錄確實(shí)存在且為目錄,則跳出循環(huán)
if ((file.exists()) && (file.isDirectory())) {
temp = root.substring(root.length() - 1, root.length());
if (!temp.equals("http://"))
root += "http://";
}
break;
}
} catch (Exception e) {
System.out.println(e.toString());
}
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Server start...");
try {
while (true) {
Socket socket = serverSocket.accept();
new ServerOneDownload(socket, root);
}
} finally {
serverSocket.close();
}
}
}
File Download Client
Client輸入IP和文件名即可直接從服務(wù)器上下載,還是看代碼。
//file:DownLoadClient.java
package org.piaozhiye.study;
import java.io.IOException;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class DownLoadClient extends Activity {
private Button download = null;
private EditText et_serverIP = null;
private EditText et_fileName= null;
private String downloadFile = null;
private final static int PORT = 65525;
private final static String defaultIP = "192.168.0.100";
private static String serverIP = null;
private Socket socket;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
download = (Button)findViewById(R.id.download);
et_serverIP= (EditText)findViewById(R.id.et_serverip);
et_fileName = (EditText)findViewById(R.id.et_filename);
et_serverIP.setText("192.168.0.100");
download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
serverIP = et_serverIP.getText().toString();
if(serverIP == null){
serverIP = defaultIP;
}
System.out.println("DownLoadClient serverIP--->" + serverIP );
System.out.println("DownLoadClient MainThread--->" + Thread.currentThread().getId() );
try{
socket = new Socket(serverIP, PORT);
}catch(IOException e){
}
downloadFile = et_fileName.getText().toString();
Thread downFileThread = new Thread(new DownFileThread(socket, downloadFile));
downFileThread.start();
System.out.println("DownLoadClient downloadFile--->" + downloadFile );
}
});
}
}
file:DownFileThread.java
package org.piaozhiye.study;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class DownFileThread extends Thread {
private Socket socket;
private String downloadFile;
private final static int Buffer = 8 * 1024;
public DownFileThread(Socket socket, String downloadFile) {
super();
this.socket = socket;
this.downloadFile = downloadFile;
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public String getDownloadFile() {
return downloadFile;
}
public void setDownloadFile(String downloadFile) {
this.downloadFile = downloadFile;
}
// 向服務(wù)器提出下載請(qǐng)求,返回下載文件的大小
private long request(String fileName, String password) throws IOException {
// 獲取socket的輸入流并包裝成DataInputStream
DataInputStream in = new DataInputStream(socket.getInputStream());
// 獲取socket的輸出流并包裝成PrintWriter
PrintWriter out = new PrintWriter(new OutputStreamWriter(
socket.getOutputStream()));
// 生成下載請(qǐng)求字符串
String requestString = fileName + "@ " + password;
out.println(requestString); // 發(fā)出下載請(qǐng)求
out.flush();
return in.readLong(); // 接收并返回下載文件長(zhǎng)度
}
// 接收并保存文件
private void receiveFile(String localFile) throws Exception {
// 獲取socket的輸入流并包裝成BufferedInputStream
BufferedInputStream in = new BufferedInputStream(
socket.getInputStream());
// 獲取與指定本地文件關(guān)聯(lián)的文件輸出流
FileOutputStream out = new FileOutputStream(localFile);
byte[] buf = new byte[Buffer];
int len;
// 反復(fù)讀取該文件中的內(nèi)容,直到讀到的長(zhǎng)度為-1
while ((len = in.read(buf)) >= 0) {
out.write(buf, 0, len); // 將讀到的數(shù)據(jù),按讀到的長(zhǎng)度寫入輸出流
out.flush();
}
out.close();
in.close();
}
// 從服務(wù)器下載文件
public void download(String downloadFile) throws Exception {
try {
String password = "password";
// String downloadFile ="imissyou.mp3";
String localpath = "/sdcard/";
String localFile = localpath + downloadFile;
long fileLength = request(downloadFile, password);
// 若獲取的文件長(zhǎng)度大于等于0,說明允許下載,否則說明拒絕下載
if (fileLength >= 0) {
System.out.println("fileLength: " + fileLength + " B");
System.out.println("downing...");
receiveFile(localFile); // 從服務(wù)器接收文件并保存至本地文件
System.out.println("file:" + downloadFile + " had save to "
+ localFile);
} else {
System.out.println("download " + downloadFile + " error! ");
}
} catch (IOException e) {
System.out.println(e.toString());
} finally {
socket.close(); // 關(guān)閉socket
}
}
@Override
public void run() {
System.out.println("DownFileThread currentThread--->"
+ DownFileThread.currentThread().getId());
// TODO Auto-generated method stub
try {
download(downloadFile);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.run();
}
}
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="服務(wù)器IP:"
/>
<EditText
android:id="@+id/et_serverip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="下載文件名:"
/>
<EditText
android:id="@+id/et_filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
/>
<Button
android:id="@+id/download"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="download"
/>
</LinearLayout>
同時(shí)別忘了權(quán)限:
<uses-permission android:name="android.permission.INTERNET" />
相關(guān)文章
Android自定義View實(shí)現(xiàn)水波紋擴(kuò)散效果
這篇文章主要為大家詳細(xì)介紹了Android如何通過自定義View實(shí)現(xiàn)水波紋擴(kuò)散效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-08-08Android判斷網(wǎng)絡(luò)狀態(tài)的代碼
這篇文章主要為大家詳細(xì)介紹了Android判斷網(wǎng)絡(luò)狀態(tài)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10kotlin Standard中的內(nèi)聯(lián)函數(shù)示例詳解
這篇文章主要給大家介紹了關(guān)于kotlin Standard中內(nèi)聯(lián)函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用kotlin具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Android 多媒體播放API簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android 多媒體播放API簡(jiǎn)單實(shí)例的相關(guān)資料,這里附有代碼實(shí)例及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-12-12Android EditText限制輸入字符的方法總結(jié)
這篇文章主要介紹了 Android EditText限制輸入字符的方法總結(jié)的相關(guān)資料,這里提供了五種方法來實(shí)現(xiàn)并進(jìn)行比較,需要的朋友可以參考下2017-07-07Android?APP啟動(dòng)時(shí)間優(yōu)化介紹
大家好,本篇文章主要講的是Android?APP啟動(dòng)時(shí)間優(yōu)化介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Android 創(chuàng)建依賴庫(kù)的方法(保姆級(jí)教程)
這篇文章主要介紹了Android 創(chuàng)建依賴庫(kù)的方法(保姆級(jí)教程),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Android的WebView與H5前端JS代碼交互的實(shí)例代碼
本篇文章主要介紹了Android的WebView與H5前端JS代碼交互的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-07-07