手机如何连接电脑?从零实现一个“局域网版手游服务器”
引言:为什么要手机连电脑?(分享踩过的坑:MySQL远程授权、防火墙、Android明文流量)由于之前想着开发手机软件,思考了一些连接的问题之后,便尝试用手机连接电脑。想法:Android里用mysql-connector-java,像Java后端一样连接数据库。遇到的阻碍:1.公钥检索错误:MySQL8.0要求allowPublickeyRetrieval=true,加了又报超时。2.网络超时:
引言:为什么要手机连电脑?(分享踩过的坑:MySQL远程授权、防火墙、Android明文流量)
由于之前想着开发手机软件,思考了一些连接的问题之后,便尝试用手机连接电脑。
目录
2.网页的数据传输,就用电脑作为服务器,使用了Node.js+HTTP APL(成功)
1.用JDBC+MySQL(失败)
想法:Android里用mysql-connector-java,像Java后端一样连接数据库。
遇到的阻碍:
1.公钥检索错误:MySQL8.0要求allowPublickeyRetrieval=true,加了又报超时。
2.网络超时:手机和电脑连接的是同一个WiFi,却连接不到3306(数据库端口)。
我关掉了Windows防火墙->还是超时。
当然应该关掉路由器的"AP隔离"(不清楚,不是自家路由)。
使用热点->还是超时(热点也许有AP隔离,实际上确实有隔离)。
用电脑telnet自己的3306是通的???,手机telnet电脑IP不通,意识到需要添加些代码,来输出 错误原因。
3.Android驱动缺失:
NoClassDefFoundError:Failed resolution of: Lcom/mysql/cj/MysqlType-就算加了依赖,Android的dex也也会因为java版本冲突而失效。
4.明文流量禁令:Android 9+默认禁止HTTP明文,需要usesCleartextTraffic="true",解决了,依然没用。
结论:JDBC 直连 MySQL 在局域网环境下几乎不可行。主要原因包括:驱动体积过大、Android 兼容性问题突出、以及网络层面的限制——无论是路由器还是手机热点,大多默认开启了客户端隔离,且没有提供关闭选项。
5.显示的错误信息

2.使用 Node.js + HTTP API(客户端-服务器架构)(成功,手机热点,无线wifi都成功,这套架构之所以在手机热点和普通 WiFi 下都能成功,是因为它不依赖设备之间的直接 TCP 连接,从而绕开了热点或路由器可能开启的客户端隔离限制)
实施步骤:
-
写一个
server.js,连接本地 MySQL,暴露/data接口。 -
电脑运行
node server.js,监听 3000 端口。 -
手机端用
http://电脑IP:3000/data发送 GET 请求,解析 JSON 展示。
遇到的阻碍及解决:
-
Node.js 模块缺失:
Cannot find module 'mysql2'→ 执行npm install express mysql2。 -
防火墙挡路:“原本担心防火墙会拦截 3000 端口,但检查发现 Windows 防火墙已经自动为 Node.js 创建了入站规则,因此手机可以顺利访问(很久前运行类似
node server.js的命令,让防火墙放权)。”。 -
手机访问不了 IP:发现电脑 IP 变了(动态 IP)→ 给电脑设置静态 IP,或在 App 里加个 IP 输入框。
-
明文流量又被拦:记得在
AndroidManifest.xml加android:usesCleartextTraffic="true"。
最终结果:手机浏览器直接访问 http://192.168.1.105:3000/data 能看到 JSON 数据,App 里也能正常显示。
执行步骤如下:
node init 产生package.json文件,node install express mysql,生成package-lock.json文件和node_modules文件夹,创建server.js文件为后端文件,
server.js文件代码如下:
const express = require('express');
const mysql = require('mysql2');
const app = express();
const db = mysql.createConnection({
host: 'localhost',
user: 'user,
password: 'password',
database: 'serial_data'
});
db.connect();
app.get('/data', (req, res) => {
db.query('SELECT id, port_name, raw_text, temperature, humidity, light_intensity, receive_time FROM serial_receive_data ORDER BY id DESC LIMIT 20',
(err, results) => {
if (err) {
res.status(500).json({ error: err.message });
} else {
res.json(results);
}
});
});
app.listen(3000, () => {
console.log('API server running on http://0.0.0.0:3000');
});
node server.js运行后端。
手机上运行用Android Studio编写的程序。
主要文件为MainActivity.java(主程序文件),build.gradle(项目配置文件),AndroidManifest.xml(项目配置文件)。
MainActivity.java代码如下:
package com.example.serialdataviewer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler = new Handler(Looper.getMainLooper());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
textView.setText("正在加载数据...");
textView.setTextSize(16);
textView.setPadding(50, 50, 50, 50);
setContentView(textView);
new Thread(this::fetchData).start();
}
private void fetchData() {
HttpURLConnection conn = null;
try {
String ip = "192.168.40.82"; // 你的电脑 IP
URL url = new URL("http://" + ip + ":3000/data");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
InputStream is = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) sb.append(line);
reader.close();
String json = sb.toString();
// 解析 JSON
JSONArray array = new JSONArray(json);
StringBuilder display = new StringBuilder();
display.append("===== 串口数据记录 =====\n\n");
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
display.append("ID: ").append(obj.getInt("id")).append("\n");
display.append("串口: ").append(obj.getString("port_name")).append("\n");
display.append("数据: ").append(obj.getString("raw_text")).append("\n");
display.append("温度: ").append(obj.optDouble("temperature")).append("°C\n");
display.append("湿度: ").append(obj.optDouble("humidity")).append("%\n");
display.append("光照: ").append(obj.optDouble("light_intensity")).append("\n");
display.append("时间: ").append(obj.getString("receive_time")).append("\n");
display.append("----------------------\n");
}
final String result = display.toString();
handler.post(() -> textView.setText(result));
} else {
handler.post(() -> textView.setText("HTTP 错误: " + responseCode));
}
} catch (Exception e) {
final String errMsg = "请求失败: " + e.getMessage();
handler.post(() -> textView.setText(errMsg));
e.printStackTrace();
} finally {
if (conn != null) conn.disconnect();
}
}
}
AndroidManifest.xml的application标签里添加android:usesCleartextTraffic="true",并且在 <manifest> 标签下添加
<uses-permission android:name="android.permission.INTERNET" />
3.运行结果展示:

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)