目录
3.3 Android 使用 SSLSocket 实现文件上传工具类(2017年)
一、Socket、HTTP和HTTPS介绍
Socket、HTTP和HTTPS是网络通信中常用的三个概念,它们在使用上存在显著的区别。以下是对这三者使用区别的详细阐述:
1.1 Socket
-
定义与功能:
- Socket,即套接字,是一种网络通信的编程接口,它提供了一套函数和方法,使得应用程序能够通过网络发送和接收数据。
- Socket可以在不同的传输层协议上运行,如TCP或UDP,其中TCP Socket提供面向连接的可靠的数据传输。
-
使用场景:
- Socket通常用于需要实现底层网络通信的应用程序,如聊天应用、实时通信应用等。
- 它允许开发者直接控制网络通信的细节,如连接的建立、数据的发送和接收等。
-
通信方式:
- Socket通信是双向的,一旦连接建立,双方可以互相发送和接收数据。
- Socket连接通常是长连接,即连接建立后可以持续进行数据传输,直到一方主动断开连接。
1.2 HTTP
-
定义与功能:
- HTTP(超文本传输协议)是一种用于在Web浏览器和Web服务器之间传输数据的协议。
- 它使用TCP作为传输协议,通过请求-响应模式进行通信。
-
使用场景:
- HTTP通常用于Web开发中,客户端(如浏览器)发送HTTP请求到服务器,服务器处理请求并返回HTTP响应。
- 它适用于传输超文本(如HTML文档、图像、链接等)和其他类型的数据。
-
通信方式:
- HTTP通信是短连接或持久连接(Keep-Alive)。短连接意味着每个请求-响应都会建立一个新的连接;而持久连接则允许在同一个连接上发送多个请求。
- HTTP请求和响应都包含头部信息和主体数据,其中头部信息包含了请求的元数据(如方法、URL、请求头等),而主体数据则包含了实际要传输的数据(如表单数据、JSON数据等)。
-
端口:
- HTTP通信通常使用80端口。
1.3 HTTPS
-
定义与功能:
- HTTPS(安全超文本传输协议)是在HTTP基础上加入了安全性的协议。
- 它使用SSL(安全套接层)或TLS(传输层安全)协议对通信进行加密和身份验证,以保护数据的安全性。
-
使用场景:
- HTTPS通常用于需要保护用户隐私和敏感数据的网站,如电子商务、在线银行、社交媒体等。
- 它通过加密传输的数据和验证服务器的身份来确保数据传输的安全性和完整性。
-
通信方式:
- HTTPS通信使用加密的TCP连接进行数据传输,确保了数据的机密性和完整性。
- HTTPS请求和响应的格式与HTTP相同,但数据在传输过程中被加密。
-
端口:
- HTTPS通信通常使用443端口。
-
安全性:
- HTTPS通过SSL/TLS协议层实现了数据的加密和身份验证,确保了数据传输的安全性和完整性。
- HTTPS使用数字证书来验证服务器的身份,数字证书由可信的第三方机构(称为证书颁发机构,CA)签发。
二、Socket 中HTTP与HTTPS的区别总结
Socket 中 HTTP 和 HTTPS 的使用区别主要体现在加密、安全性和默认
-
加密传输:
- HTTP (HyperText Transfer Protocol):HTTP
- HTTPS (HTTP Secure):HTTPS 则是在 HTTP 基础上加入了 SSL/TLS 加密层,确保数据传输的安全性和隐私性。HTTPS 通过加密确保传输的数据只有接收端才能解密,因此更加安全。
-
握手流程:
- HTTP:建立 TCP 连接后,客户端和服务器直接开始数据通信。
- HTTPS:建立 TCP 连接后,还需要进行 SSL/TLS 握手,以协商加密算法、生成对称密钥等步骤。握手成功后,通信内容才会被加密。
-
默认端口:
- HTTP:默认使用 80 端口。
- HTTPS:默认使用 443 端口。
-
证书验证:
- HTTP:不涉及证书。
- HTTPS:在握手过程中,服务器会将数字证书发送给客户端,客户端验证证书的合法性以确保通信方的身份可靠。
在使用 Socket 进行 HTTPS 通信时,通常需要借助一些 SSL 库(如 OpenSSL),因为需要在普通 Socket 连接上加入加密层的支持。
三、在 Android 中使用 Socket 通信
在 Android 中使用 Socket 通信可以实现客户端和服务器之间的网络通信。
3.1 基本的 Socket 客户端示例
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.InetSocketAddress;
public class SocketClientThread extends Thread {
private static final String SERVER_IP = "192.168.1.1"; // 服务器 IP
private static final int SERVER_PORT = 12345; // 服务器端口号
private Socket socket;
@Override
public void run() {
try {
// 建立连接
socket = new Socket();
socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), 5000); // 超时时间5秒
// 发送消息到服务器
OutputStream outputStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(outputStream, true);
writer.println("Hello from Android!");
// 接收服务器消息
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = reader.readLine();
System.out.println("Server response: " + response);
// 关闭连接
writer.close();
reader.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2 在主线程启动 Socket 通信
SocketClientThread socketClientThread = new SocketClientThread();
socketClientThread.start();
3.3 Android 使用 SSLSocket 实现文件上传工具类(2017年)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import com.rl.mobile.entity.FormFile;
import android.text.format.DateFormat;
/**
* 上传文件到服务器的工具类,使用 HTTPS 的 Socket 连接
*
* @author Administrator
*
*/
public class SocketHttpRequester {
/**
* 使用 SSLSocketFactory 发送 HTTP POST 请求并上传文件
*
* @param path 上传路径
* @param params 请求参数(键值对)
* @param files 要上传的文件数组
* @return 上传成功返回 true,否则返回 false
* @throws Exception
*/
public static boolean postSSLSocketFactory(String path, Map<String, String> params, FormFile[] files) throws Exception {
String BOUNDARY = "---------------------------7da2137580612"; // 请求头和上传文件内容的分隔符
final String endline = "--" + BOUNDARY + "--\r\n"; // 数据结束标志
// 计算文件数据的总长度
int fileDataLength = 0;
String name = DateFormat.format("yyyyMMddhhmmss", Calendar.getInstance(Locale.CHINA)) + "";
for (FormFile uploadFile : files) {
StringBuilder fileExplain = new StringBuilder();
fileExplain.append("--");
fileExplain.append(BOUNDARY);
fileExplain.append("\r\n");
name = DateFormat.format("yyyyMMddhhmmss", Calendar.getInstance(Locale.CHINA)) + "." + getExtensionName(uploadFile.getFilname());
fileExplain.append("Content-Disposition: form-data; name=\"" + uploadFile.getParameterName() + "\"; filename=\"" + name + "\"\r\n");
fileExplain.append("Content-Type: " + uploadFile.getContentType() + "\r\n\r\n");
fileDataLength += fileExplain.length();
if (uploadFile.getInStream() != null) {
fileDataLength += uploadFile.getFile().length();
} else {
fileDataLength += uploadFile.getData().length;
}
}
// 构造文本类型参数的实体数据
StringBuilder textEntity = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
textEntity.append("--");
textEntity.append(BOUNDARY);
textEntity.append("\r\n");
textEntity.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");
textEntity.append(URLEncoder.encode(MStringUtils.getSpecial(entry.getValue()), "UTF-8"));
textEntity.append("\r\n");
}
// 计算数据总长度
int dataLength = textEntity.toString().getBytes().length + fileDataLength + endline.getBytes().length;
// 建立 SSL 连接
URL url = new URL(path);
int port = 443;
Socket socket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(InetAddress.getByName(url.getHost()), port);
OutputStream outStream = socket.getOutputStream();
// 发送 HTTP 请求头
String requestMethod = "POST " + url.getPath() + " HTTP/1.1\r\n";
outStream.write(requestMethod.getBytes());
outStream.write(("Accept: */*\r\n").getBytes());
outStream.write(("Accept-Language: zh-CN\r\n").getBytes());
outStream.write(("Content-Type: multipart/form-data; boundary=" + BOUNDARY + "\r\n").getBytes());
outStream.write(("Content-Length: " + dataLength + "\r\n").getBytes());
outStream.write(("Connection: Keep-Alive\r\n").getBytes());
outStream.write(("Host: " + url.getHost() + ":" + port + "\r\n").getBytes());
outStream.write("\r\n".getBytes());
// 发送文本类型的实体数据
outStream.write(textEntity.toString().getBytes());
// 发送文件类型的实体数据
for (FormFile uploadFile : files) {
StringBuilder fileEntity = new StringBuilder();
fileEntity.append("--");
fileEntity.append(BOUNDARY);
fileEntity.append("\r\n");
fileEntity.append("Content-Disposition: form-data; name=\"" + uploadFile.getParameterName() + "\"; filename=\"" + name + "\"\r\n");
fileEntity.append("Content-Type: " + uploadFile.getContentType() + "\r\n\r\n");
outStream.write(fileEntity.toString().getBytes());
if (uploadFile.getInStream() != null) {
byte[] buffer = new byte[1024];
int len;
while ((len = uploadFile.getInStream().read(buffer, 0, 1024)) != -1) {
outStream.write(buffer, 0, len);
}
uploadFile.getInStream().close();
} else {
outStream.write(uploadFile.getData(), 0, uploadFile.getData().length);
}
outStream.write("\r\n".getBytes());
}
// 发送数据结束标志
outStream.write(endline.getBytes());
// 读取服务器返回数据
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
boolean isSuccess = reader.readLine().contains("200"); // 请求成功则返回 200
outStream.flush();
outStream.close();
reader.close();
socket.close();
return isSuccess;
}
/**
* 获取文件扩展名
*
* @param filename 文件名
* @return 文件扩展名
*/
public static String getExtensionName(String filename) {
if (filename != null && filename.length() > 0) {
int dot = filename.lastIndexOf('.');
if (dot > -1 && dot < (filename.length() - 1)) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* 上传单个文件
*
* @param path 上传路径
* @param params 请求参数
* @param file 上传的文件
* @return 成功返回 true,否则返回 false
* @throws Exception
*/
public static boolean post(String path, Map<String, String> params, FormFile file) throws Exception {
return postSSLSocketFactory(path, params, new FormFile[]{file});
}
}
注释:
- postSSLSocketFactory 方法:使用
SSLSocket
发送 HTTPS POST 请求,将文本参数和文件数据以multipart/form-data
格式发送到服务器。- getExtensionName 方法:获取文件的扩展名,用于为上传的文件命名。
- post 方法:用于上传单个文件,调用
postSSLSocketFactory
进行 HTTPS 请求。
相关推荐
TCP三次握手四次挥手(三国版)-CSDN博客文章浏览阅读6.9k次,点赞33次,收藏95次。TCP的三次握手和四次挥手是网络通信的基础。三次握手确保建立可靠的连接,四次挥手则确保双方都能正确关闭连接。文章详细解释了每个步骤,并通过三国演义的例子辅助理解。同时,提到了SYN洪水攻击和TCP的保活计时器机制。https://shuaici.blog.csdn.net/article/details/121560065adb 常用命令汇总-CSDN博客文章浏览阅读1.7w次,点赞37次,收藏178次。Android Debug Bridge (ADB) 是一个多功能命令行工具,它允许你与连接的Android设备进行通信。ADB主要用于调试和与设备进行各种交互,如安装和调试应用、访问设备的shell、复制文件等。它包含在Android SDK中,并且是Android开发者的重要工具之一。_adb命令https://shuaici.blog.csdn.net/article/details/135509740