Moto G5 Plus无法通过Socket连接到本地服务器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Moto G5 Plus无法通过Socket连接到本地服务器相关的知识,希望对你有一定的参考价值。

我有一个应用程序,智能手机必须通过SSLSocket连接到本地服务器。我在5款不同的智能手机上测试了我的应用程序:Moto G2(6.0),Redmi 3S(6.0.1),LG K5(6.0),Moto G5 Plus(7.1.1)和OnePlus 5(8.0)。 Moto G5 Plus是唯一一个能够解决这个问题的人。

这是导致问题行为的线。所有测试都在同一网络上完成。

socket = (SSLSocket) sslContext.getSocketFactory().createSocket(serverAddress, serverPort);

对于这种行为,Moto G5 Plus或android 7+是否存在任何已知问题?

编辑:一些更多的测试导致Android系统的想法试图强迫Socket通过移动网络连接时识别WiFi接口已连接,但没有互联网。有没有办法强制Socket使用WiFi而不是移动网络?

答案

免责声明:我没有测试这个,所以我真的不确定它是否有效。

Network类有一个bind(Socket)方法,也许你可以找到wifi网络然后绑定到你的套接字。从文档看来,这似乎是你需要的,它说:

/**
 * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
 * will be sent on this {@code Network}, irrespective of any process-wide network binding set by
 * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected.
 */

在绑定到网络之前,不应该连接Socket,因此我认为您应该使用socketFactory.createSocket()创建它并仅在绑定后连接它。

所以,你应该首先找到你的Network(Kotlin):

val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val wifiNetwork = connectivityManager.allNetworks.firstOrNull {
    val info = connectivityManager.getNetworkInfo(it)
    info.type == ConnectivityManager.TYPE_WIFI
}

或(Java)

ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
Network wifiNetwork = null;
for(Network network : connectivityManager.getAllNetworks()){
    NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
    if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI){
        wifiNetwork = network;
        break;
    }
}

然后将它绑定到Socket并最终连接(Kotlin):

wifiNetwork?.bindSocket(socket)
val socketAddress = InetSocketAddress(hostname, port)
socket.connect(socketAddress)

或(Java)

if(wifiNetwork != null){
    wifiNetwork.bindSocket(socket);
}
InetSocketAddress socketAddress = InetSocketAddress(hostName, port);
socket.connect(socketAddress);

注意,它需要ACCESS_NETWORK_STATE权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
另一答案

我希望它可以帮助你,我刚刚在github上找到了你的解决方案。有关更多详细信息和官方链接,请check this out,我认为这对您有所帮助。如果不是答案,请忽略这个答案。

我们正在使用AsyncTask来避免网络访问的StrictMode致命错误(查看引用)。 StrictMode策略只是禁止我们影响UI线程。

   /* AsyncTask class which manages connection with server app and is sending shutdown command.
   */
public class ShutdownAsyncTask extends AsyncTask<String, String, TCPClient> {

    private static final String     COMMAND     = "shutdown -s"      ;
    private              TCPClient  tcpClient                        ;
    private              Handler    mHandler                         ;
    private static final String     TAG         = "ShutdownAsyncTask";

    /**
     * ShutdownAsyncTask constructor with handler passed as argument. The UI is updated via handler.
     * In doInBackground(...) method, the handler is passed to TCPClient object.
     * @param mHandler Handler object that is retrieved from MainActivity class and passed to TCPClient
     *                 class for sending messages and updating UI.
     */
    public ShutdownAsyncTask(Handler mHandler){
        this.mHandler = mHandler;
    }

    /**
     * Overriden method from AsyncTask class. There the TCPClient object is created.
     * @param params From MainActivity class empty string is passed.
     * @return TCPClient object for closing it in onPostExecute method.
     */
    @Override
    protected TCPClient doInBackground(String... params) {
        Log.d(TAG, "In do in background");

        try{
            tcpClient = new TCPClient(mHandler,
                                      COMMAND,
                                      "192.168.1.1",
                                      new TCPClient.MessageCallback() {
                @Override
                public void callbackMessageReceiver(String message) {
                    publishProgress(message);
                }
            });

        }catch (NullPointerException e){
            Log.d(TAG, "Caught null pointer exception");
            e.printStackTrace();
        }
        tcpClient.run();
        return null;
    }   

在这个AsyncTask中,我们创建了TCPClient对象(如下所述)。在TCPClient构造函数中,我们传递Handler对象以更改UI,COM​​MAND - 带有“shutdown -s”命令的String用于关闭计算机,IP号码 - 服务器ip号;回调对象 - 当我们得到服务器响应时,回调方法'messageCallbackReceiver'正在启动'publishProgress'方法,即将进度发布到'onProgressUpdate'AsyncTask的方法。

        /**
         * Overriden method from AsyncTask class. Here we're checking if server answered properly.
         * @param values If "restart" message came, the client is stopped and computer should be restarted.
         *               Otherwise "wrong" message is sent and 'Error' message is shown in UI.
         */
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            Log.d(TAG, "In progress update, values: " + values.toString());
            if(values[0].equals("shutdown")){
                tcpClient.sendMessage(COMMAND);
                tcpClient.stopClient();
                mHandler.sendEmptyMessageDelayed(MainActivity.SHUTDOWN, 2000);

            }else{
                tcpClient.sendMessage("wrong");
                mHandler.sendEmptyMessageDelayed(MainActivity.ERROR, 2000);
                tcpClient.stopClient();
            }
        }

收到正确的消息后,我们发送命令,或者如果收到错误的消息,我们发送消息“错误”并停止客户端。在此之后,我们将被转移到'onPostExecute'方法:

    @Override
        protected void onPostExecute(TCPClient result){
            super.onPostExecute(result);
            Log.d(TAG, "In on post execute");
            if(result != null && result.isRunning()){
                result.stopClient();
            }
            mHandler.sendEmptyMessageDelayed(MainActivity.SENT, 4000);

        }
    }

所以一步一步:

- > AsyncTask正在创建TCPClient对象。

- >在TCPClient构造函数中,我们传递Handler,Command,IP Number和Callback对象。

- >当TCPClient开始连接时,它会向服务器发送消息“shutdown”。

- >当我们从服务器接收消息时,回调将它传递给'onProgressUpdate'。

- >如果收到的消息(来自服务器的响应)等于“shutdown”,我们正在向服务器发送COMMAND。

- >发送后我们停止客户端,将我们转移到'onPostExecute'方法。

- >同时,处理程序正在接收带有MainActivity中定义的'msg.what'整数的空消息,它们负责更新GUI。

窗口小部件UI如何更新的示例:

       mHandler = new Handler(){
        public void handleMessage(Message msg) {
            switch(msg.what){
                case SHUTDOWN:
                    Log.d(mTag, "In Handler's shutdown");

                     views     = new RemoteViews(context.getPackageName(), R.layout.activity_main);
                     widget    = new ComponentName(context, MainActivity.class);
                     awManager = AppWidgetManager.getInstance(context);
                                 views.setTextViewText(R.id.state, "Shutting PC...");
                                 awManager.updateAppWidget(widget,views);
                    break;

TCPClient

该类负责维护连接。我会一步一步解释:

在第一步中,我们可以看到从ShutdownAsyncTask和其他人传递的对象。另外,我们可以看到sendMessage和stopClient方法。

    public class TCPClient {

        private static final String            TAG             = "TCPClient"     ;
        private final        Handler           mHandler                          ;
        private              String            ipNumber, incomingMessage, command;
                             BufferedReader    in                                ;
                             PrintWriter       out                               ;
        private              MessageCallback   listener        = null            ;
        private              boolean           mRun            = false           ;


        /**
         * TCPClient class constructor, which is created in AsyncTasks after the button click.
         * @param mHandler Handler passed as an argument for updating the UI with sent messages
         * @param command  Command passed as an argument, e.g. "shutdown -r" fo

以上是关于Moto G5 Plus无法通过Socket连接到本地服务器的主要内容,如果未能解决你的问题,请参考以下文章

带docker的Mysql:无法通过socket连接到本地MySQL服务器

无法通过套接字连接到本地 MySQL 服务器

无法通过 php 脚本连接到 xdebug(在 xampp for mac 上运行)

mac上怎么连接到socket

如何通过批处理文件连接到 SQL Plus 来运行 SQL 查询

无法通过套接字“/var/run/mysqld/mysqld.sock”连接到本地 MySQL 服务器。