TCP 文件传输

后来优化了代码,完整项目博客地址:这里太久了

https://blog.csdn.net/fkgjdkblxckvbxbgb/article/details/79456563


项目中有集成tecent 的Im, 传递一些图片 ,音频和一些文字消息,还是刚刚的 ,还是系统升级的问题 ,OTA升级没做好,只能升级系统整包 ,600多M  ,网络不好的用户就很头疼,文件太大 ,耗时太久 ,

这就催生了我是用局域网文件传输的功能 ,上次想到的是UDP ,测试环境下 ,丢包比较严重 ,体验较差,返回来使用Socket传输把 ,稳定性提高了很多

这是网上以为仁兄的代码 ,我稍微改动了一下 ,写下来分享出来,网上很多的博客 ,demo都美发使用,这个是可以使用的 

 直接上代码 




选择本地文件并上传需要依赖

compile 'com.nononsenseapps:filepicker:2.5.2'

清单文件注册

<activity
    android:name="com.nononsenseapps.filepicker.FilePickerActivity"
    android:label="@string/app_name"
    android:theme="@style/FilePickerTheme">
    <intent-filter>
        <action android:name="android.intent.action.GET_CONTENT" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>



1:一个封装进度的对象

package com.mmb.tcp;

/**
 * Created by jsjm on 2017/11/28.
 */

public class TcpEntity {

    long progress;

    public TcpEntity(long progress) {
        this.progress = progress;
    }

    public long getProgress() {
        return progress;
    }

    public void setProgress(long progress) {
        this.progress = progress;
    }
}

工具类,所有的传送和接受代码就在这里了

package com.mmb.tcp;

import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import org.greenrobot.eventbus.EventBus;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class SocketManager {
    private ServerSocket server;
    private Handler handler = null;

    public SocketManager(Handler handler) {
        this.handler = handler;
        int port = 9999;
        while (port > 9000) {
            try {
                server = new ServerSocket(port);
                break;
            } catch (Exception e) {
                port--;
            }
        }
        SendMessage(1, port);
        Thread receiveFileThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    ReceiveFile();
                }
            }
        });
        receiveFileThread.start();
    }

    void SendMessage(int what, Object obj) {
        if (handler != null) {
            Message.obtain(handler, what, obj).sendToTarget();
        }
    }

    void ReceiveFile() {
        try {
            Socket name = server.accept();
            InputStream nameStream = name.getInputStream();
            InputStreamReader streamReader = new InputStreamReader(nameStream);
            BufferedReader br = new BufferedReader(streamReader);
            String fileName = br.readLine();
            br.close();
            streamReader.close();
            nameStream.close();
            name.close();
            SendMessage(0, "正在接收:" + fileName);

            Socket data = server.accept();
            InputStream dataStream = data.getInputStream();
            String savePath = Environment.getExternalStorageDirectory().getPath() + "/" + fileName;
            FileOutputStream file = new FileOutputStream(savePath, false);
            byte[] buffer = new byte[1024];
            int size = -1;
            while ((size = dataStream.read(buffer)) != -1) {
                file.write(buffer, 0, size);
            }
            file.close();
            dataStream.close();
            data.close();
            SendMessage(0, fileName + "接收完成");
        } catch (Exception e) {
            SendMessage(0, "接收错误:\n" + e.getMessage());
        }
    }

    public void SendFile(ArrayList<String> fileName, ArrayList<String> path, String ipAddress, int port) {
        try {
            for (int i = 0; i < fileName.size(); i++) {
                Socket name = new Socket(ipAddress, port);
                OutputStream outputName = name.getOutputStream();
                OutputStreamWriter outputWriter = new OutputStreamWriter(outputName);
                BufferedWriter bwName = new BufferedWriter(outputWriter);
                bwName.write(fileName.get(i));
                bwName.close();
                outputWriter.close();
                outputName.close();
                name.close();
                SendMessage(0, "正在发送" + fileName.get(i));

                Socket data = new Socket(ipAddress, port);
                OutputStream outputData = data.getOutputStream();
                FileInputStream fileInput = new FileInputStream(path.get(i));
                int size = -1;
                long sum = 0;
                byte[] buffer = new byte[1024];
                while ((size = fileInput.read(buffer, 0, 1024)) != -1) {
                    outputData.write(buffer, 0, size);
                    sum += buffer.length;
                    Log.e("write", "====" + sum);
                    EventBus.getDefault().post(new TcpEntity(sum));
                }
                outputData.close();
                fileInput.close();
                data.close();
                SendMessage(0, fileName.get(i) + "  发送完成");
            }
            SendMessage(0, "所有文件发送完成");
        } catch (Exception e) {
            SendMessage(0, "发送错误:\n" + e.getMessage());
        }
    }
}


传送端的代码

package com.mmb.activity;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.mmb.tcp.SocketManager;
import com.mmb.tcp.TcpEntity;
import com.nononsenseapps.filepicker.FilePickerActivity;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class ChatTestActivity extends AppCompatActivity {
    private static final int FILE_CODE = 0;
    private TextView tvMsg, send_progress;
    private EditText txtIP, txtEt;
    private Button btnSend;
    private Handler handler;
    private SocketManager socketManager;

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

        initView();
        EventBus.getDefault().register(this);
    }

    private void initView() {
        send_progress = (TextView) findViewById(R.id.send_progress);
        tvMsg = (TextView) findViewById(R.id.tvMsg);
        txtIP = (EditText) findViewById(R.id.txtIP);
        txtEt = (EditText) findViewById(R.id.et);
        btnSend = (Button) findViewById(R.id.btnSend);
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(ChatTestActivity.this, FilePickerActivity.class);
                i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, true);
                i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
                i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE);
                i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath());
                startActivityForResult(i, FILE_CODE);
            }
        });
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:
                        SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
                        txtEt.append("\n[" + format.format(new Date()) + "]" + msg.obj.toString());
                        break;
                    case 1:
                        tvMsg.setText("本机IP:" + GetIpAddress() + " 监听端口:" + msg.obj.toString());
                        break;
                    case 2:
                        Toast.makeText(getApplicationContext(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        };
        socketManager = new SocketManager(handler);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void sendFileTcp(TcpEntity info) {
        long progress = info.getProgress();
        send_progress.setText(bytes2kb(progress) + "   /" + progress);
    }

    public static String bytes2kb(long bytes) {
        BigDecimal filesize = new BigDecimal(bytes);
        BigDecimal megabyte = new BigDecimal(1024 * 1024);
        float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP)
                .floatValue();
        if (returnValue > 1)
            return (returnValue + "MB");
        BigDecimal kilobyte = new BigDecimal(1024);
        returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP)
                .floatValue();
        return (returnValue + "KB");
    }


    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == FILE_CODE && resultCode == Activity.RESULT_OK) {
            final String ipAddress = txtIP.getText().toString();
            final int port = 9999;
            if (data.getBooleanExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, true)) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    ClipData clip = data.getClipData();
                    final ArrayList<String> fileNames = new ArrayList<>();
                    final ArrayList<String> paths = new ArrayList<>();
                    if (clip != null) {
                        for (int i = 0; i < clip.getItemCount(); i++) {
                            Uri uri = clip.getItemAt(i).getUri();
                            paths.add(uri.getPath());
                            fileNames.add(uri.getLastPathSegment());
                        }
                        Message.obtain(handler, 0, "正在发送至" + ipAddress + ":" + port).sendToTarget();
                        Thread sendThread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                socketManager.SendFile(fileNames, paths, ipAddress, port);
                            }
                        });
                        sendThread.start();
                    }
                } else {
                    final ArrayList<String> paths = data.getStringArrayListExtra
                            (FilePickerActivity.EXTRA_PATHS);
                    final ArrayList<String> fileNames = new ArrayList<>();
                    if (paths != null) {
                        for (String path : paths) {
                            Uri uri = Uri.parse(path);
                            paths.add(uri.getPath());
                            fileNames.add(uri.getLastPathSegment());
                            socketManager.SendFile(fileNames, paths, ipAddress, port);
                        }
                        Message.obtain(handler, 0, "正在发送至" + ipAddress + ":" + port).sendToTarget();
                        Thread sendThread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                socketManager.SendFile(fileNames, paths, ipAddress, port);
                            }
                        });
                        sendThread.start();
                    }
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @SuppressLint("WifiManagerLeak")
    public String GetIpAddress() {
        WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        int i = wifiInfo.getIpAddress();
        return (i & 0xFF) + "." +
                ((i >> 8) & 0xFF) + "." +
                ((i >> 16) & 0xFF) + "." +
                ((i >> 24) & 0xFF);
    }
}

传送段的布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvMsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:textColor="@color/white" />

    <EditText
        android:id="@+id/txtIP"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:contentDescription="目标IP地址"
        android:ems="10"
        android:hint="请输入对方ip"
        android:textColor="@color/white" />

    <EditText
        android:id="@+id/et"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:layout_alignLeft="@+id/txtIP"
        android:clickable="false"
        android:editable="false"
        android:ems="10"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:gravity="center_vertical|left|top"
        android:inputType="textMultiLine"
        android:longClickable="false"
        android:scrollbarAlwaysDrawVerticalTrack="true"
        android:scrollbarStyle="insideInset"
        android:scrollbars="vertical"
        android:textColor="@color/white"
        android:textSize="15dp">

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/send_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="发送大小"
        android:textColor="@color/white" />

    <Button
        android:id="@+id/btnSend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/txtPort"
        android:layout_below="@+id/et"
        android:text="选择文件并发送"
        android:textColor="@color/white" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dimen_20"
        android:text="使用方法:\n1:打开设备,退出到退出界面,\n2:点击鼠标menu菜单按钮,点击5次,进入接受文件界面\n3:双方设备须在同一wifi下\n4:点击选择文件,后发送,\n5:设备接受完毕,重启设备,等待升级"
        android:textColor="@color/white" />

</LinearLayout>

接收端的代码,里面有个二维码显示的功能,可以直接删除,我是准备用扫码传送的,

package com.mirror.activity;

import android.annotation.SuppressLint;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.mirror.R;
import com.mirror.config.AppInfo;
import com.mirror.tcp.SendFileEntity;
import com.mirror.tcp.SocketManager;
import com.mirror.util.FileUtil;
import com.mirror.util.ImageUtil;
import com.mirror.util.QRCodeUtil;
import com.mirror.view.MyToastView;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TestTcpActiivty extends BaseActivity {
    private TextView tvMsg, tv_desc;
    private EditText txtEt;
    ImageView iv_bind_code;
    private SocketManager socketManager;
    private TextView tv_receiver_progress;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
        setContentView(R.layout.activity_tcp);
        initView();
    }

    private void initView() {
        tv_receiver_progress = (TextView) findViewById(R.id.tv_receiver_progress);
        iv_bind_code = (ImageView) findViewById(R.id.iv_bind_code);
        tv_desc = (TextView) findViewById(R.id.tv_desc);
        tvMsg = (TextView) findViewById(R.id.tvMsg);
        txtEt = (EditText) findViewById(R.id.et);
        socketManager = new SocketManager(handler);
        FileUtil.creatDirPathNoExists();
        QRCodeUtil.createErCode(GetIpAddress(), AppInfo.BASE_QR_PATH + "/bindqu.jpg", 200, listener);
    }

    QRCodeUtil.ErCodeListener listener = new QRCodeUtil.ErCodeListener() {

        @Override
        public void createSuccess(String path) {
            Message message = new Message();
            message.what = CREATE_IMAGE;
            message.obj = path;
            handler.sendMessage(message);
        }

        @Override
        public void createFailed(String error) {
            handler.sendEmptyMessage(CREATE_IMAGE_FAILED);
        }
    };


    public static final int CREATE_IMAGE = 89;
    public static final int CREATE_IMAGE_FAILED = 90;
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CREATE_IMAGE_FAILED:
                    tv_desc.setText("图片创建失败,请手动输入IP地址,进行文件传输");
                    break;
                case CREATE_IMAGE:
                    tv_desc.setText("扫描二维码,进行文件传输");
                    String path = (String) msg.obj;
                    ImageUtil.loadImg(TestTcpActiivty.this, iv_bind_code, path);
                    break;
                case 0:
                    SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
                    txtEt.append("\n[" + format.format(new Date()) + "]" + msg.obj.toString());
                    break;
                case 1:
                    tvMsg.setText("本机IP:" + GetIpAddress() + " ( 监听端口:" + msg.obj.toString() + " )");
                    break;
                case 2:
                    Toast.makeText(getApplicationContext(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };


    @Subscribe(threadMode = ThreadMode.MAIN)
    public void sendFileTcp(SendFileEntity info) {
        long progress = info.getFileLength();
        tv_receiver_progress.setText(progress + "  k");
    }

    public static String bytes2kb(long bytes) {
        BigDecimal filesize = new BigDecimal(bytes);
        BigDecimal megabyte = new BigDecimal(1024 * 1024);
        float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP)
                .floatValue();
        if (returnValue > 1)
            return (returnValue + "MB");
        BigDecimal kilobyte = new BigDecimal(1024);
        returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP)
                .floatValue();
        return (returnValue + "KB");
    }


    @SuppressLint("WifiManagerLeak")
    public String GetIpAddress() {
        WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        int i = wifiInfo.getIpAddress();
        return (i & 0xFF) + "." +
                ((i >> 8) & 0xFF) + "." +
                ((i >> 16) & 0xFF) + "." +
                ((i >> 24) & 0xFF);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}


布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvMsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="TextView"
        android:textColor="@color/black"
        android:textSize="@dimen/text_25" />

    <TextView
        android:id="@+id/tv_receiver_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="@color/gray"
        android:textSize="@dimen/text_20" />


    <ImageView
        android:id="@+id/iv_bind_code"
        android:layout_width="@dimen/dimen_200"
        android:layout_height="@dimen/dimen_200"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="@dimen/dimen_30" />

    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="扫描二维码进行文件传输"
        android:textColor="@color/gray"
        android:textSize="@dimen/text_20" />


    <EditText
        android:id="@+id/et"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:layout_marginTop="@dimen/dimen_15"
        android:editable="false"
        android:ems="10"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:gravity="center_vertical|left|top"
        android:inputType="textMultiLine"
        android:longClickable="false"
        android:scrollbarAlwaysDrawVerticalTrack="true"
        android:scrollbarStyle="insideInset"
        android:scrollbars="vertical"
        android:textSize="15dp">

        <requestFocus />
    </EditText>

</LinearLayout>












猜你喜欢

转载自blog.csdn.net/fkgjdkblxckvbxbgb/article/details/78674430
今日推荐