代码改变世界

android中的socket使用报错NetworkOnMainThreadException

2019-04-12 11:55  雄风狂飙  阅读(788)  评论(0)    收藏  举报

1.先简单贴一下服务端代码:

package com.example.myfirstapp2.socketServer;

public class AndroidServer {

    public static void main(String args[])
    {
        SocketServerMain socketServerMain = SocketServerMain.getInstance();
        socketServerMain.server();
    }
}
package com.example.myfirstapp2.socketServer;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServerMain implements  Runnable{

    private  final int port = 8888;
    private static SocketServerMain mainHandle = null;
    private ServerSocket handle = null;
    private Socket socket = null;

    SocketServerMain()
    {
        handle =  getSocketServerInstance();
    }
    public static SocketServerMain getInstance()
    {
        if(  mainHandle == null )
        {
            mainHandle = new SocketServerMain();
        }
        return mainHandle;
    }

    private ServerSocket getSocketServerInstance()
    {
        if( null == handle )
        {
            try {
                InetAddress bindAddr = InetAddress.getByName("127.0.0.1");
                //InetAddress bindAddr = InetAddress.getByName("10.0.2.2");
                handle = new ServerSocket(port,10,bindAddr);
                //handle = new ServerSocket(port);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return handle;
    }

    private String readString(InputStream input){

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input));

        StringBuffer sb = new StringBuffer(2048);

        int i = 0;
        char[] buffer = new char[2048];
        try {
            i = bufferedReader.read(buffer);
        }
        catch (IOException e) {
            e.printStackTrace();
            i = -1;
        }

        for (int j=0; j < i; j++) {
            sb.append((char) buffer[j]);
        }
        return sb.toString();
    }

    public void server(){
        while(true) {
            try {
                System.out.println("server accept ...");
                socket = handle.accept();
                String input = readString(socket.getInputStream());
                System.out.println(input);

                PrintStream output = new PrintStream( socket.getOutputStream()) ;

                String outputString = "hello world!!";
                outputString.getBytes();
                output.write(outputString.getBytes(),0,outputString.getBytes().length);
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        SocketServerMain socketServerMain = SocketServerMain.getInstance();
        socketServerMain.server();
    }
}

2.客户端代码

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /*SocketServerMain socketServerMain = SocketServerMain.getInstance();
        Thread serverThread = new Thread(socketServerMain);
        serverThread.start();*/

        button1 = findViewById(R.id.feepolicy);

        Thread thread = new  Thread(){
            public void run(){
                button1.setOnClickListener(new SocketClientListener());
                //SocketClient socketClient = new SocketClient("10.0.2.2",8888);
                //socketClient.start();
            }
        };
        thread.start();
    }
package com.example.myfirstapp2.com.example.myfirstapp2.listener;

import android.view.View;

import com.example.myfirstapp2.SocketClient;
import com.example.myfirstapp2.socketServer.SocketServerMain;

public class SocketClientListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
        System.out.println("start socket ..。。。。。。。。。。。。。。。。。。。。。。。.");
        SocketClient socketClient = new SocketClient("10.0.2.2",8888);
        socketClient.request();
        //SocketClient socketClient = new SocketClient("10.0.2.2",8888);
        //socketClient.start();
    }
}
package com.example.myfirstapp2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class SocketClient implements Runnable {

    //private  String host = "10.0.2.2";
    private  String host = "127.0.0.1";
    private  int port = 8888;
    private Socket socket = null;
    private BufferedReader input = null;
    private PrintStream output = null;

    public SocketClient(String hostStr, int portInt)
    {
        if( hostStr != null && hostStr.length() != 0 )
            this.host = hostStr;
        if( portInt != 0 )
            this.port = portInt;
        try {
            socket = new Socket(host,port);
            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            output = new PrintStream( socket.getOutputStream() );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[])
    {
        SocketClient socketClient = new SocketClient("",0);
        Thread thread = new Thread(socketClient);
        thread.start();
    }

    public void send(String outputString)  {
        System.out.println("send ...............");
        System.out.println(outputString.getBytes());
        System.out.println(outputString.getBytes().length);
        output.write(outputString.getBytes(),0,outputString.getBytes().length);
    }

    public synchronized String read(){
        StringBuffer strBuf = new StringBuffer(2048);
        int i;
        char[] buffer = new char[2048];
        try {
            i = input.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
            i = -1;
        }

        for (int j = 0; j < i; j++) {
            strBuf.append((char) buffer[j]);
        }
        return strBuf.toString();
    }

    public void request()
    {
        try {
            send("hello world!");
            String out = read();
            System.out.println(out);
            System.out.println("net connection is ok!");
            socket.close();
        } catch (IOException e) {
            e.printStackTrace( );
        }
    }

    @Override
    public void run() {
        try {
            send("hello world!");
            String out = read();
            System.out.println(out);
            System.out.println("net connection is ok!");
            socket.close();
        } catch (IOException e) {
            e.printStackTrace( );
        }
    }
}

3.问题来了:

app跑起来以后,avd就是各种报错,连接不到服务端。我单独讲代码拿出来测试,客户端和服务端的代码均没有问题。

踩过的坑:网上很多人说要进行端口映射,通过telnet localhost 5554【这意味着进入了avd的管理端。5554,是这么来的--在启动android studio的时候,有这么一句,大家注意一下,就是它:Connected to process 22573 on device mydevice3 [emulator-5554]】 ,然后通过 redir add tcp:8888:8888做端口映射,然后就可以连接了。

但是,上述方法无用。而且在我做了端口映射以后,启动服务器端还会报错说端口被占用。

 

仔细查看报错,原来是:NetworkOnMainThreadException这个错误,

从这个博客https://blog.csdn.net/llixiangjian/article/details/72910557这里搜到了答案,

在代码中增加如下一段就可以强制在主线程内发起联网请求

if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

 另一种解决方案,就是新开一个线程,然后再发起联网请求:

Thread thread = new  Thread(){
            public void run(){SocketClient socketClient = new SocketClient("10.0.2.2",8888);
                socketClient.request();
            }
        };
        thread.start();

如上的写法是没有问题的,但是如下的写法是不行的:

Thread thread = new  Thread(){
            public void run(){
                button1.setOnClickListener(new SocketClientListener());
            }
        };
        thread.start();

这说明,即使是新开的线程,在里面也不能在监听器中有联网请求。