第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 安卓学习笔记40:基于套接字网络编程

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

时间:2022-12-11 01:35:33

相关推荐

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

文章目录

零、学习目标一、Socket概述(一)两种传输模式(二)基于Socket网络编程三、案例演示 - C/S架构聊天室(一)运行效果(二)涉及知识点(三)实现步骤1、创建聊天服务器端(1)创建Java项目 - ChatServer(2)创建聊天服务窗口类 - ChatServerWindow(3)启动应用,查看效果2、创建聊天安卓客户端(1)创建安卓应用【ChatAndroidClient】(2)将图片素材拷贝到drawable目录(3)创建接收按钮背景选择器(4)创建发送按钮背景选择器(5)主布局资源文件activity_main.xml(6)字符串资源文件strings.xml(7)在项目清单文件里授权访问因特网(8)主界面类 - MainActivity3、启动聊天服务器端与安卓客户端进行测试(1)启动聊天服务器端(2)启动聊天安卓客户端(3)演示服务器端与安卓客户端进行聊天

零、学习目标

了解基于套接字网络有两种传输模式掌握基于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

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 .ServerSocket;import .Socket;/*** 功能:聊天服务窗口类* 作者:华卫* 日期: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() {@Overridepublic 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)创建接收按钮背景选择器

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="/apk/res/android"><item android:drawable="@drawable/receive" android:state_pressed="false"/><item android:drawable="@drawable/receive_pressed" android:state_pressed="true"/></selector>

(4)创建发送按钮背景选择器

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="/apk/res/android"><item android:drawable="@drawable/send" android:state_pressed="false"/><item android:drawable="@drawable/send_pressed" android:state_pressed="true"/></selector>

(5)主布局资源文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/background"android:orientation="vertical"android:padding="10dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:id="@+id/tvHost"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/host"android:textColor="#0000ff"android:textSize="20sp" /><EditTextandroid:id="@+id/edtHost"android:layout_width="match_parent"android:layout_height="40dp"android:background="#ffffff"android:padding="5dp"android:singleLine="true"android:textColor="#000000"android:textSize="20sp" /></LinearLayout><Buttonandroid:id="@+id/btnReceiveMessage"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_marginBottom="10dp"android:background="@drawable/btn_receive_selector" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><EditTextandroid:id="@+id/edtMessage"android:layout_width="0dp"android:layout_height="40dp"android:layout_weight="4"android:hint="@string/input_message"android:paddingLeft="5dp"android:singleLine="true"android:textColor="#000000"android:textSize="20sp" /><Buttonandroid:id="@+id/btnSendMessage"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="5dp"android:layout_weight="1"android:background="@drawable/btn_send_selector"android:textSize="18sp" /></LinearLayout><EditTextandroid:id="@+id/edtMessageList"android:layout_width="match_parent"android:layout_height="match_parent"android:focusable="false"android:gravity="left|top"android:inputType="textMultiLine|none"android:scrollbars="vertical"android:textSize="18sp"><requestFocus /></EditText></LinearLayout>

(6)字符串资源文件strings.xml

<resources><string name="app_name">聊天安卓客户端</string><string name="host">服务器地址:</string><string name="input_message">请输入聊天内容</string></resources>

(7)在项目清单文件里授权访问因特网

(8)主界面类 - MainActivity

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 .Socket;import .UnknownHostException;/*** 功能:安卓聊天客户端* 作者:华卫* 日期: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;@Overrideprotected 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() {@Overridepublic void onClick(View v) {sendMessage(); // 发送消息}});// 给接收按钮注册监听器btnReceiveMessage.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {receiveMessage(); // 接收消息}});// 给消息编辑框注册监听器edtMessage.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_ENTER) {sendMessage(); // 收发消息}return false;}});// 创建消息处理器handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (msg.what == 0x001) {// 设置聊天信息列表内容edtMessageList.setText(chatMesssageBuilder.toString());// 清空输入框edtMessage.setText("");}}};}/*** 接收消息:接收来自服务器端的消息*/private void receiveMessage() {new Thread() {@Overridepublic 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() {@Overridepublic 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();}@Overrideprotected void onDestroy() {super.onDestroy();if (socket != null) {try {// 关闭套接字socket.close();} catch (Exception e) {System.out.println("异常:无法关闭Socket!");}}}}

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

(1)启动聊天服务器端

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

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。