羊皮书APP(Android版)开发系列(十二)Android Socket UDP大文件传输

Tcp和IP协议是很重要的内容,但是要理解这些协议最好的方式就是自己根据业务写一些demo,加深理解。

业务需求是:通过电脑端(网页或客户端形式)发送文件到Android的客户端,下面是使用UDP实现的一个简单的文件传输Demo,因UDP为不可靠传输,可能会丢包。

  • 服务器端发送本地文件,代码如下:
package client;

import server.udp.UDPUtils;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;

public class UDPClient {

    private static final String SEND_FILE_PATH = "/Users/wangjie/Documents/123.mp4";

    public static void main(String[] args){
        long startTime = System.currentTimeMillis();

        byte[] buf = new byte[UDPUtils.BUFFER_SIZE];
        byte[] receiveBuf = new byte[1];

        RandomAccessFile accessFile = null;
        DatagramPacket dpk = null;
        DatagramSocket dsk = null;
        int readSize = -1;
        try {
            accessFile = new RandomAccessFile(SEND_FILE_PATH,"r");
//            dpk = new DatagramPacket(buf, buf.length,new InetSocketAddress(InetAddress.getByName("localhost"), UDPUtils.PORT + 1));
            dpk = new DatagramPacket(buf, buf.length,new InetSocketAddress(InetAddress.getByName("192.168.1.119"), UDPUtils.PORT + 1));
            dsk = new DatagramSocket(UDPUtils.PORT);
            int sendCount = 0;
            while((readSize = accessFile.read(buf,0,buf.length)) != -1){
                System.out.println("readSize:"+readSize);
                dpk.setData(buf, 0, readSize);
                dsk.send(dpk);
                // wait server response
                {
                    while(true){
                        dpk.setData(receiveBuf, 0, receiveBuf.length);
                        dsk.receive(dpk);

                        // confirm server receive
                        if(!UDPUtils.isEqualsByteArray(UDPUtils.successData,receiveBuf,dpk.getLength())){
                            System.out.println("resend ...");
                            dpk.setData(buf, 0, readSize);
                            dsk.send(dpk);
                        }else
                            break;
                    }
                }

                System.out.println("send count of "+(++sendCount)+"!");
            }
            // send exit wait server response
            while(true){
                System.out.println("client send exit message ....");
                dpk.setData(UDPUtils.exitData,0,UDPUtils.exitData.length);
                dsk.send(dpk);

                dpk.setData(receiveBuf,0,receiveBuf.length);
                dsk.receive(dpk);
                // byte[] receiveData = dpk.getData();
                if(!UDPUtils.isEqualsByteArray(UDPUtils.exitData, receiveBuf, dpk.getLength())){
                    System.out.println("client Resend exit message ....");
                    dsk.send(dpk);
                }else
                    break;
            }
        }catch (Exception e) {
            e.printStackTrace();
        } finally{
            try {
                if(accessFile != null)
                    accessFile.close();
                if(dsk != null)
                    dsk.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        long endTime = System.currentTimeMillis();
        System.out.println("time:"+(endTime - startTime));
    }
}
  • 客户端接收文件存到本地,代码如下:
package cn.studyou.androidsocket;


import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;

public class UDPReceiveFileActivity extends Activity {

    private String localUrl;
    private static final String FILE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/VideoCache/";
    private static final String SAVE_FILE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/VideoCache/";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_udpfile_mplayer);

        Log.e("FILE_DIR", FILE_DIR);
        new Thread(new Runnable() {
            @Override
            public void run() {
                receiveFile();
            }
        }).start();
    }
    public void receiveFile() {

        byte[] buf = new byte[UDPUtils.BUFFER_SIZE];

        DatagramPacket dpk = null;
        DatagramSocket dsk = null;
        BufferedOutputStream bos = null;
        try {
            InetAddress loc = InetAddress.getByName("192.168.1.107");

            dpk = new DatagramPacket(buf, buf.length, new InetSocketAddress(loc, UDPUtils.PORT));
            dsk = new DatagramSocket(UDPUtils.PORT + 1);

            if (localUrl == null) {
                localUrl = SAVE_FILE_PATH + "1235.mp4";
            }
            File cacheFile = new File(localUrl);

            if (!cacheFile.exists()) {
                cacheFile.getParentFile().mkdirs();
                cacheFile.createNewFile();
            }
            bos = new BufferedOutputStream(new FileOutputStream(localUrl));
            System.out.println("wait client ....");
            dsk.receive(dpk);
            System.out.println("wait clientq ....");

            int readSize = 0;
            int readCount = 0;
            int flushSize = 0;
            while ((readSize = dpk.getLength()) != 0) {
                // validate client send exit flag
                if (UDPUtils.isEqualsByteArray(UDPUtils.exitData, buf, readSize)) {
                    System.out.println("server exit ...");
                    // send exit flag
                    dpk.setData(UDPUtils.exitData, 0, UDPUtils.exitData.length);
                    dsk.send(dpk);
                    break;
                }

                bos.write(buf, 0, readSize);
                if (++flushSize % 1000 == 0) {
                    flushSize = 0;
                    bos.flush();
                }
                dpk.setData(UDPUtils.successData, 0, UDPUtils.successData.length);
                dsk.send(dpk);

                dpk.setData(buf, 0, buf.length);
                System.out.println("receive count of " + (++readCount) + " !");
                dsk.receive(dpk);
            }

            // last flush
            bos.flush();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bos != null)
                    bos.close();
                if (dsk != null)
                    dsk.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏刘晓杰

Glide生命周期管理

4448
来自专栏函数式编程语言及工具

Akka(31): Http:High-Level-Api,Route rejection handling

   Route 是Akka-http routing DSL的核心部分,使用户能比较方便的从http-server的角度筛选http-request、进行se...

2567
来自专栏向治洪

android异步操作

为了使UI在数据获取时不僵死,数据获取需要在新开Worker线程中进行,然后将返回结果在UI线程中进行读取并渲染页面。面对这种异步处理,到底如何写才简洁,先后面...

2278
来自专栏码匠的流水账

micrometer自定义metrics

spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframewor...

2382
来自专栏积累沉淀

多人聊天室

最近学完网络线程协议 ,因此写了一个用java编写的聊天室 话不多说 效果如图 ? 首先 创建服务器端 package com.yc.server...

7398
来自专栏码匠的流水账

聊聊spring cloud gateway的RedirectToGatewayFilter

本文主要研究下spring cloud gateway的RedirectToGatewayFilter

1691
来自专栏向治洪

android进程 清理及activity栈管理

MainActivity如下: package come.on;   import android.app.Activity;   import andro...

26310
来自专栏码匠的流水账

聊聊springcloud的featuresEndpoint

spring-cloud-commons-2.0.0.RC1-sources.jar!/org/springframework/cloud/client/Com...

991
来自专栏向治洪

android多线程下载2

在上一集中,我们简单介绍了如何创建多任务下载,但那种还不能拿来实用,这一集我们重点通过代码为大家展示如何创建多线程断点续传下载,这在实际项目中很常用. main...

2229
来自专栏Android工程师的修仙之旅

自己动手写Android插件化框架

本文旨在通过两个实例直观的说明插件的实现原理以加深对插件内开发的理解,因此不会深入探讨背景和原理,代码也尽量专注于核心逻辑。

6093

扫码关注云+社区

领取腾讯云代金券