【达内课程】利用Socket实现群聊

2024-05-12 09:58
文章标签 实现 socket 课程 群聊

本文主要是介绍【达内课程】利用Socket实现群聊,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 思路
  • 实现

思路

【完成群聊天室】
服务端:
每当接收到客户端发来的消息后,需要给每一个在线的客户都输出一遍

List<Socket> sockets;main{socket= ss.accept();sockets.add(socket);new Thread(){run(){}}.start();
}

客户端:
建立连接、发送消息、接收并显示消息

注意:
网络编程注意事项:
1、所有网络操作都需要在工作线程中执行
2、网络操作需要添加权限

实现

按照以上思路完成服务端 ChatServer

public class ChatServer {private List<Socket> sockets = new ArrayList<Socket>();/*** 开启服务** @throws IOException*/public void startServer() throws IOException {System.out.println("服务已启动...");//启动服务ServerSocket ss = new ServerSocket(8888);//不断接收从客户端发来的消息while (true) {//阻塞执行,接收客户端连接Socket socket = ss.accept();sockets.add(socket);//想要并发处理的话,需要开启线程new WorkThread(socket).start();}}/*** 工作线程* 接收客户端的消息,并给每个线程发一遍*/class WorkThread extends Thread {private Socket socket;public WorkThread(Socket socket) {this.socket = socket;}public void run() {try {DataInputStream dis = new DataInputStream(socket.getInputStream());while (true) {String message = dis.readUTF();//给每一个客户端都发一遍for (int i = 0; i < sockets.size(); i++) {Socket s = sockets.get(i);DataOutputStream dos = new DataOutputStream(s.getOutputStream());dos.writeUTF(message);dos.flush();}}} catch (IOException e) {e.printStackTrace();//当开启一条线程后,线程会等待客户端发消息//在等待的过程中,可能出现异常,比如连接中断,就会抛出connection reset的异常//就会走到这里System.out.println("连接中断");//把当前socket对象从集合中移除sockets.remove(socket);}}}public static void main(String[] args) {ChatServer server = new ChatServer();try {server.startServer();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

布局文件activity_main

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:id="@+id/et_ip"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_toLeftOf="@+id/btn_ip" /><Buttonandroid:id="@+id/btn_ip"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:text="确定" /><ListViewandroid:id="@+id/listview"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@+id/btn_message"android:layout_below="@+id/btn_ip" /><Buttonandroid:id="@+id/btn_message"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_alignParentBottom="true"android:text="确定" /><EditTextandroid:id="@+id/et_message"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_toLeftOf="@+id/btn_message" />
</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private EditText et_ip;private EditText et_message;private Button btn_ip;private Button btn_message;private ListView listview;private Socket socket;private DataInputStream dis;private DataOutputStream dos;private List<String> messages = new ArrayList<>();private ArrayAdapter<String> adapter;private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case HANDLER_CONNECT_SUCCESS://连接成功Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();et_ip.setEnabled(false);btn_ip.setEnabled(false);break;case HANDLER_MESSAGE_RECEIVED://接受到消息String message = (String) msg.obj;messages.add("小明:" + message);//更新adapteradapter.notifyDataSetChanged();//显示最后一条listview.setSelection(messages.size() - 1);break;}}};private static final int HANDLER_CONNECT_SUCCESS = 1;private static final int HANDLER_MESSAGE_RECEIVED = 2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setViews();//设置适配器setAdapter();}private void setAdapter() {adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, messages);listview.setAdapter(adapter);}private void setViews() {et_ip = findViewById(R.id.et_ip);et_message = findViewById(R.id.et_message);btn_ip = findViewById(R.id.btn_ip);btn_message = findViewById(R.id.btn_message);listview = findViewById(R.id.listview);btn_ip.setOnClickListener(this);btn_message.setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.btn_ip://建立连接new Thread() {@Overridepublic void run() {try {connect();} catch (IOException e) {e.printStackTrace();//连接建立失败}}}.start();break;case R.id.btn_message://发送消息new Thread() {@Overridepublic void run() {try {sendMessage();} catch (IOException e) {e.printStackTrace();}}}.start();break;}}private void sendMessage() throws IOException {String text = et_message.getText().toString();dos.writeUTF(text);dos.flush();}/*** 读取服务端发回的消息的工作线程*/class ReadThread extends Thread {//run方法执行完毕后,线程也就销毁了//垃圾回收机制会回收@Overridepublic void run() {/*while (true){try {String message = dis.readUTF();} catch (IOException e) {e.printStackTrace();//当断开连接,并不会跳出while循环,所以改成以下写法}}*/try {while (true) {String message = dis.readUTF();Log.i("info", "message:" + message);//更新ListView,给handler发消息Message msg = new Message();msg.what = HANDLER_MESSAGE_RECEIVED;msg.obj = message;handler.sendMessage(msg);}} catch (IOException e) {e.printStackTrace();//连接异常,断开Log.e("error", "连接出错,读不了数据了,看着办吧");}}}private void connect() throws IOException {String ip = et_ip.getText().toString();socket = new Socket(ip, 8888);dis = new DataInputStream(socket.getInputStream());dos = new DataOutputStream(socket.getOutputStream());//连接成功,发消息给主线程Handler 更新UIhandler.sendEmptyMessage(HANDLER_CONNECT_SUCCESS);//启动读取消息的工作线程new ReadThread().start();}@Overrideprotected void onDestroy() {super.onDestroy();if (socket != null) {try {//socket关掉后,流也就关掉了//而客户端还有线程正等着读取数据,所以也需要处理下socket.close();} catch (IOException e) {e.printStackTrace();}}}
}

AndroidManifest增加权限

    <uses-permission android:name="android.permission.INTERNET"/>

运行步骤
1、用 IntelliJ IDEA 运行ChatServer
在这里插入图片描述

2、查看自己电脑 ip
cmd 中执行ipconfig
在这里插入图片描述

3、修改MainActivity中,以下代码,把 message 前增加一个称呼,例如“小明”,运行在一台模拟机中

private void sendMessage() throws IOException {String text = et_message.getText().toString();dos.writeUTF("小明:\n"+text);dos.flush();}

4、修改 MainActivity 中 3 步骤代码中的称呼,改为“小红”,运行在另一台模拟机中

5、都输入 ip 地址确保连接成功

5、开始尬聊

在这里插入图片描述

这篇关于【达内课程】利用Socket实现群聊的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/982310

相关文章

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3