【Android】Socket實現簡易聊天室功能

2021-01-17 書客創作

人的一生總要去書寫許多不知結局的故事。有的故事可以順利完成,而有的故事或許將永遠都是一種殘缺。完美的結局是我們搏擊風雨的見證,也是我們永久的期待,然而生活並不像我們所想像的那樣美好,既然有年輕,也必然有衰老。

簡易聊天室,什麼是聊天室呢,簡單一點說就是一些人可以共同聊天,別人能夠看見你發布的消息,你也可以看到別人的消息,大家的消息是公開的。

功能分析:

1、聊天功能,聊天是一個長時間的相互交互的過程,要實現長時間連接Socket是一個比較不錯的選擇。

2、一些人相互聊天功能,要想實現相互聊天,就要將消息轉發給所有建立連接的人,這裡就要進行消息轉發。

實現思路:

利用Socket實現客戶端和服務端長連接,每次將連接進來的Socket保存到一個集合當中,當其中一個Socket有接收到數據的時候,將接收到的數據轉發給其他的Socket,這樣既能實現聊天功能又能實現轉發。

對Socket的操作應放在子線程當中,每一次有新的Socket連接進來之後就新開一個子線程。

如果對Socket不是很了解,推薦【JavaEE】Socket簡單體驗, TCP和UDP這篇文章進行了解。

服務端搭建

首先要實現監聽客戶端連接,需要利用ServerSocket的accept方法進行監聽,但是該方法會將程序阻塞,所以該監聽過程要放在子線程中完成。這裡定義的線程為ServerListener。

其次每監聽到一個Socket,Socket無論是獲取還是傳輸過程都是對字節流進行操作,這是一個比較耗時的操作,所以也要放在子線程中操作。這裡定義的線程為ChatSocket。

最後還要定義一個Socket的子線程管理類,方便對所有連接進來的Socket的子線程進行管理,例如對數據的轉發。這裡定義的管理類為ChatManager。

在程序最開始運行的時候,要開啟對Socket連接的監聽,所以在main方法中開始監聽線程。

public static void main(String[] args) { // 開啟服務端監聽 new ServerListener().start(); }

開啟監聽線程之後,當監聽到有Socket進行連接的時候,不僅要新建一個子線程實現該Socket的操作,而且要把該Socket添加到Socket線程管理類ChatManager當中,方便後期管理。

public class ServerListener extends Thread { @Override public void run() { try { // 1、創建ServerScoket,設置埠 ServerSocket serverSocket = new ServerSocket(12345); while (true) { // 2、accept方法將導致程序阻塞 Socket socket = serverSocket.accept(); JOptionPane.showMessageDialog(null, "有客戶端連接到本機的12345埠"); // 3、將socket傳遞給新線程 ChatSocket cs = new ChatSocket(socket); cs.start(); // 4、使用Chatmanager進行管理 ChatManager.getInstance().add(cs); } } catch (IOException e) {e.printStackTrace();} } }

在ChatSocket新線程中,要實現對接收到的Socket進行處理,例如獲取Socket客戶端發送過來的數據進行轉發等。而轉發過程,是轉發給所有連接進來的Socket,所以轉發過程的實現將由ChatManager完成。

ChatSocket在一開啟線程的時候,就要進行客戶端數據獲取,並轉發。

ChatSocket要能夠完成服務端想客戶端發送數據的過程。

public class ChatSocket extends Thread { private Socket socket; public ChatSocket(Socket socket) { this.socket = socket; } // 服務端傳值給客戶端 public void out(String out) { try { if (socket.isConnected() && !socket.isClosed()) { // 獲取當前Socket輸出流,輸出數據 socket.getOutputStream().write(out.getBytes("gbk")); System.out.println("轉發數據**********" + out); } else { // 連結已關閉 ChatManager.getInstance().remove(this); } } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { if (socket.isConnected() && !socket.isClosed()) { // 接受客戶端數據 BufferedReader br = new BufferedReader(new InputStreamReader( socket.getInputStream(), "gbk")); // 讀取數據 String line = null; while ((line = br.readLine()) != null) { // 轉發數據 ChatManager.getInstance().publish(this, line); System.out.println("接受數據******" + line); } br.close(); } else { // 連結已關閉 ChatManager.getInstance().remove(this); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }

最後來說說Socket線程管理類ChatManager,一個聊天室只能有一個Socket線程管理類,所以該類要使用單例模式。

private static ChatManager cm; // 單例 public static ChatManager getInstance() { if (cm == null) { cm = new ChatManager(); } return cm; }

提供Socket子線程存放集合,能夠實現Socket子線程添加和移除功能。

// ChatSocket集合 Vector vector = new Vector(); // 添加ChatSocket public void add(ChatSocket chatSocket) { vector.add(chatSocket); } // 移除ChatSocket public void remove(ChatSocket chatSocket) { vector.remove(chatSocket); }

最後是藉助Socket子線程存放集合,實現數據轉發功能。

// 發送消息 public void publish(ChatSocket cs, String out) { for (int i = 0; i

Android端搭建

對於Android客戶端而言就顯得稍微簡單一些,只需要實現數據的接受和傳遞即可。

首先是界面的構建:

客戶端界面當點擊連接的時候,客戶端會向服務端發送連接請求,請求成功之後便可發送消息,聊天內容將會在界面中間部分顯示。

1、初始化信息,在Activity中完成對控制項的初始化和點擊事件監聽。

// 定義控制項全局變量 private TextView ipTv, contentTv; private Button linkBtn, sendBtn; private EditText sendEd; // 初始化控制項 private void initView() { ipTv = (TextView) findViewById(R.id.tv_ip); contentTv = (TextView) findViewById(R.id.tv_content); linkBtn = (Button) findViewById(R.id.btn_link); linkBtn.setOnClickListener(this); sendBtn = (Button) findViewById(R.id.btn_send); sendBtn.setOnClickListener(this); sendEd = (EditText) findViewById(R.id.ed_send); } // 點擊事件監聽 @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_link:// 連結 connect(); break; case R.id.btn_send:// 發送 send(); break; } }

2、連接服務端,並獲取服務端傳遞數據。

// 定義三個全局變量 private Socket socket; private BufferedReader reader; private BufferedWriter writer; // 連接Socket服務端 private void connect() { final String ip = ipTv.getText().toString().trim(); final int port = 12345; // 異步執行 AsyncTask asyncTask = new AsyncTask() { @Override protected Void doInBackground(Void... params) { try { // 實例化Socket socket = new Socket(ip, port); reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); publishProgress("success"); // 讀取傳遞過來的數據 String line; while ((line = reader.readLine()) != null) { publishProgress(line); } } catch (IOException e) { publishProgress("failed"); e.printStackTrace(); } return null; } @Override protected void onProgressUpdate(String... values) { if ("success".equals(values[0])) Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_LONG).show(); else if ("failed".equals(values[0])) Toast.makeText(MainActivity.this, "無法建立連接", Toast.LENGTH_LONG).show(); else contentTv.append("他說:" + values[0] + "\n"); super.onProgressUpdate(values); } }; asyncTask.execute(); }

注意連接服務端和都去服務端數據是一個耗時的操作,所以應放在子線程中完成,這裡是採用異步AsyncTask的方式來進行處理。

3、發送數據

// 向Socket服務端發送 private void send() { String out = sendEd.getText().toString().trim(); // 發送數據 try { writer.write(out + "\n"); writer.flush(); sendEd.setText(""); contentTv.append("我說:" + out + "\n"); } catch (IOException e) { e.printStackTrace(); } }

到這裡就已經全部完成了,包括服務端和Android客戶端的實現,在實際開發當中往往是通過構建一些比較成熟的框架來實現這一過程,實現原理大致相同,實現過程有所不同。

Github後臺代碼地址[https://github.com/zrunker/SocketChatRoomDemo]

Github安卓客戶端代碼地址[https://github.com/zrunker/MySocketClient]

相關焦點

  • Node.JS和Socket.io入門
    安裝所有必需的模塊express:npm install express --saveSocket.io: npm install socket.io在server.js中:更換:app.listen(port); 為:var io = require('socket.io').listen(app.listen(port));這使Socket.io可以訪問伺服器
  • Android Studio基礎-選項菜單Java實現實例
    使用觸控螢幕無法調用此功能。 Android提供了兩種創建菜單的方法,一種是在java代碼中創建,另一種是使用xml資源文件定義 一、效果圖:
  • 在Android 中,使用簡單的幾行代碼實現複雜、漂亮的動畫
    要使用比較複雜、漂亮的動畫,使用 Android API 就比較難以實現了,或者說需要花更多的時間,往往還達不到理想中的視覺效果。比如,如下動畫的實現該動畫效果來自 lottie 官方。這個動畫如果使用幀動畫來實現,很可能就會出現 oom。這個動畫複雜在哪?
  • Socket網絡編程核心API深入分析(一):bind函數
    本文轉載自【微信公眾號:小碼逆襲,ID:gh_7c5a039380a0】經微信公眾號授權轉載,如需轉載與原文作者聯繫本篇文章你能學到:1、實現簡單的c++版本的伺服器和客戶端2、深入理解bind注意:本片文章涉及到的內核源碼來自linux內核版本3.6簡單的伺服器與客戶端實現本篇文章的重點在於從底層深入分析bind()函數,相信已經能夠自己實現一個簡單的伺服器和客戶端並進行交互,下面是一個簡單的demo,幫助大家複習一下socket編程api的調用過程。
  • Linux進程間通信的socketpair()函數
    Linux的socketpair()函數,是創建一對互相連接著的socket描述符。類似TCP連接,兩個文件描述符都可以讀寫,sv[0]寫入的數據在sv[1]讀出,sv[1]寫入的數據在sv[0]讀出。
  • Linux使用epoll控制多個socket發送http請求
    在客戶端使用epoll控制多個socket發送數據,與在伺服器上是類似的,也是把一個連續的同步過程拆成多個非阻塞的階段,在一個線程內實現高並發,而不是開多個線程。客戶端使用多個socket異步高並發,一般是對伺服器做壓力測試的代碼。
  • 一文教你如何利用NIO搭建一個簡單版的聊天室
    SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 10086));socketChannel.configureBlocking(false);selector =
  • easyswoole安裝完整教程及搭建簡易聊天室
    vim /usr/local/php/etc/php.ini##增加swoole擴展extension=swoole.so##service php-fpm restart #php重啟#獲取聊天室代碼
  • 登錄功能
    一、前言很多的應用程式都有登錄功能模塊,這裡的登錄註冊功能只是簡單地模擬了登錄註冊的過程,並沒有真正的發送簡訊、接收簡訊的功能。如果想要實現這樣的功能,就需要藉助第三方平臺,比如Bomb。二、界面截圖登錄界面在該界面只要輸入了用戶名和密碼,再點擊登錄就能進入到主界面。
  • 愛奇藝首創框內「聊天室」 用戶追劇開啟「邊看邊聊...
    1月4日,該劇在VIP會員收官當天迎來了主創李現、李一桐」空降」愛奇藝全網首創的框內「聊天室「,與用戶一起邊看邊聊實時互動,平均每分鐘的互動消息數超500條,引爆用戶互動熱情。愛奇藝通過拉起聊天浮層打造聊天室的形式,實現用戶「邊看邊聊」的實時互動需求,創新框內互動玩法。
  • 網易雲信聯手配音秀,打造語音聊天室互動新體驗
    除此之外,語音聊天室、在線pia戲、圈子和社團等功能為用戶提供了豐富的在線互動空間。在眾多功能模塊中,語音聊天室是最受用戶喜愛的模塊之一。用戶可自行創建聊天室,成為房主,邀請好友或陌生人加入暢聊;也可加入自己感興趣的聊天室,參與連麥或進行文字互動。
  • Android集成環信IM,實現聊天置頂的功能
    當我們的app中有集成環信即時通信SDK時,我們需要實現這樣一個功能,將某一個好友的聊天設置為置頂,這樣不管你當前正在跟多少好友聊天,該好友的消息始終都會出現在第一個回話列表中,這類似於微信的置頂功能。
  • 駭極乾貨|第2期:Android日誌系統分析
    Liblog提供的接口實現在logd_write.c文件中,它的位置如下:其中實現了一系列的日誌寫入函數,如下圖所示:其中_android_log_assert, _android_log_vprint和_android_log_print用來寫入類型為
  • FRAE菲瑞智能衛浴:簡易淋浴房的五大功能
    說到簡易淋浴房,相信大家對此都感到不陌生,現很多家庭裡都裝備!簡易淋浴房,是一種功能結構簡單、空間獨立簡潔、通透感十足的時尚淋浴房,因其簡約、舒服、整潔的沐浴體驗,近年來市場需求逐步擴大。而簡易淋浴房之所以會如此火熱,是因為它擁有乾濕分離、安全性、冬季保暖、裝飾性、節省空間這五大功能。下面,FRAE菲瑞小編給大家詳細講一下這五大功能。一、乾濕分離在家居裝修時,多數家庭都會要求衛生間進行乾濕分離。
  • PC版Telegram添加語音聊天室,最多支持數千人
    加密消息軟體Telegram積極擴張功能,本周發布最新PC機版Telegram,添加可允許數千人參加的語音聊天室,加入對講機(Push-to-Talk)交談等功能。語音聊天室是從原有的群組文本交談強化功能而成,即在群組交談之外加一層即時語音通信,語音可和現有的文本及圖片通信同時進行。不過用戶必須是群組管理員才能創建語音聊天室。新版Telegram群組交談接口頂端多了一條橫幅,可顯示正在講話的人頭像、甚至他們講話的音量。管理員可瀏覽誰在線上,並通過菜單中的「啟動語音交談」功能,來啟動交談或邀請其他人加入。
  • android電源管理 - OFweek電子工程網
    framework層主要有這兩個文件:  frameworks\base\core\java\android\os\PowerManager.java  frameworks\base\services\java\com\android\server\PowerManagerService.java  其中PowerManager.java
  • 快手怎麼進行語音直播 如何在快手上找到語音聊天室
    很多剛剛才玩快手的老哥們不是特別熟悉快手的各種功能在哪裡,比如就有人問了主播語音聊天室在哪,所以今天就這裡跟大家說一下如何在快手上找到聊天室,一起來看看吧
  • Twitter正在開發名為"音頻空間"的語音聊天室
    Twitter正在與大型社交網絡爭奪用戶的注意力份額,當科技公司們大力進軍群組視頻通話時,該公司正在尋求嘗試一些完全不同的功能。
  • Google I/O 2019 Android 應用原始碼現已發布
    更多內容,請閱讀《手勢導航: 實現邊到邊的全屏體驗》系列連載,或請前往 Github 查看團隊在 Google I/O 應用庫中提交的相關代碼,了解如何將應用內容擴展到屏幕邊緣。手勢導航: 返回上一級界面和主屏https://developer.android.google.cn/preview/features/gesturalnavhttps://medium.com/androiddevelopers/gesture-navigation-going-edge-to-edge-812f62e4e83ehttps://github.com