请选择 进入手机版 | 继续访问电脑版

安卓学习笔记40:基于套接字网络编程

[复制链接]
钟启航 发表于 2021-1-2 12:13:13 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
文章目次



零、学习目的


  • 相识基于套接字网络有两种传输模式
  • 掌握基于TCP/IP协议的套接字网络编程
一、Socket概述

Socket(套接字)是一种通信机制,可以实现单机或跨网络举行通信,其创建需要明确的区分C(客户端)/S(服务器端),支持多个客户端毗连到同一个服务器。
(一)两种传输模式


  • 面向毗连的传输:基于TCP协议,可靠性高,但效率低
  • 面向无毗连的传输:基于UDP协议,可靠性低,但效率高
(二)基于Socket网络编程



  • 在安卓中,直接采取Socket通信应该是我们遇到的最低级的网络运用。只管已经作了很洪流平的抽象,但是纯粹的Socket通信,仍然给开辟者留下许多细节需要处置惩罚,尤其在服务器端,开辟者需要处置惩罚多线程以及数据缓冲等的设计问题。相对而言,处于更高抽象层的HTTP等,已经对Socket通信中需要处置惩罚的技能细节举行了很好的封装,开辟者无须关心,因此,HTTP在网络开辟中通常具有决定性的优势。
  • ServerSocket(int aport):创建一个绑定到本机指定端口的服务端Socket;aport就是指定的本机端口。与上述客户端Socket对应,通过TCP毗连时,ServerSocket创建后需要在aport端口上举行监听,等候客户端的毗连。
三、案例演示 - C/S架构谈天室

(一)运行效果


(二)涉及知识点


  • Swing窗口(JFrame)
  • Swing文本区(JTextArea)
  • Swing按钮(JButton)
  • Java事件处置惩罚机制
  • 数据字节输入流(DataInputStream)
  • 数据字节输出流(DataOutputStream)
  • 运动窗口(Activity)
  • 标签(TextView)
  • 按钮(Button)
  • 编辑框(EditText)
  • 服务器套接字(ServerSocket)
  • 套接字(Socket)
  • 消息处置惩罚器(Handler)
  • 线程(Thread)
(三)实现步调

1、创建谈天服务器端

(1)创建Java项目 - ChatServer


(2)创建谈天服务窗口类 - ChatServerWindow


  1. package net.hw.chat;import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** * 功能:谈天服务窗口类 * 作者:华卫 * 日期:2021年01月01日 */public class ChatServerWindow extends JFrame {    /**     * 界说端标语常量     */    static final int PORT = 8888;    private JButton btnClose;    private JButton btnSend;    /**     * 数据输入流     */    private DataInputStream netIn;    /**     * 数据输出流     */    private DataOutputStream netOut;    private JScrollPane panContent;    private JScrollPane panInput;    private JPanel panel1;    private JPanel panel2;    /**     * 服务器端套接字     */    private static ServerSocket ss;    /**     * 客户端套接字     */    private static Socket socket;    /**     * 谈天信息列表     */    private JTextArea txtChatMessageList;    /**     * 谈天信息输入框     */    private JTextArea txtInputMessage;    /**     * 来自客户端的消息     */    private static String clientMsg;    /**     * 服务器端的消息     */    private static String serverMsg;    /**     * 线程循环控制变量     */    private static boolean isRunning;    public static void main(String[] args) {        new ChatServerWindow();    }    /**     * 构造方法     */    public ChatServerWindow() {        super("谈天服务器端");        initUI();        try {            // 创建服务器端套接字            ss = new ServerSocket(PORT);            txtChatMessageList.append("服务器已启动...\n");            txtChatMessageList.append("等候客户请求...\n");            isRunning = true;            new Thread(new Runnable() {                @Override                public void run() {                    while (isRunning) {                        try {                            // 监听别的设备的毗连请求,处于阻塞状态                            socket = ss.accept();                            if (!txtChatMessageList.getText().toString()                                    .contains("毗连了一个客户端。")) {                                txtChatMessageList.append("毗连了一个客户端。\n");                            }                            netIn = new DataInputStream(socket.getInputStream());                            netOut = new DataOutputStream(socket                                    .getOutputStream());                            // 初始化服务器端消息                            if (null == serverMsg || serverMsg.equals("")) {                                serverMsg = "接待您,新朋侪! ";                            }                            // 获取输出流(套接字输出流-->数据输出流)                            netOut = new DataOutputStream(socket                                    .getOutputStream());                            // 向客户端输出信息                            netOut.writeUTF(serverMsg);                            // 清空输出流缓冲数据                            netOut.flush();                            // 获取客户端消息                            displayClientMsg();                        } catch (IOException e) {                        }                    }                }            }).start();        } catch (IOException e1) {        }        /* 给各个控件注册监听器,编写事件代码 */        btnSend.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent e) {                try {                    serverMsg = txtInputMessage.getText();                    if (!serverMsg.trim().equals("")) {                        txtChatMessageList.append("服务器>>>" + serverMsg + "\n");                        if (netOut != null) {                            netOut.writeUTF(serverMsg);                        }                    } else {                        JOptionPane.showMessageDialog(null, "不能发送空信息!", "服务器",                                JOptionPane.WARNING_MESSAGE);                    }                    txtInputMessage.setText("");                    txtInputMessage.requestFocus();                } catch (IOException ie) {                }            }        });        // 给关闭按钮注册监听器        btnClose.addActionListener(new ActionListener() {            public void actionPerformed(ActionEvent arg0) {                releaseResource();                System.exit(0);            }        });        // 给窗口注册监听器        addWindowListener(new WindowAdapter() {            public void windowActivated(WindowEvent e) {                txtInputMessage.requestFocus();            }            public void windowClosing(WindowEvent e) {                releaseResource();                System.exit(0);            }        });    }    /**     * 释放资源     */    private void releaseResource() {        isRunning = false;        try {            if (netIn != null && netOut != null) {                netIn.close();                netOut.close();            }            if (socket != null && !socket.isClosed()) {                socket.close();            }            if (ss != null && !ss.isClosed()) {                ss.close();            }        } catch (IOException e) {        }    }    /**     * 初始化用户界面     */    private void initUI() {        // 创建组件        panel1 = new JPanel();        panel2 = new JPanel();        txtChatMessageList = new JTextArea(15, 60);        txtInputMessage = new JTextArea(3, 60);        panContent = new JScrollPane(txtChatMessageList,                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);        panInput = new JScrollPane(txtInputMessage,                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);        btnClose = new JButton("关闭");        btnSend = new JButton("发送");        // 添加组件        getContentPane().add(panContent, "Center");        getContentPane().add(panel1, "South");        panel1.setLayout(new GridLayout(0, 1));        panel1.add(panInput);        panel1.add(panel2);        panel2.add(btnSend);        panel2.add(btnClose);        // 设置组件属性        txtChatMessageList.setEditable(false);        txtChatMessageList.setFont(new Font("宋体", Font.PLAIN, 13));        txtInputMessage.setFont(new Font("宋体", Font.PLAIN, 15));        txtChatMessageList.setLineWrap(true);        txtInputMessage.setLineWrap(true);        txtInputMessage.requestFocus();        setSize(450, 350);        setLocation(50, 200);        setResizable(false);        setLocationRelativeTo(null);        setVisible(true);    }    // 显示客户端信息    void displayClientMsg() {        try {            clientMsg = netIn.readUTF();            txtChatMessageList.append("客户端>>>" + clientMsg + "\n");        } catch (IOException e) {        }    }}
复制代码
(3)启动应用,检察效果



2、创建谈天安卓客户端

(1)创建安卓应用【ChatAndroidClient】



(2)将图片素材拷贝到drawable目次


(3)创建吸收按钮配景选择器


  1.         
复制代码
(4)创建发送按钮配景选择器


  1.         
复制代码
(5)主结构资源文件activity_main.xml


  1.                                                                     
复制代码
(6)字符串资源文件strings.xml


  1.     谈天安卓客户端    服务器所在:    请输入谈天内容
复制代码
(7)在项目清单文件里授权访问因特网


(8)主界面类 - MainActivity


  1. package net.hw.chat_android_client;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.KeyEvent;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.Socket;import java.net.UnknownHostException;/** * 功能:安卓谈天客户端 * 作者:华卫 * 日期:2021年01月01日 */public class MainActivity extends AppCompatActivity {    /**     * 发送信息按钮     */    private Button btnSendMessage;    /**     * 吸收信息按钮     */    private Button btnReceiveMessage;    /**     * 消息编辑框     */    private EditText edtMessage;    /**     * 客户端套接字     */    private Socket socket;    /**     * 消息处置惩罚器(发送与处置惩罚消息)     */    private Handler handler;    /**     * 服务器端标语     */    private static final int PORT = 8888;    /**     * 服务器端主机所在     */    private String host;    /**     * 初始化网络毗连的线程     */    private Thread initNetworkThread;    /**     * 谈天消息构建器     */    private StringBuilder chatMesssageBuilder;    /**     * 谈天信息列表编辑框     */    private EditText edtMessageList;    /**     * 服务器所在     */    private EditText edtHost;    /**     * 数据输出流     */    private static DataOutputStream netOut;    /**     * 数据输入流     */    private static DataInputStream netIn;    /**     * 来自客户端的消息     */    private static String clientMsg;    /**     * 服务器端的消息     */    private static String serverMsg;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 使用结构资源文件设置用户界面        setContentView(R.layout.activity_main);        // 通过资源索引得到界面控件实例        btnSendMessage = findViewById(R.id.btnSendMessage);        btnReceiveMessage = findViewById(R.id.btnReceiveMessage);        edtMessage = findViewById(R.id.edtMessage);        edtMessageList = findViewById(R.id.edtMessageList);        edtHost = findViewById(R.id.edtHost);        // 设置服务器所在        edtHost.setText("192.168.1.5");        // 实例化谈天消息构建器        chatMesssageBuilder = new StringBuilder();        // 给发送按钮注册监听器        btnSendMessage.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                sendMessage(); // 发送消息            }        });        // 给吸收按钮注册监听器        btnReceiveMessage.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                receiveMessage(); // 吸收消息            }        });        // 给消息编辑框注册监听器        edtMessage.setOnKeyListener(new View.OnKeyListener() {            @Override            public boolean onKey(View v, int keyCode, KeyEvent event) {                if (keyCode == KeyEvent.KEYCODE_ENTER) {                    sendMessage(); // 收发消息                }                return false;            }        });        // 创建消息处置惩罚器        handler = new Handler() {            @Override            public void handleMessage(Message msg) {                super.handleMessage(msg);                if (msg.what == 0x001) {                    // 设置谈天信息列表内容                    edtMessageList.setText(chatMesssageBuilder.toString());                    // 清空输入框                    edtMessage.setText("");                }            }        };    }    /**     * 吸收消息:吸收来自服务器端的消息     */    private void receiveMessage() {        new Thread() {            @Override            public void run() {                // 获取主机                host = edtHost.getText().toString();                // 非空校验                if (host.length() == 0) {                    Toast.makeText(MainActivity.this, "请输入服务器所在!", Toast.LENGTH_LONG);                    return;                }                // 采取短毗连,吸收一次消息,立马断开毗连                try {                    // 创建客户端套接字                    socket = new Socket(host, PORT);                    // 吸收服务器端发送的消息                    netIn = new DataInputStream(socket.getInputStream());                    // 从数据输入流读取内容                    serverMsg = netIn.readUTF();                    // 在谈天信息列表里添加服务器端的信息                    chatMesssageBuilder.append("服务器>>>" + serverMsg + "\n");                    // 发送消息                    handler.sendEmptyMessage(0x001);                    // 关闭输入流                    netIn.close();                    // 关闭客户端套接字                    socket.close();                } catch (UnknownHostException e) {                    Toast.makeText(MainActivity.this, "未知的主机异常!",                            Toast.LENGTH_LONG).show();                } catch (IOException e) {                    Toast.makeText(MainActivity.this, "输入输出异常!",                            Toast.LENGTH_LONG).show();                }            }        }.start();    }    /**     * 发送消息:向服务器端发送消息     */    private void sendMessage() {        // 启动子线程,执行发送谈天内容        new Thread() {            @Override            public void run() {                // 获取主机                host = edtHost.getText().toString();                // 非空校验                if (host.length() == 0) {                    Toast.makeText(MainActivity.this, "请输入服务器所在!",                            Toast.LENGTH_LONG);                    return;                }                // 采取短毗连,发送一次消息,立马断开毗连                try {                    // 创建客户端套接字                    socket = new Socket(host, PORT);                    // 向服务器端发送信息                    netOut = new DataOutputStream(socket.getOutputStream());                    // 获取客户端消息                    clientMsg = edtMessage.getText().toString();                    // 不允许发送空消息给服务器端                    if (clientMsg.length() == 0) {                        return;                    }                    // 向服务器端发送消息                    netOut.writeUTF(clientMsg);                    // 清空输出流缓冲数据                    netOut.flush();                    // 添加客户端信息                    chatMesssageBuilder.append("客户端>>>" + clientMsg + "\n");                    // 发送消息                    handler.sendEmptyMessage(0x001);                    // 关闭输出流                    netOut.close();                    // 关闭客户端套接字                    socket.close();                } catch (UnknownHostException e) {                    Toast.makeText(MainActivity.this, "未知的主机异常!",                            Toast.LENGTH_LONG).show();                } catch (IOException e) {                    Toast.makeText(MainActivity.this, "输入输出异常!",                            Toast.LENGTH_LONG).show();                }            }        }.start();    }    @Override    protected void onDestroy() {        super.onDestroy();        if (socket != null) {            try {                // 关闭套接字                socket.close();            } catch (Exception e) {                System.out.println("异常:无法关闭Socket!");            }        }    }}
复制代码


3、启动谈天服务器端与安卓客户端举行测试

(1)启动谈天服务器端


(2)启动谈天安卓客户端


(3)演示服务器端与安卓客户端举行谈天




来源:https://blog.csdn.net/howard2005/article/details/112058138
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )