Android应用连接SQL Server时因Conscrypt SSL栈触发AssertionError错误求助
兄弟,我太懂你这种头疼了——明明只是想整个简单的测试应用连SQL Server,都加了encrypt=false了,结果还被Conscrypt的SSL栈搞出个断言错误,太闹心了!先把你的测试代码和遇到的错误理清楚,再给你几个靠谱的解决办法:
你的测试连接代码
private void testDatabaseConnection(String ip, String port, String username, String password, String dbName) { new Thread(() -> { String connectionUrl = "jdbc:sqlserver://" + ip + ":" + port + ";" + "databaseName=" + dbName + ";" + "user=" + username + ";" + "password=" + password + ";" + "encrypt=false;" + "loginTimeout=10;"; Log.d(TAG, "Testing SQL Server connection with URL:"); Log.d(TAG, connectionUrl.replace(password, "******")); try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); Log.d(TAG, "✅ JDBC Driver class loaded."); // Log JDBC driver version java.sql.Driver driver = java.sql.DriverManager.getDriver(connectionUrl); Log.i(TAG, "Microsoft JDBC Driver version: " + driver.getMajorVersion() + "." + driver.getMinorVersion()); try (Connection connection = DriverManager.getConnection(connectionUrl)) { if (connection != null && !connection.isClosed()) { Log.i(TAG, "✅ SQL Server connection established successfully."); runOnUiThread(() -> Toast.makeText(this, "Connection successful!", Toast.LENGTH_LONG).show()); } else { Log.w(TAG, "⚠️ Connection object is null or closed."); runOnUiThread(() -> Toast.makeText(this, "Connection failed: unknown reason.", Toast.LENGTH_LONG).show()); } } } catch (ClassNotFoundException e) { Log.e(TAG, "❌ JDBC driver not found.", e); runOnUiThread(() -> Toast.makeText(this, "JDBC driver not found.", Toast.LENGTH_LONG).show()); } catch (SQLException e) { Log.e(TAG, "❌ SQL Server connection failed: " + e.getMessage(), e); runOnUiThread(() -> Toast.makeText(this, "Connection failed: " + e.getMessage(), Toast.LENGTH_LONG).show()); } catch (Exception e) { Log.e(TAG, "❌ Unexpected error during SQL connection test", e); runOnUiThread(() -> Toast.makeText(this, "Unexpected error: " + e.getMessage(), Toast.LENGTH_LONG).show()); } }).start(); }
你遇到的错误栈
FATAL EXCEPTION: main Process: com.k.blancia.dev.qmsandroid, PID: 31970 java.lang.AssertionError: numMsgsRcvd:1 should be less than numMsgsSent:1 at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:6303) at com.microsoft.sqlserver.jdbc.TDSReader.nextPacket(IOBuffer.java:6269) at com.microsoft.sqlserver.jdbc.TDSReader.ensurePayload(IOBuffer.java:6247) at com.microsoft.sqlserver.jdbc.TDSReader.readBytes(IOBuffer.java:6531) at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.readInternal(IOBuffer.java:833) at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.read(IOBuffer.java:821) at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.readInternal(IOBuffer.java:1003) at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.read(IOBuffer.java:991) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:945) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:909) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access$100(ConscryptEngineSocket.java:731) at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:241) at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:220) at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1753) at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:2022) at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:1687) at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1528) at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:866) at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:569) at java.sql.DriverManager.getConnection(DriverManager.java:580) at java.sql.DriverManager.getConnection(DriverManager.java:218) at com.k.blancia.dev.qmsandroid.SQLServerHandler.connectToDatabase(SQLServerHandler.java:24) at com.k.blancia.dev.qmsandroid.MainActivity.testSQLServerConnection(MainActivity.java:74) at com.k.blancia.dev.qmsandroid.MainActivity.lambda$onCreate$0$com-k-blancia-dev-qmsandroid-MainActivity(MainActivity.java:45) at com.k.blancia.dev.qmsandroid.MainActivity$$ExternalSyntheticLambda1.onClick(D8$$SyntheticClass:0) at android.view.View.performClick(View.java:7471) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218) at android.view.View.performClickInternal(View.java:7444)
问题原因&解决办法
这个问题的核心是:哪怕你设了encrypt=false,Microsoft JDBC Driver在某些场景下还是会触发SSL握手(比如SQL Server默认强制加密、驱动版本兼容问题),再加上Android的Conscrypt SSL栈和驱动的SSL处理逻辑冲突,就炸出了这个断言错误。给你几个亲测有效的解决方向:
方案1:补加
trustServerCertificate=true参数
有时候只关加密不够,驱动可能还是会做证书校验,加这个参数可以彻底跳过SSL相关的验证逻辑,修改你的连接URL:String connectionUrl = "jdbc:sqlserver://" + ip + ":" + port + ";" + "databaseName=" + dbName + ";" + "user=" + username + ";" + "password=" + password + ";" + "encrypt=false;" + "trustServerCertificate=true;" // 新增这个参数 + "loginTimeout=10;";方案2:调整JDBC Driver版本
你当前用的驱动版本可能和Android Conscrypt不兼容,试试换成mssql-jdbc 9.4.1.jre8这个稳定版本(选jre8分支,因为Android ART和高版本JRE语法有差异),或者升级到最新的兼容Android的驱动版本。方案3:指定使用Android原生SSL工厂
强制驱动用Android的原生SSL Socket工厂,避免Conscrypt的冲突,在连接URL里加:String connectionUrl = "jdbc:sqlserver://" + ip + ":" + port + ";" + "databaseName=" + dbName + ";" + "user=" + username + ";" + "password=" + password + ";" + "encrypt=false;" + "socketFactory=javax.net.ssl.SSLSocketFactory;" // 指定原生工厂 + "loginTimeout=10;";方案4:检查SQL Server配置
打开SQL Server配置管理器,找到你的实例的「网络配置」→「TCP/IP属性」→「标志」,确认「强制加密」设为「否」——如果服务器端强制加密,客户端设encrypt=false也没用,还是会触发SSL握手。
小提醒
别忘了在AndroidManifest.xml里加必要的网络权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
内容来源于stack exchange

