美文网首页
基于UDP实现Android和PC端的双向通信

基于UDP实现Android和PC端的双向通信

作者: yangshengyi | 来源:发表于2019-02-21 19:53 被阅读0次

首先我们先来简单了解一下UDP协议。它和TCP协议都是网络通信中非常重要的传输协议。不同于TCP协议的端到端服务,它是面向非连接的,属不可靠协议,实际上,UDP实现了两个功能,并有它自己的优势:

  • 在IP协议的基础上添加了端口
  • 可以检测传输过程中可能产生的错误数据,抛弃那些已经损坏的数据
  • 无需建立连接,传输速度快
  • 在多播和广播时只能用UDP协议

当然UDP也有一定的不足之处:

  • 无连接,传输不可靠
  • 无连接,一旦一方数据报丢失,另一方将陷入无限等待(这时可以设置一个超时来解决)

接下来切入正题,在Java中UDP的实现分为两个类:DatagramPacket和DatagramSocket。DatagramPacket类将数据字节填充到UDP包中,这就是数据报;DatagramSocket来发送这个包,要接收数据。到底java如何一步步实现UDP通信呢?

  • 首先创建一个DatagramSocket实例,指定本地端口号,并可以有选择地指定本地地址,此时,服务器已经准备好从任何客户端接收数据报文;
  • 使用DatagramSocket实例的receive()方法接收一个DatagramPacket实例,当receive()方法返回时,数据报文就包含了客户端的地址,这样就知道了回复信息应该发送到什么地方;
  • 使用DatagramSocket实例的send()方法向服务器端返回DatagramPacket实例。

了解了UDP通信的基本原理之后,下面分别从Android端作为发送方,PC端作为接收方和Android端作为接收方,PC端作为发送方来具体说明实现思路和过程。

无论是发送方还是接收方,消息的发送和接收都要放在单独的线程中执行,以免出现消息阻塞。需要特别注意的是,Android端作为接收方要考虑Android的UI主线程和子线程,也就是说,UI主线程里不能有任何延时的操作。所以Android端接收到的消息要放进消息队列中,用handle消息处理机制,在子线程中接收消息并处理。

Android端:
public class MainActivity extends AppCompatActivity {

    private EditText etmessage;
    private TextView showmessage;
    private String message;


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btnsend = this.findViewById(R.id.btnSend);
        etmessage = this.findViewById(R.id.etMessage);
        showmessage = this.findViewById(R.id.showMessage);

        Log.v("shoudao", "msg");

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        receiveMsg();
                    } catch (IOException e) {

                    }
                }
            }
        }).start();

        btnsend.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            String s = etmessage.getText().toString();
                            sendMsg(s);
                            Log.v("client send", s);
                        } catch (IOException e) {

                        }
                    }
                }).start();

            }

        });
    }

    public void sendMsg(String msg) throws IOException {

        Log.v("client send", msg);

        DatagramSocket socket = new DatagramSocket(0);
        InetAddress host = InetAddress.getByName("192.168.43.171");
        byte[] data = msg.getBytes();
        DatagramPacket request = new DatagramPacket(data, data.length, host, 9988);
        socket.send(request);

    }

    public void receiveMsg() throws IOException {

        Log.v("Android recieve", "start..");

        DatagramSocket socket = new DatagramSocket(6666);
        Log.v("Android port", "start..");
        byte[] container = new byte[10];
        DatagramPacket request = new DatagramPacket(container, 10);
        Log.v("Android port", "start..");

        socket.receive(request);
        message = new String(container);

        Message msg = handle.obtainMessage();
        msg.obj = message;
        handle.sendMessage(msg);

        Log.v("shou dao xiaoxi", message);

    }

     private Handler handle=new Handler(){
        public void handleMessage(Message msg){

            String s=(String)msg.obj;
            showmessage.setText(s);
         }
    };

}

PC端:
public class UDPServer {
    public static void main(String[] args) throws IOException {
        System.out.println("UDP recive server start...");

       DatagramSocket socket=new DatagramSocket(9988);
       byte[]container=new byte[10];

       DatagramPacket request=new DatagramPacket(container,10);

        System.out.println("go");
        SendMsg send=new SendMsg();
        send.start();
        System.out.println("go1");

        while(true) {
            socket.receive(request);
            String address=request.getAddress().toString();
            String s = new String(container);
            System.out.println("shou dao xiaoxi" + s+"from"+address);
        }

    }

public class SendMsg extends Thread {

    @Override
    public void run(){
        String message= null;
        System.out.println("go2");
        try {
            message = sendMsg();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("fasong:"+message);
    }

    public String sendMsg() throws IOException {

        String s="run";
        DatagramSocket socket = new DatagramSocket(0);

        InetAddress host = InetAddress.getByName("192.168.43.1");

        byte[] data = s.getBytes();
        DatagramPacket request = new DatagramPacket(data, data.length, host, 6666);

        socket.send(request);
        return s;

    }
}

UDP程序在receive()方法处阻塞,直到收到一个数据报文或等待超时,由于UDP协议是不可靠协议,如果没有收到DatagramPacket,那么程序将会一直阻塞在receive()方法处,这样客户端将永远都接收不到服务器端发送回来的数据,但是又没有任何提示。为了避免这个问题,除了放在线程中解决之外,我们也可以在客户端使用DatagramSocket类的setSoTimeout()方法来制定receive()方法的最长阻塞时间,并指定重发数据报的次数,如果每次阻塞都超时,并且重发次数达到了设置的上限,则关闭客户端。

这样就基本实现了基于UDP的Android端与PC端的简单通信,与君共勉。

相关文章

网友评论

      本文标题:基于UDP实现Android和PC端的双向通信

      本文链接:https://www.haomeiwen.com/subject/jcbdyqtx.html