IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android网络聊天室实现过程中遇到的问题及解决 -> 正文阅读

[移动开发]Android网络聊天室实现过程中遇到的问题及解决

Android网络聊天室实现过程中遇到的问题及解决

服务器端

  • 思路
  1. 创建服务器,绑定端口号
  2. while(true)无限循环不断接收客户端的连接请求
  3. 将各个客户端对应的socket添加到集合,方便统一管理
  4. 为各个客户端的socket开启子线程,实现通信(接收,转发)
  • 结构
    在eclipse中创建两个类:Server—对应服务器;ServerThread—对应子线程,重写run()方法,实现接收和转发

源码

  • Server.java
public class Server {
	private static List<Socket> socket_list = new LinkedList<>();

	public static void main(String[] args) {
		try (
				ServerSocket server = new ServerSocket(8888);
				) {
				//使用try with resources确保出现异常时服务器的关闭
			try {
				String hostAddress = InetAddress.getLocalHost().getHostAddress();
				System.out.println("服务器 " + hostAddress + " 已就绪");
				while (true) {
					Socket socket = server.accept();
					//接收客户端的请求
					socket_list.add(socket);
					//添加到集合
					System.out.println("ip: " + socket.getInetAddress().getHostAddress() + " 加入聊天室");
					new Thread(new ServerThread(socket, socket_list)).start();
					//开启线程
				}
			} catch (UnknownHostException e) {
				System.out.println("找不到主机名称");
				e.printStackTrace();
			}
		} catch (IOException e) {
			System.out.println("服务器端口已被占用,无法建立服务器");
			e.printStackTrace();
		}
	}
}
  • ServerThread.java
public class ServerThread implements Runnable {
	private List<Socket> socket_list = new LinkedList<>();
	private Socket mSocket = null;

	public ServerThread(Socket socket, List<Socket> list) {
		this.mSocket = socket;
		socket_list = list;
		//拿到socket的集合,为转发做基础
	}

	@Override
	public void run() {
	//try with resources确保流的关闭
		try (
				BufferedReader br = new BufferedReader(
						new InputStreamReader(mSocket.getInputStream()));
						//读取文本信息,考虑可以用BufferedReader的readLine()方法读取到换行符
				PrintStream ps = new PrintStream(
						new FileOutputStream("chatting records", true));
						//写出到服务器的文件,做记录
						//println()可以直接写出换行符
		) {
			String content = null;
			while(true) {
				
				while ((content = br.readLine()) != null) {
					
					ps.println(content);				
					System.out.println(content);

					Iterator<Socket> it = socket_list.iterator();
					//使用迭代器,获得每一个socket对象
					while (it.hasNext()) {
						Socket socket = it.next();
						if (socket != mSocket) {
						//自己不需要接收自己的消息
							try {
								PrintStream tps = new PrintStream(socket.getOutputStream());
								tps.println(content);
							} catch (IOException e) {
							//创建流对象失败,意味着此socket已关闭,客户端已下线,直接在集合中移除
								it.remove();
							}
						}
					}
				}
			}
		} catch (IOException e) {
			System.out.println("客户端已断开连接");
			socket_list.remove(mSocket);
			System.out.println("ip: " + mSocket.getInetAddress().getHostAddress() + " 退出了聊天室");
		}
	}
}

重点内容

  • 客户端之间的通信
    服务端接收客户端消息,向客户端发送消息我们在Java网络编程已经有了相关基础.那么我们是怎么实现客户端之间的通信的呢?
    我们可以在服务端创建一个LinkedList集合,将所有与客户端相连接的socket保存起来,在接收到一个socket发送过来的信息后,使用迭代器逐个获取所有的socket对象,一一向每一个socket发送信息,这样就实现了客户端之间的通信

客户端

  • 思路
  1. 登录页面,输入用户名,与服务器建立连接
  2. 聊天页面,接收信息,发送信息,UI更新等操作
  3. 考虑到多个页面都会用到socket,BufferedReader等,创建BaseActivity方便变量访问
    BaseActivity内容
public class BaseActivity extends AppCompatActivity {
    public static Socket socket;
    public static BufferedReader br;
    public static BufferedWriter bw;

    private NotNetworkReceiver receiver;

    public void notNetworkBroadcast(){
        Intent intent = new Intent("com.example.chatroom.NOTNETWORK");
        sendBroadcast(intent);
        //发送广播
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.chatroom.NOTNETWORK");
        receiver = new NotNetworkReceiver();
        registerReceiver(receiver, intentFilter);
        //动态注册广播
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(receiver != null){
            unregisterReceiver(receiver);
            receiver = null;
        }
        //注销广播
    }

    private class NotNetworkReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "无连接,请检查您的网络", Toast.LENGTH_SHORT).show();
        }
    }
}
  • 重点内容
  1. 权限申请
    要与服务器建立连接,需要首先在Manifest获取权限,
    在Manifest中添加
<uses-permission android:name="android.permission.INTERNET" />
  1. 与服务器建立连接
new Thread(new Runnable() {
                       @Override
                       public void run() {
                           try {
                               BaseActivity.socket = new Socket("192.168.1.126", 8888);
                               //a.建立与服务器连接
                               BaseActivity.br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                               BaseActivity.bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                               ChatActivity.actionStart(LoginActivity.this, userName);
                               finish();
                           } catch (IOException e) {
                               notNetworkBroadcast();
                               //b.发送广播,通过广播接收器显示Toast
                               e.printStackTrace();
                           }
                       }

a. 在Android中,Socket socket = new Socket();需要放在子线程中进行,所以为其开启线程.
b. 与socket不同,Toast只能在主线程中显示,因此用广播来实现Toas显示
3. UI更新
与Toast相同,Ui的更新操作也只能在主线程中操作,但是我们客户端的接收和发送信息肯定是会开启子线程的,那么该如何进行编写?
有两种方法:1.使用Handle完成UI更新;
2.使用runOnUiThread()完成更新,这里我使用的第二种

runOnUiThread(new Runnable() {
                               @Override
                               public void run() {
                                   adapter.notifyDataSetChanged();
                                   //消息更新
                                   msgRecycleView.scrollToPosition(msgList.size() - 1);
                                   //显示最后一行,即最新消息
                               }
                           });

对了,在更新UI之前,记得要将消息列表进行更新,就像这样.

msgList.add(new Msg(content, Msg.TYPE_RECIVED));
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-10 13:32:03  更:2021-08-10 13:32:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 23:11:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码