Android——套接字Socket

Android——套接字Socket

一.网络地址InetAddress

检查设备自身与某个网络地址的连通性用到了InetAddress工具,这是对网络地址的一个封装。下面介绍该工具的主要方法说明。

  • getByName:根据主机IP或主机名称获取InetAddress对象。

  • getHostAddress:获取主机的IP地址。

  • getHostName:获取主机的名称。

  • isReachable:判断该地址是否可到达,即是否连通。

下面是检查网络地址能否连通的代码片段:
public void onClick(View v) {
     
        if (v.getId() == R.id.btn_host_name) {
       // 点击了“检查主机名”按钮
            // 启动主机检查线程
            new CheckThread(et_host_name.getText().toString()).start();
        }
    }

    // 创建一个检查结果的接收处理器
    private Handler mHandler = new Handler() {
     
        // 在收到结果消息时触发
        public void handleMessage(Message msg) {
     
            tv_host_name.setText("主机检查结果如下:\n" + msg.obj);
        }
    };

    // 定义一个主机检查线程
    private class CheckThread extends Thread {
     
        private String mHostName;  // 主机名称

        public CheckThread(String host_name) {
     
            mHostName = host_name;
        }

        public void run() {
     
            // 获得一个默认的消息对象
            Message message = Message.obtain();
            try {
     
                // 根据主机名称获得主机名称对象
                InetAddress host = InetAddress.getByName(mHostName);
                // 检查该主机在规定时间内能否连上
                boolean isReachable = host.isReachable(5000);
                String desc = (isReachable) ? "可以连接" : "无法连接";
                if (isReachable) {
       // 可以连接
                    desc = String.format("%s\n主机名为%s\n主机地址为%s",
                            desc, host.getHostName(), host.getHostAddress());
                }
                message.what = 0;  // 消息类型
                message.obj = desc;  // 消息描述
            } catch (Exception e) {
     
                e.printStackTrace();
                message.what = -1;  // 消息类型
                message.obj = e.getMessage();  // 消息描述
            }
            // 向接收处理器发送检查结果消息
            mHandler.sendMessage(message);
        }
    }

检查网络地址连通性的效果:

Android——套接字Socket_第1张图片

​ 检测域名的连通性结果图

Android——套接字Socket_第2张图片

​ 检测IP的连通性结果图

二.Socket通信

计算机网络有一个大名鼎鼎的TCP/IP协议,TCP/IP是一个协议组,分为3个层次:

  • 网络层:包括IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
  • 传输层:包括TCP协议和UDP协议。
  • 应用层:包括HTTP、FTP、TELNET、SMTP、DNS等协议

Socket属于传输层的技术, API实现TCP协议后即可用于HTTP通信,实现UDP协议后即可用于FTP通信,当然也可以直接在底层进行点对点通信。

Android的Socket编程主要使用Socket和ServerSocket两个类:

1.Scoket

Socket是最常用的工具,客户端和服务端都要用到,描述了两边对套接字(Socket)处理的一般行为。主要方法如下:

  • connect:连接指定IP和端口。该方法用于客户端连接服务端。
  • getInputStream:获取输入流,即自身收到对方发过来的数据。
  • getOutputStream:获取输入流,即自身向对方发送的数据。
  • getInetAddress:获取网络地址对象。
  • isConnected:判断socket是否连上。
  • isClosed:判断socket是否关闭。
  • close:关闭socket。

2.ServerSocket

ServerSocket仅用于服务端,在运行时不停地侦听指定端口。主要方法如下:

  • 构造函数:指定侦听哪个端口。
  • accept:开始接收客户端的连接。有客户端连上时就返回一个Socket对象,若要持续侦听连接,则在循环语句中调用该函数。
  • getInetAddress:获取网络地址对象。
  • isClosed:判断socket服务器是否关闭。
  • close:关闭socket服务器。

3.Scoket通信案例

举个Socket通信的案例,详细步骤说明如下:

(1)首先在客户端与服务端之间建立Socket连接。

(2)然后在Activity中启动Socket连接的线程,等待界面向Socket服务器发送消息,并准备接收消息。

(3)最后启动Socket服务器(其实一开始就要启动,这样App运行时才能马上连上后端服务器)。

下面是在客户端与服务端之间建立Socket连接的详细代码:

public class MessageTransmit implements Runnable {
     
    // 以下为Socket服务器的ip和端口,根据实际情况修改
    private static final String SOCKET_IP = "192.168.0.212";
    private static final int SOCKET_PORT = 51000;
    private BufferedReader mReader = null;  // 声明一个缓存读取器对象
    private OutputStream mWriter = null;  // 声明一个输出流对象

    @Override
    public void run() {
     
        // 创建一个套接字对象
        Socket socket = new Socket();
        try {
     
            // 命令套接字连接指定地址的指定端口
            socket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);
            // 根据套接字的输入流,构建缓存读取器
            mReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 获得套接字的输出流
            mWriter = socket.getOutputStream();
            // 启动一条子线程来读取服务器的返回数据
            new RecvThread().start();
            // 为当前线程初始化消息队列
            Looper.prepare();
            // 让线程的消息队列开始运行,之后就可以接收消息了
            Looper.loop();
        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }

    // 创建一个发送处理器对象,让App向后台服务器发送消息
    public Handler mSendHandler = new Handler() {
     
        // 在收到消息时触发
        public void handleMessage(Message msg) {
     
            // 换行符相当于回车键,表示我写好了发出去吧
            String send_msg = msg.obj.toString() + "\n";
            try {
     
                // 往输出流对象中写入数据
                mWriter.write(send_msg.getBytes("utf8"));
            } catch (Exception e) {
     
                e.printStackTrace();
            }
        }
    };

    // 定义消息接收子线程,让App从后台服务器接收消息
    private class RecvThread extends Thread {
     
        @Override
        public void run() {
     
            try {
     
                String content;
                // 读取到来自服务器的数据
                while ((content = mReader.readLine()) != null) {
     
                    // 获得一个默认的消息对象
                    Message msg = Message.obtain();
                    msg.obj = content;  // 消息描述
                    // 通知SocketActivity收到消息
                    SocketActivity.mHandler.sendMessage(msg);
                }
            } catch (Exception e) {
     
                e.printStackTrace();
            }
        }
    }
}

下面是等待界面向Socket服务器发送消息,并准备接收消息的页面代码:

public class SocketActivity extends AppCompatActivity implements OnClickListener {
     
    private EditText et_socket;
    private static TextView tv_socket;
    private MessageTransmit mTransmit;  // 声明一个消息传输对象

    protected void onCreate(Bundle savedInstanceState) {
     
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_socket);
        et_socket = findViewById(R.id.et_socket);
        tv_socket = findViewById(R.id.tv_socket);
        findViewById(R.id.btn_socket).setOnClickListener(this);
        mTransmit = new MessageTransmit();  // 创建一个消息传输
        new Thread(mTransmit).start();  // 启动消息传输线程
    }

    public void onClick(View v) {
     
        if (v.getId() == R.id.btn_socket) {
     
            // 获得一个默认的消息对象
            Message msg = Message.obtain();
            msg.obj = et_socket.getText().toString();  // 消息内容
            // 通过消息线程的发送处理器,向后端发送消息
            mTransmit.mSendHandler.sendMessage(msg);
        }
    }

    // 创建一个主线程的接收处理器,专门处理服务器发来的消息
    public static Handler mHandler = new Handler() {
     
        @Override
        public void handleMessage(Message msg) {
     
            if (tv_socket != null) {
     
                // 拼接服务器的应答字符串
                String desc = String.format("%s 收到服务器的应答消息:%s",
                        DateUtil.getNowTime(), msg.obj.toString());
                tv_socket.setText(desc);
            }
        }
    };
}

Socket通信的实现效果:

Android——套接字Socket_第3张图片

​ Socket消息发送前的界面

Android——套接字Socket_第4张图片

​ Socket消息发送后的界面

你可能感兴趣的:(Android——套接字Socket)