UDP实现图片群发

UDP协议(用户数据报协议)是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket,但是这两个Socket之间并没有虚拟链路,这两个Socket只是发送,接收数据报的对象。

UDP的优缺点:
1. 因为UDP协议是面向非连接的协议,没有建立连接的过程,因此它的通信效率很高。很适合一些即时性很强的应用场景。

2.因为在正式通信前不必与对方先连接,不管对方状态就直接发送,至于对方是否可以收到这些数据内容,UDP无法控制,所以说UDP是一种不可靠的协议。

3.传输大小限制在64KB以下,这个尤其要注意,在做这个实例的时候,因为没有考虑到这个,直接传了一张大图,结果找了半天的原因。

Java使用DatagramSocket代表UDP协议的Socket,它唯一的作用是接收和发送数据报,至于数据究竟发给谁,DatagramSocket并不清楚;具体发送的目的地是由DatagramPacket自身决定。当Client/Server程序使用UDP协议时,实际上并没有严格的服务器和客户端的区分。通常固定IP地址,固定端口的DatagramSocket对象所在程序被称为服务器,因为有固定的IP,端口地址,其他客户端的数据报可以直接发送到服务器上。

接收数据的DatagramPacket在实例化时无需指定端口和IP地址,给出数据数据的字节数组以及长度即可。然后调用DatagramSocket的receive()方法等待数据报的到来,该方法阻塞线程直到受到一个数据报为止。

发送数据的DatagramPacket不同的是,需要给出完整的目的地,包括IP地址和端口,这样数据报才能知道将数据发给谁。当服务器接收到一个DatagramPacket对象后,如果想向该数据报的发送者反馈一些消息,但由于UDP协议是面向非连接的,所以不知道数据报是谁发送过来的,但程序可以调用DatagramPacket的getAddress()(返回一个InetAddress对象,发报的IP地址),getPort()(返回发报的端口)和getSocketAddress()(返回一个SocketAddress对象,该对象可以同时代表IP地址和端口)。

实现思路:每个客户端启动时都会向服务端发送一个字符串,该字符串代表该客户端已经上线,并在服务端将每个客户端的发报地址(即SocketAddress对象)保存在一个Set集合中。当点击任意一个上线的客户端的发送图片按钮,该图片数据就会被发送到服务端上,服务端遍历SocketAddress集合,并将图片数据转发到每个SocketAddress对应的客户端上,就实现了简单的图片群发。具体代码如下:

客户端发送数据报的工具类:

public class DatagramUtil
{
    public static final int BOADCAST_PORT = 8888;
    public static final String DEST_IP = "192.168.1.101";
    private static final int DATA_LEN = 50000;
    //定义本程序私聊的Socket实例
    private DatagramSocket singleSocket = null;
    //定义接收网络数据的字符数组
    byte[] inBuff = new byte[DATA_LEN];
    private Handler handler;

    //构造器,初始化资源
    public DatagramUtil(Handler handler) throws Exception
    {
        this.handler = handler;
        //创建用于私聊的DatagramSocket对象
        singleSocket = new DatagramSocket();
        new ReadSingle().start();
    }

    //定义单独用户发送消息的方法
    public void sendSingle(byte[] msg)
    {
        try
        {
            DatagramPacket packet = new DatagramPacket(new byte[0] , 0 ,  InetAddress.getByName(DEST_IP) , BOADCAST_PORT);
            packet.setData(msg);
            singleSocket.send(packet);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    //不断地从DatagramSocket中读取数据的线程
    class ReadSingle extends Thread
    {
        byte[] singleBuff = new byte[DATA_LEN];
        private DatagramPacket singlePacket = new DatagramPacket(singleBuff , singleBuff.length);

        @Override
        public void run()
        {
            while (true)
            {
                // 读取Socket中的数据
                try
                {
                    //读取Socket中的数据
                    singleSocket.receive(singlePacket);
                    //处理得到的消息
                    Message msg = new Message();
                    msg.what = 0x123;
                    msg.obj = singleBuff;
                    handler.sendMessage(msg);
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                    if (singleSocket != null)
                    {
                        //关闭该Socket对象
                        singleSocket.close();
                    }
                }
            }
        }
    }
}

收到服务端发来的图片数据时,使用Handler更新UI。

public class MainActivity extends Activity
{
    private Button button;
    private ImageView img;
    private DatagramUtil datagramUtil;
    Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            if (msg.what == 0x123)
            {
                byte[] result = (byte[]) msg.obj;
                img.setImageBitmap(BitmapFactory.decodeByteArray(result , 0 , result.length));
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        button = (Button) findViewById(R.id.send_img_all);
        img = (ImageView) findViewById(R.id.receiver_img);

        try
        {
            datagramUtil = new DatagramUtil(handler);
            sendData(stringYoByte());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        button.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                sendData(bitMapToByte());
            }
        });
    }

    private void sendData(final byte[] msg)
    {
        new Thread()
        {
            @Override
            public void run()
            {
                datagramUtil.sendSingle(msg);
            }
        }.start();
    }

    public byte[] bitMapToByte()
    {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources() , R.drawable.wenqing);
        ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG , 100 , byteArray);
        bitmap.recycle();
        return byteArray.toByteArray();
    }

    public byte[] stringYoByte()
    {
        String loginStr = "hello";
        return loginStr.getBytes();
    }
}

服务端代码(运行该Java程序即可):

public class UDPServer
{
    public static final int PORT = 8888;
    private static final int DATA_LEN = 50000;
    byte[] inBuff = new byte[DATA_LEN];
    private DatagramPacket inPacket = new DatagramPacket(inBuff , inBuff.length);
    private DatagramPacket outPacket;
    private DatagramSocket serverSocket;
    private Set<SocketAddress> socketAddressList = Collections.synchronizedSet(new HashSet<SocketAddress>());

    public void init() throws IOException
    {
        serverSocket = new DatagramSocket(PORT);
        while (true)
        {
            serverSocket.receive(inPacket);
            String result = new String(inBuff , 0 , inBuff.length);
            if (result.trim().equals("hello"))
            {
                socketAddressList.add(inPacket.getSocketAddress());
            }
            else
            {
                for (Iterator<SocketAddress> iterator = socketAddressList.iterator(); iterator.hasNext() ; )
                {
                    SocketAddress socketAddress = iterator.next();
                    outPacket = new DatagramPacket(inBuff , inBuff.length , socketAddress);
                    serverSocket.send(outPacket);
                }
            }
        }
    }

    public static void main(String[] args) throws IOException
    {
        new UDPServer().init();
    }
}

这样实现了简单的图片群发的效果。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值