公司要求搞个手机控制电视盒子的功能,涉及到文件传输和控制指令,网上有很多例子,简单的总结一下,使用一个socket线程来进行文件传输和指令传输

server端WifiFileServers.java

public class WifiFileServers {

    private ServerSocket serverSocket = null;
    private String serversIp;

    private Handler mHandler;
    private HandlerThread handlerThread;

    private Socket socket = null;
    private OnServersListener serversListener;

    public WifiFileServers(final int port){

        handlerThread = new HandlerThread("WifiFileServers");
        handlerThread.start();

        mHandler = new Handler(handlerThread.getLooper());

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //开启socket
                try {
                    serverSocket = new ServerSocket(port);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                serversIp = GetIpAddress.getLocalIpAddress();
            }
        });
    }


    public void startServers(final OnServersListener listener){
        serversListener = listener;
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                int port = serverSocket.getLocalPort();

                serversListener.onServersIp(serversIp,port);
                //等待连接,我这里做的是单连接,多连接可以建个连接类,把socket放到连接类中
                while (!serverSocket.isClosed()){

                    try {
                        socket = serverSocket.accept();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //连接成功开始接收数据,如果多连接需要多开线程
                    if(socket != null){
                        start();
                    }
                }
            }
        });
    }

    public void start() {
        int port = serverSocket.getLocalPort();
        String ip = socket.getInetAddress().getHostAddress();
        serversListener.onConnect(port,ip);
        long length = 0;
        int len;
        FileOutputStream fos = null;
        File file = null;
        //用于接收文件数据
        byte[] bytes = new byte[8192];
        //用于接收字符串
        ByteArrayOutputStream baos  = new  ByteArrayOutputStream();
        try {
            File path = new File(Environment.getExternalStorageDirectory()+"/HMSDK/video");
            if(!path.exists()){
                path.mkdir();
            }
            int type = -1;
            String fileName = null;
            long size = 0;
            //等待数据
            while ((len = socket.getInputStream().read(bytes)) != -1) {
                //数据长度为1的时候,可能为client端发来的数据类型标签
                if(len == 1){
                    //0表示准备发送字符串
                    if(bytes[0] == '0' && type == -1){
                        type = 1;
                        //准备好接收字符串
                        socket.getOutputStream().write('0');
                    }else if(bytes[0] == '\0' && type == 1){//表示字符串接收完成
                        //转成字符串
                        String data = new String(baos.toByteArray(),"utf8");
                        baos.flush();
                        baos.close();
                        baos.reset();
                        //开始解析
                        String t = data.substring(0,1);
                        if("0".equals(t)){
                            fileName = data.substring(1,data.length());
                        }else if("1".equals(t)){
                            length = Long.valueOf(data.substring(1,data.length()));
                        }else if("3".equals(t)){//正常字符串
                            serversListener.onReceive(port,ip,data.substring(1,data.length()));
                        }
                        type = -1;
                        //通知client字符串接收完成
                        socket.getOutputStream().write('1');
                    }else if(bytes[0] == '5' && type == -1){//准备接收文件
                        type = 0;
                        size = 0;
                        //创建文件
                        if(fileName != null){
                            file = new File(Environment.getExternalStorageDirectory()+"/HMSDK/video", fileName);
                            if (file.exists()) {
                                file.delete();
                            }
                            fos = new FileOutputStream(file);
                        }
                        //通知client端准备接收数据
                        socket.getOutputStream().write('5');
                    }else if(type == 0 && fos != null) {//接收只有1的数据
                        fos.write(bytes, 0, len);
                        fos.flush();
                        size += len;
                        serversListener.onData(port,ip,fileName,length,size);
                        //接收到的数据和文件大小相等
                        if(size == length){
                            //接收完成,通知client端
                            type = -1;
                            fos.close();
                            socket.getOutputStream().write('9');
                            serversListener.onOver(port,ip,fileName);
                            fileName = null;
                        }
                    }else if(type == 1){//字符串最后1位数据
                        baos.write(bytes,0,len);
                    }
                }else{
                    if(type == 1){
                        if(bytes[len -1] == '\0'){//字符串最后1位是\0,表示字符串接收结束
                            baos.write(bytes,0,len -1);
                            String data = new String(baos.toByteArray(),"utf8");
                            baos.flush();
                            baos.close();
                            baos.reset();
                            String t = data.substring(0,1);
                            if("0".equals(t)){
                                fileName = data.substring(1,data.length());
                            }else if("1".equals(t)){
                                length = Long.valueOf(data.substring(1,data.length()));
                            }else if("3".equals(t)){
                                serversListener.onReceive(port,ip,data.substring(1,data.length()));
                            }
                            type = -1;
                            socket.getOutputStream().write('1');
                        }else{
                            //正常接收
                            baos.write(bytes,0,len);
                        }
                    }else if(type == 0 && fos != null){
                        fos.write(bytes, 0, len);
                        fos.flush();
                        size += len;
                        serversListener.onData(port,ip,fileName,length,size);
                        if(size == length){
                            type = -1;
                            fos.close();
                            socket.getOutputStream().write('9');
                            serversListener.onOver(port,ip,fileName);
                            fileName = null;
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            serversListener.onDisconnect(port,ip);
            try {
                socket.getInputStream().close();
                socket.getOutputStream().close();
                socket.close();
                if(fos != null){
                    fos.close();
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

    }

    public void release(){
        try {
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        handlerThread.quit();
    }
    interface OnServersListener{
        void onServersIp(String serversIp,int port);
        void onConnect(int port,String clientIp);
        void onData(int port,String clientIp,String fileName,long size,long progress);
        void onReceive(int port, String clientIp, String data);
        void onOver(int port, String clientIp,String fileName);
        void onDisconnect(int port,String clientIp);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private TextView editText_1;
    private TextView editText_2;
    private EditText editText_data;

    private WifiFileServers wifiFileServers;

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

        editText_1 = findViewById(R.id.et_1);
        editText_2 = findViewById(R.id.et_2);

        editText_data = findViewById(R.id.et_data);
        //创建文件夹
        File file = new File(Environment.getExternalStorageDirectory()+"/HMSDK/video");
        if(file.exists()){
            file.mkdir();
        }
        receiveData();


    }
    public void send(View view){



    }

    public void receiveData(){

        //初始化
        wifiFileServers = new WifiFileServers(8068);

        //开启server线程
        wifiFileServers.startServers(fileListener);
    }
    //释放socket资源
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        wifiFileServers.release();
    }
    //回调
    WifiFileServers.OnServersListener fileListener = new WifiFileServers.OnServersListener() {
        @Override
        public void onServersIp(final String serversIp, final int port) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    editText_1.setText("IP:" + serversIp + " PORT: " + port);
                }
            });
        }

        @Override
        public void onConnect(int port, final String clientIp) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    editText_1.setText(clientIp+"连接成功");
                }
            });
        }

        @Override
        public void onData(int port, String clientIp, final String fileName, final long size, final long progress) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    long p = progress*100/size;
                    editText_2.setText(fileName+p+"%");
                }
            });
        }

        @Override
        public void onReceive(int port, String clientIp, String data) {

        }

        @Override
        public void onOver(int port, String clientIp, String fileName) {

        }

        @Override
        public void onDisconnect(int port, final String clientIp) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    editText_1.setText(clientIp+"断开连接");
                }
            });
        }
    };
}

布局就不贴了

client端ClientFileServers.java

public class ClientFileServers {
    private Socket socket = null;
    private OutputStream outputStream = null;
    private InputStream inputStream = null;

    private OnServersListener serversListener;

    private Handler mHandler;
    private HandlerThread handlerThread;
    private int port;

    public ClientFileServers() {
        handlerThread = new HandlerThread("ClientFileServers");
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper());
    }

    //连接
    public void connect(final String ip, final int port, OnServersListener listener) {
        serversListener = listener;
        this.port = port;
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    socket = new Socket(ip, port);
                    outputStream = socket.getOutputStream();
                    inputStream = socket.getInputStream();
                    serversListener.onConnect(port);
                } catch (IOException e) {
                    e.printStackTrace();
                    serversListener.onError(port, -1);
                }

            }
        });

    }


    private boolean sendString(String data) throws IOException{
        byte[] buffer = new byte[8192];
        //先发送个0给server端,0表示接下来要发送字符串数据
        outputStream.write('0');
        //接收server端的反馈,0表示准备完成
        if(inputStream.read(buffer) != -1){
            if(buffer[0] != '0'){
                return false;
            }
        }
        //发送数据
        byte[] b = data.getBytes("utf8");
        outputStream.write(b,0,b.length);
        //'\0'表示字符串结束
        outputStream.write('\0');
        //接收server反馈,1表示接收成功
        if(inputStream.read(buffer) != -1){
            if(buffer[0] != '1'){
                return false;
            }
        }
        return true;
    }
    //发生文字
    public void sendData(final String data){
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    if(!sendString(data)){
                        serversListener.onError(port,3);
                        return;
                    }
                    serversListener.onSendData(port);
                } catch (IOException e) {
                    e.printStackTrace();
                    synchronized (ClientFileServers.this){
                        try {
                            if(outputStream != null){
                                outputStream.close();
                                outputStream = null;
                            }
                            if(inputStream != null){
                                inputStream.close();
                                inputStream = null;
                            }
                            if(socket != null){
                                socket.close();
                                socket = null;
                                serversListener.onDisconnect(port);
                            }
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            }
        });
    }
    //发送文件
    public void sendFile(final File file) {

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                FileInputStream fis = null;
                try {
                    //先发送文件名,在文件名前加个0表示这段数据是文件名,也可用json格式,看自己写法
                    String path = "0"+file.getName();
                    //通过发送字符串的形式发送
                    if(!sendString(path)){
                        serversListener.onError(port,3);
                        return;
                    }
                    //再发送文件大小,1表示文件长度
                    String l = "1"+file.length();
                    if(!sendString(l)){
                        serversListener.onError(port,3);
                        return;
                    }
                    //5表示告诉server要开始发送文件数据
                    byte[] b = new byte[8192]; // 8k 
                    outputStream.write('5');
                    //server反馈5表示server准备好接收
                    if(inputStream.read(b) != -1){
                        if(b[0] != '5'){
                            serversListener.onError(port,3);
                            return ;
                        }
                    }
                    //发送文件数据
                    fis = new FileInputStream(file);
                    long size = 0;
                    byte[] buffer = new byte[8192]; // 8k  
                    int len;
                    while ((len = fis.read(buffer)) != -1) {
                        size += len;
                        outputStream.write(buffer, 0, len);
                        outputStream.flush();
                        serversListener.onSendFile(port,file.length(),size);
                    }
                    //等待server端反馈,9表示接收成功
                    if(inputStream.read(b) != -1){
                        if(b[0] != '9'){
                            serversListener.onError(port,3);
                            return ;
                        }
                    }
                    serversListener.onReceive(port);
                } catch (IOException e) {
                    e.printStackTrace();
                    synchronized (ClientFileServers.this){
                        try {
                            if(outputStream != null){
                                outputStream.close();
                                outputStream = null;
                            }
                            if(inputStream != null){
                                inputStream.close();
                                inputStream = null;
                            }
                            if(socket != null){
                                socket.close();
                                socket = null;
                                serversListener.onDisconnect(port);
                            }
                            if(fis != null){
                                fis.close();
                            }
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            }
        });
    }


    public void release() {
        synchronized (ClientFileServers.this){
            try {
                if(inputStream != null){
                    inputStream.close();
                    inputStream = null;
                }
                if (outputStream != null) {
                    outputStream.close();
                    outputStream = null;
                }
                if (socket != null) {
                    socket.close();
                    socket = null;
                    serversListener.onDisconnect(port);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        handlerThread.quit();

    }


    interface OnServersListener {
        void onConnect(int port);
        void onSendData(int port);
        void onSendFile(int port,long size,long progress);
        void onReceive(int port);
        void onDisconnect(int port);
        void onError(int port, int error);
    }


}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private String[] denied;
    private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};


    private EditText editText_data;
    private TextView editText_ip;
    private TextView editText_receive;
    private String ip = "192.168.1.38";
    private String fileName = "1520564093079.mp4";
    //      1520583417803  1520564093079 1521533868730  1528278027688 1528363714863
    private ClientFileServers fileServers;

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

        editText_ip = findViewById(R.id.et_ip);
        editText_data = findViewById(R.id.et_data);
        editText_receive = findViewById(R.id.et_receive);
        editText_ip.setText(ip);

        //权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            ArrayList<String> list = new ArrayList<>();
            for (int i = 0; i < permissions.length; i++) {
                if (PermissionChecker.checkSelfPermission(this, permissions[i]) == PackageManager.PERMISSION_DENIED) {
                    list.add(permissions[i]);
                }
            }
            if (list.size() != 0) {
                denied = new String[list.size()];
                for (int i = 0; i < list.size(); i++) {
                    denied[i] = list.get(i);
                    ActivityCompat.requestPermissions(this, denied, 5);
                }

            } else {
                init();
            }
        } else {
            init();
        }


    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 5) {
            boolean isDenied = false;
            for (int i = 0; i < denied.length; i++) {
                String permission = denied[i];
                for (int j = 0; j < permissions.length; j++) {
                    if (permissions[j].equals(permission)) {
                        if (grantResults[j] != PackageManager.PERMISSION_GRANTED) {
                            isDenied = true;
                            break;
                        }
                    }
                }
            }
            if (isDenied) {
                Toast.makeText(this, "请开启权限", Toast.LENGTH_SHORT).show();
            } else {
                init();

            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    private void init(){
        //初始化socket
        fileServers = new ClientFileServers();
    }


    public void connect(View view){
        //连接server端
        fileServers.connect(ip,8068,serversListener);
    }
    public void send(View view){
        //发送文件
        String f = Environment.getExternalStorageDirectory()+"/HMSDK/video/"+fileName;
        File file = new File(f);
        fileServers.sendFile(file);
    }

    //当客户端界面返回时,关闭相应的socket资源
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        fileServers.release();
    }
    //回调
    private ClientFileServers.OnServersListener serversListener = new ClientFileServers.OnServersListener() {
        @Override
        public void onConnect(int port) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    editText_ip.setText(ip+"连接成功");
                }
            });
        }

        @Override
        public void onSendData(int port) {

        }

        @Override
        public void onSendFile(int port, final long size, final long progress) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    long p = progress*100/size;
                    editText_receive.setText(fileName+p+"%");
                }
            });
        }

        @Override
        public void onReceive(int port) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    editText_receive.setText("文件接收成功");
                }
            });
        }

        @Override
        public void onDisconnect(int port) {

        }

        @Override
        public void onError(int port, int error) {

        }
    };
}