Android 簡單的UDP通信

本來公司想做不經過服務器轉發(fā),兩個設備進行P2P通信的, 經過調研發(fā)現好像只有電信的4G可以實現打洞, 移動和聯通都不能直接進行P2P。然后就寫了個demo測試一下udp通信。查詢網上的資料都是已經知道客戶端和服務端(其實UDP沒有服務端之說)的地址直接進行通信,而我要進行的是兩個客戶端事先不知道對方的ip和port,那應該怎么通信呢?肯定要有一個中間者去將它們聯系起來啊, 具體的做法是:
一個服務端S, 一個客戶端A, 一個客戶端B
A去登陸服務器,這時服務器可以得到A的地址和端口, 并保存下來

A登陸.jpg

B也去登陸服務器,同樣服務器保存了B的地址和端口


B登陸.jpg

這時A去獲取在線的設備,服務器會把在線的ip和port返回,A就有了B的信息,這時就可以給B發(fā)送消息了


A向B發(fā)消息.jpg

B接收到A的消息.jpg
B發(fā)送消息給A.jpg

A收到B的消息.jpg

客戶端代碼:

class UdpThread : Thread(), Runnable {

    //定義一個socket
    private lateinit var socket: DatagramSocket

    //服務器的地址和端口號
    private var serverAddress = "192.168.1.17"
    private var serverPort = 9000

    //需要進行通信的客戶端ip和port
    private var clientIP = ""
    private var clientPort = 1

    private var socketListener: SocketListener? = null

    init {
        try {
            //初始化一個socket, 并監(jiān)聽6000端口
            socket = DatagramSocket(6000)
            Log.d("socket", "init socket")
        } catch (e: SocketException) {
            e.printStackTrace()
            Log.d("socket", e.message)
        }
    }

    fun setSocketListener(socketListener: SocketListener) {
        this.socketListener = socketListener
    }

    fun sendPackData(messageBean: MessageBean, address: String, port: Int) {
        val packs = Gson().toJson(messageBean).toByteArray()
        try {
            socket.send(DatagramPacket(packs, packs.size, InetAddress.getByName(address), port))
            socketListener?.sendSocketData(messageBean.toString())
        } catch (io: IOException) {
            io.printStackTrace()
            Log.d("socket", io.message)
            socketListener?.error(io)
        }
    }

    override fun run() {
        super.run()
        Log.d("socket", "start run")

        try {
            while (true) {
                //接收數據
                val receiveBytes = ByteArray(1024)
                val packet = DatagramPacket(receiveBytes, receiveBytes.size)
                socket.receive(packet)

                //解析數據
                val receiveData = packet.data
                val json = String(Utils.subBytes(receiveData, 0, packet.length))
                val messageBean = Gson().fromJson(json, MessageBean::class.java)
                when (messageBean.protocol) {
                    //登陸結果
                    Cons.PROTOCOL_LOGIN_ACK -> socketListener?.receiveSocketData(messageBean.data)
                    //獲取在線設備結果
                    Cons.PROTOCOL_GET_ONLINE_ACK -> socketListener?.receiveSocketData(messageBean.data)
                    //請求連接結果
                    Cons.PROTOCOL_CONNECT_ACK -> socketListener?.receiveSocketData(messageBean.data)
                    else -> socketListener?.receiveSocketData(messageBean.data)
                }
            }
        } catch (se: SocketException) {
            se.printStackTrace()
            Log.d("socket", se.message)
            socketListener?.error(se)
        } catch (io: IOException) {
            io.printStackTrace()
            Log.d("socket", io.message)
            socketListener?.error(io)
        } finally {
            Log.d("socket", "close")
            socket.close()
        }

    }

    interface SocketListener {
        /**
         * 接收到的數據
         */
        fun receiveSocketData(socketData: String)

        /**
         * 發(fā)送數據
         */
        fun sendSocketData(packs: String)

        /**
         * 發(fā)生錯誤
         */
        fun error(e: Throwable)
    }
}

服務端代碼:

public class UdpServerThread extends Thread implements Runnable {


    // 數據報套接字
    private DatagramSocket datagramSocket;
    // 用以接收數據報
    private DatagramPacket datagramPacket;

    private Map<String, String> loginMap = new HashMap<>();

    public UdpServerThread() {
        try {
            datagramSocket = new DatagramSocket(9000);
            System.out.println("Server Start and listenering 9000");
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void run() {
        super.run();
        try {
            while (true){
                //接收數據包
                byte[] receiveData = new byte[1024];
                datagramPacket = new DatagramPacket(receiveData, receiveData.length);
                datagramSocket.receive(datagramPacket);
                String ip = ((InetSocketAddress)datagramPacket.getSocketAddress()).getAddress().getHostAddress();
                int port = datagramPacket.getPort();

                byte[] datas = datagramPacket.getData();
                String json = new String(Utils.subBytes(datas, 0, datagramPacket.getLength()));
                System.out.println(json);
                MessageBean messageBean = new Gson().fromJson(json, MessageBean.class);
                //登陸
                if (messageBean.getProtocol() == Cons.PROTOCOL_LOGIN){
                    boolean isLogin = false;
                    for (Map.Entry<String, String> entry : loginMap.entrySet()) {
                        if (Integer.valueOf(entry.getKey()) == messageBean.getId()){
                            isLogin = true;
                            break;
                        }
                    }
                    if (!isLogin){
                        //保存登陸信息
                        loginMap.put(String.valueOf(messageBean.getId()), ip + ":" + port);
                        String packs = new Gson().toJson(new MessageBean(0, Cons.PROTOCOL_LOGIN_ACK, "login success:" + messageBean.getId()));
                        sendPacketData(packs.getBytes(), ip, port);
                    }else{
                        String packs = new Gson().toJson(new MessageBean(0, Cons.PROTOCOL_LOGIN_ACK, "already login:" + messageBean.getId()));
                        sendPacketData(packs.getBytes(), ip, port);
                    }
                }else if (messageBean.getProtocol() == Cons.PROTOCOL_GET_ONLINE){
                    String clients = Utils.getMapToString(loginMap);
                    String packts = new Gson().toJson(new MessageBean(0, Cons.PROTOCOL_GET_ONLINE_ACK, clients));
                    sendPacketData(packts.getBytes(), ip, port);
                }
            }
        }catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 關閉socket
            if (datagramSocket != null) {
                datagramSocket.close();
            }
        }
    }

    private void sendPacketData(byte[] packs, String address, int port) {
        try {
            datagramSocket.send(new DatagramPacket(packs, packs.length, InetAddress.getByName(address), port));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容