Android中的Socket通信(UDP方式和TCP方式)

前言:在Android中,应用进程间的通信有很多种,包括Socket、AIDL、广播等,基于socket通讯的方式有两种,一个是TCP的方式,一种是UDP的方式,两种通讯方式各有特点。本篇文章带领大家看一下关于Socket通讯的实践过程(附源码demo)

一. TCP方式,主要分为以下几个步骤:

在这里插入图片描述

这边利用TCP方式做了一个简单的服务端 + 多客户端 (一对多),实现群聊的功能,效果如下:
服务端聊天记录:

在这里插入图片描述
客户端聊天记录:
在这里插入图片描述

服务端:

public class TcpServerActivity extends AppCompatActivity {
    private static final String TAG = "TcpServerActivity";
    Button sendBtn;
    EditText messageEdt;

    HandlerThread handlerThread;
    Handler handler;

    ServerSocket serverSocket;
    List<Socket> socketClients = new ArrayList<>();

    volatile boolean isStop = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcp_server);
        messageEdt = findViewById(R.id.message_edt);
        sendBtn = findViewById(R.id.message_send_btn);
        initListener();
        //server开启接受客户端的消息
        new ServerThread().start();

        //初始化handlerThread
        handlerThread = new HandlerThread("Thread-TcpServer");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
    }

    class ServerThread extends Thread {
        @Override
        public void run() {
            try {
                //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
                serverSocket = new ServerSocket(8888);
                //2.调用accept()等待客户端连接
                Log.d(TAG, "服务端" + IPUtils.getIPAddress(TcpServerActivity.this) + "已就绪,等待客户端接入.....");
                while (!isStop) {
                    if (null != serverSocket) {
                        Socket socket = serverSocket.accept();
                        //每次客户端连接后,新启一个线程
                        new ReceiveThread(socket).start();
                        //添加到socket集合中
                        socketClients.add(socket);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    class ReceiveThread extends Thread {
        private Socket socket;
        private BufferedReader bufferedReader;
        private BufferedWriter bufferedWriter;

        public ReceiveThread(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            super.run();
            String clientIP = socket.getInetAddress().getHostAddress();
            Log.d(TAG, "客户端" + clientIP + "已经上线---");
            //3.获取输出流,准备反馈信息给客户端
            try {
                String message = "新用户已经上线," + "目前聊天室人数为:" + socketClients.size();
                sendMessageToAllClient(message);
                //4.获取输入流,读取客户端信息
                bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
                String info = "";
                while ((info = bufferedReader.readLine()) != null) {
                    Log.d(TAG, "用户" + clientIP + "说:" + info);
                    if (info.contains("下线")) {
                        socketClients.remove(socket);
                    }
                    //需要把消息发给所有非当前用户的人
                    sendMessageToOtherClient(socket, info);
                }
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    //服务端主动发消息给客户端
    public void startSend(String text) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                sendMessageToAllClient(text);
                Log.d(TAG, "服务端" + IPUtils.getIPAddress(TcpServerActivity.this) + "说: " + text);
            }
        });
    }

    public void sendMessageToAllClient(String message) {
        BufferedWriter bufferedWriter = null;
        try {
            if (null != socketClients && socketClients.size() > 0) {
                for (Socket socket : socketClients) {
                    bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    bufferedWriter.write(message);
                    //切记一定要添加换行符,否则服务端无法读取到换行符,readLine一直在读
                    bufferedWriter.write("\n");
                    bufferedWriter.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void sendMessageToOtherClient(Socket currentSocket, String message) throws IOException {
        BufferedWriter bufferedWriter = null;
        if (null != socketClients && socketClients.size() > 0) {
            for (Socket socket : socketClients) {
                if (socket != currentSocket) {
                    bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    bufferedWriter.write(message);
                    //切记一定要添加换行符,否则服务端无法读取到换行符,readLine一直在读
                    bufferedWriter.write("\n");
                    bufferedWriter.flush();
                }
            }
        }

    }

    public void close() {
        try {
            if (null != socketClients && socketClients.size() > 0) {
                for (Socket socket : socketClients) {
                    //关闭socket
                    if (null != socket) {
                        socket.shutdownInput();
                        socket.shutdownOutput();
                        socket.close();
                        socket = null;
                    }
                }

            }
            //关闭serverSocket连接
            if (null != serverSocket) {
                serverSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * server发送消息给client
     */
    private void initListener() {
        sendBtn.setOnClickListener(view -> {
            String text = messageEdt.getText().toString().trim();
            if (!TextUtils.isEmpty(messageEdt.getText().toString().trim())) {
                Toast.makeText(this, "已发送!", Toast.LENGTH_SHORT).show();
                startSend(text);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "服务端已经退出啦!");
        close();
        isStop = true;

    }

}
客户端:

public class TcpClientActivity extends AppCompatActivity {
    private static final String TAG = "TcpClientActivity";
    Button sendBtn;
    EditText messageEdt;

    MyRunnable myRunnable;
    HandlerThread handlerThread;
    Handler handler;


    BufferedReader bufferedReader;
    BufferedWriter bufferedWriter;
    Socket socket;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcp_client2);
        messageEdt = findViewById(R.id.message_edt);
        sendBtn = findViewById(R.id.message_send_btn);
        initListener();
        myRunnable = new MyRunnable();
        new Thread(myRunnable).start();

        //初始化handlerThread
        handlerThread = new HandlerThread("Thread-TcpClient");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
    }

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            try {
                Log.d(TAG, "客户端尝试连接服务器---");
                //1.创建客户端Socket,指定服务器地址和端口
                socket = new Socket("10.5.212.203", 8888);
                if (null != socket) {
                    String serverAddress = socket.getInetAddress().getHostAddress();
                    String ip = IPUtils.getIPAddress(TcpClientActivity.this);
                    Log.d(TAG, "服务器连接成功,当前用户ip:" + ip + ",当前服务器ip:" + serverAddress);

                    //2.获取输出流,向服务器端发送信息表明已上线
                    bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    String message = "我来了";
                    Log.d(TAG, "我说:" + message);
                    sendMessageToServer(message);

                    //3.获取输入流,不断从服务器接收内容
                    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
                    String info = "";
                    while ((info = bufferedReader.readLine()) != null) {
                        Log.d(TAG, "服务端" + serverAddress + "说:" + info);
                    }
                    bufferedReader.close();
                } else {
                    Log.d(TAG, "TCP客户端连接服务器失败!");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    public void sendMessageToServer(String message) {
        try {
            bufferedWriter.write(message);
            //切记一定要添加换行符,否则服务端无法读取到换行符,readLine一直在读
            bufferedWriter.write("\n");
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void startSend(String text) {
        //在统一新的线程中发送,避免耗时异常,注意每次调用sendMessageToServer
        handler.post(new Runnable() {
            @Override
            public void run() {
                sendMessageToServer(text);
                Log.d(TAG, "我说:" + text);
            }
        });
    }

    public void close() {
        try {
            //关闭输入流连接
            if (null != bufferedReader) {
                bufferedReader.close();
            }
            //关闭输出流连接
            if (null != bufferedWriter) {
                bufferedWriter.close();
            }
            //关闭socket
            if (null != socket) {
                socket.shutdownInput();
                socket.shutdownOutput();
                socket.close();
                socket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * client发送消息给server
     */
    private void initListener() {
        sendBtn.setOnClickListener(view -> {
            if (!TextUtils.isEmpty(messageEdt.getText().toString().trim())) {
                Toast.makeText(this, "已发送!", Toast.LENGTH_SHORT).show();
                String text = messageEdt.getText().toString().trim();
                startSend(text);

            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        startSend("我下线了,拜拜!");
        close();
        Log.d(TAG, "我下线了,拜拜!");

    }

}

工具类:

public class IPUtils {

    public static String getIPAddress(Context context) {
        NetworkInfo info = ((ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
        if (info != null && info.isConnected()) {
            if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
                try {
                    //Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces();
                    for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                        NetworkInterface intf = en.nextElement();
                        for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                            InetAddress inetAddress = enumIpAddr.nextElement();
                            if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
                                return inetAddress.getHostAddress();
                            }
                        }
                    }
                } catch (SocketException e) {
                    e.printStackTrace();
                }

            } else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
                WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址
                return ipAddress;
            }
        } else {
            //当前无网络连接,请在设置中打开网络
        }
        return null;
    }

    /**
     * 将得到的int类型的IP转换为String类型
     *
     * @param ip
     * @return
     */
    public static String intIP2StringIP(int ip) {
        return (ip & 0xFF) + "." +
                ((ip >> 8) & 0xFF) + "." +
                ((ip >> 16) & 0xFF) + "." +
                (ip >> 24 & 0xFF);
    }
}


二:UDP方式:
发送方:

public class SendTest {
    private static InetAddress mAddress;
    private static DatagramSocket socket = null;
    private static String ip = "255.255.255.255"; //发送给整个局域网
    private static final int sendPort = 9999;  //发送方和接收方需要端口一致

    public static void SendUtils (final Context context, final String content) {
        //初始化socket
        try {
            socket = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        try {
            mAddress = InetAddress.getByName(ip);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        //创建线程发送信息
        new Thread() {
            private byte[] sendBuf;

            public void run() {
                try {
                    sendBuf = content.getBytes("utf-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                DatagramPacket recvPacket1 = new DatagramPacket(sendBuf, sendBuf.length, mAddress, sendPort);
                try {
                    socket.send(recvPacket1);
                    socket.close();
                    Log.e("zziafyc", "已将内容发送给了AIUI端内容为:" + content);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

接收端:

public class ReceiveTest {
    private DatagramSocket socket;
    private static final int PhonePort = 9999;//手机端口号
    private DatagramPacket packet;
    private volatile boolean stopReceiver;

    private void receiveMessage() {
        new Thread() {
            public void run() {
                try {
                    socket = new DatagramSocket(PhonePort);
                } catch (SocketException e) {
                    e.printStackTrace();
                }
                byte[] receBuf = new byte[1024];
                packet = new DatagramPacket(receBuf, receBuf.length);
                while (!stopReceiver) {
                    try {
                        socket.receive(packet);
                        String receive = new String(packet.getData(), 0, packet.getLength(), "utf-8");
                        Log.e("zziafyc", "收到的内容为:" + receive);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

边发送边接收:

public class SendAndReceiveTest {
    private static InetAddress mAddress;
    private static DatagramSocket socket = null;
    private static String ip = "255.255.255.255"; //发送给整个局域网
    private static int port = 8899;  //发送方和接收方需要端口一致

    public static void sendSearchGateWay(Context context, final String content, final String sid, int port) {
        //初始化socket
        try {
            socket = new DatagramSocket();
            //设置超时时间
            socket.setSoTimeout(5000);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        try {
            mAddress = InetAddress.getByName(ip);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //创建线程发送信息
        new Thread() {
            private byte[] sendBuf;

            public void run() {
                try {
                    sendBuf = content.getBytes("utf-8");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                DatagramPacket packet = new DatagramPacket(sendBuf, sendBuf.length, mAddress, port);
                try {
                    //已发送完成
                    socket.send(packet);
                    byte[] receive = new byte[1024];
                    DatagramPacket receivePacket = new DatagramPacket(receive, receive.length);
                    while (true) {
                        socket.receive(receivePacket);
                        String result = new String(receivePacket.getData(), 0, receivePacket.getLength(), "utf-8");
                        Log.d("result: ", result);
                        if (!TextUtils.isEmpty(result) && result.contains(sid)) {
                            break;
                        }
                    }
                } catch (SocketTimeoutException timeOutException) {
                    socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }.start();
    }
}


  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值