android socket聊天室功能實現(xiàn)
前提概要
筆者很久之前其實就已經(jīng)學(xué)習(xí)過了socket,當(dāng)然也是用socket做過了聊天室,但是覺得此知識點比較一般,并無特別難的技術(shù)點,于是也并未深究。
然而近期一個項目中對socket的使用卻讓筆者感覺socket強大無比,可以實現(xiàn)諸多功能。
個人Socket體驗
項目主要有關(guān)智能家居,需要實現(xiàn)多臺手機同時對燈進行操作(開或者關(guān)),主要需要實現(xiàn)以下幾點:
1、進入界面時獲取所有燈的狀態(tài)。
2、一臺手機改變了燈的狀態(tài),其他的手機上可以有所顯示。
3、硬件上改變了燈的狀態(tài)(手動開關(guān)燈),所有手機上要有所顯示。
此功能如果使用HTTP讀取的方式實現(xiàn)就不太合適了。一方面客戶端與服務(wù)器讀取文件的同步性難以保證,即使保證了,也需要浪費大量性能;另一方面,類似筆者的這種項目功能服務(wù)器和客戶端交互比較頻繁,對“即時性”要求也比較高,用HTTP不僅性能消耗太大,而且難以保證“即時性”。
但是使用Socket就很容易實現(xiàn)了,主要邏輯如下:
1、每次進入界面與服務(wù)器建立Socket連接,并得到此時燈的狀態(tài)
2、每次需要對燈進行操作的時候建立一個線程把燈的狀態(tài)傳遞給服務(wù)器,服務(wù)器接收到之后,把該狀態(tài)傳遞給每一個此時與服務(wù)器建立連接的客戶端。
此次體驗也是讓筆者想起了學(xué)長之前做的一道筆試題,題目大概如下:
將淘寶網(wǎng)頁和手機版同時打開賬戶,手機停留在購物車界面,此時網(wǎng)頁上將某一物品加入購物車,如何設(shè)計才能讓手機自動刷新購物車。
如果使用socket,相信是一個不錯的思路。
好了,接下來進入正題,展示socket聊天室demo。
效果(源碼在文章結(jié)尾)

主要思路
Android
1、進入界面客戶端與服務(wù)器建立socket,同時此時開啟一個線程一直接收服務(wù)器發(fā)送來的消息。
2、每次點擊button獲取EditText中的字符串,調(diào)用子線程把字符串發(fā)送給服務(wù)器。
服務(wù)器
1、創(chuàng)建一個ArrayList存儲Socket。
2、循環(huán)接收請求訪問該端口的客戶端,接收到之后,把該socket存儲到ArrayList中,并且為每一個socket開啟一個線程用于通信。
3、每個socket的線程的邏輯如下:循環(huán)接收客戶端發(fā)來的消息,接收到之后,利用之前的ArrayList,發(fā)送到每一個客戶端。如果某個客戶端返回空值或者無法發(fā)送過去,那么表示該客戶端已經(jīng)斷開,就從ArrayList中移除。
代碼
(借鑒《Android瘋狂講義》)
Android
不要忘記在AndroidManifest里面加上訪問網(wǎng)絡(luò)的權(quán)限
MainActivity:
package com.example.double2.sockettesttwo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private EditText etMain;
private Button btnMain;
private TextView tvMain;
private ClientThread mClientThread;
//在主線程中定義Handler傳入子線程用于更新TextView
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etMain = (EditText) findViewById(R.id.et_main);
btnMain = (Button) findViewById(R.id.btn_main);
tvMain = (TextView) findViewById(R.id.tv_main);
mHandler=new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
tvMain.append("\n" + msg.obj.toString());
}
}
};
//點擊button時,獲取EditText中string并且調(diào)用子線程的Handler發(fā)送到服務(wù)器
btnMain.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Message msg = new Message();
msg.what = 1;
msg.obj = etMain.getText().toString();
mClientThread.revHandler.sendMessage(msg);
etMain.setText("");
} catch (Exception e) {
e.printStackTrace();
}
}
});
mClientThread = new ClientThread(mHandler);
new Thread(mClientThread).start();
}
}
ClientThread
package com.example.double2.sockettesttwo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
/**
* 項目名稱:SocketTestTwo
* 創(chuàng)建人:Double2號
* 創(chuàng)建時間:2016.11.20 9:16
* 修改備注:
*/
public class ClientThread implements Runnable {
private Socket mSocket;
private BufferedReader mBufferedReader = null;
private OutputStream mOutputStream = null;
private Handler mHandler;
public Handler revHandler;
public ClientThread(Handler handler) {
mHandler = handler;
}
@Override
public void run() {
try {
mSocket = new Socket("10.3.20.159", 30003);
Log.d("xjj","connect success");
mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
mOutputStream = mSocket.getOutputStream();
new Thread(){
@Override
public void run() {
super.run();
try {
String content = null;
while ((content = mBufferedReader.readLine()) != null) {
Log.d("xjj",content);
Message msg = new Message();
msg.what = 0;
msg.obj = content;
mHandler.sendMessage(msg);
}
}catch (IOException e){
e.printStackTrace();
}
}
}.start();
//由于子線程中沒有默認(rèn)初始化Looper,要在子線程中創(chuàng)建Handler,需要自己寫
Looper.prepare();
revHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
try {
mOutputStream.write((msg.obj.toString() + "\r\n").getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
Log.d("xjj","");
}
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/activity_vertical_margin" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android:id="@+id/et_main" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <Button android:id="@+id/btn_main" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/send"/> </LinearLayout> <TextView android:id="@+id/tv_main" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
服務(wù)器:
MySever
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class MySever {
public static ArrayList<Socket> socketList = new ArrayList<Socket>();
public static String content="";
public static void main(String[] args) throws IOException {
//建立ServerSocket
ServerSocket ss = new ServerSocket(30003);
//不斷接收此端口的socket,并存儲到socketList中
//并且為每一個socket開啟一個線程,用于接收信息
while (true) {
Socket s = ss.accept();
System.out.println("connect success!");
socketList.add(s);
new Thread(new ServerThread(s)).start();
}
}
}
SeverThread
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketException;
import java.util.Iterator;
public class ServerThread implements Runnable {
private Socket mSocket = null;
private BufferedReader mBufferedReader = null;
// 構(gòu)造函數(shù)中接收socket并且初始化BufferedReader
public ServerThread(Socket socket)
throws UnsupportedEncodingException, IOException {
mSocket = socket;
mBufferedReader = new BufferedReader(
new InputStreamReader(mSocket.getInputStream(), "utf-8"));
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
String content = null;
//循環(huán)接收來自此客戶端的消息
//如果接收不到了,表面已經(jīng)斷開,就將此客戶端從socketList中移除
while ((content = mBufferedReader.readLine()) != null) {
System.out.println(content);
//向連接中的每個客戶端發(fā)送數(shù)據(jù)
//如果異常,說明斷開,就將該條目從socketList中移除
for (Iterator<Socket> it = MySever.socketList.iterator();
it.hasNext();) {
Socket s = it.next();
try {
OutputStream os = s.getOutputStream();
os.write((content + "\n").getBytes("utf-8"));
} catch (SocketException e) {
e.printStackTrace();
it.remove();
}
}
}
} catch (IOException e) {
e.printStackTrace();
MySever.socketList.remove(mSocket);
}
}
}
源碼地址:android socket聊天室
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android Socket實現(xiàn)多個客戶端聊天布局
- android使用Socket通信實現(xiàn)多人聊天應(yīng)用
- Android Socket通信實現(xiàn)簡單聊天室
- Android使用Websocket實現(xiàn)聊天室
- 基于Socket.IO實現(xiàn)Android聊天功能代碼示例
- android Socket實現(xiàn)簡單聊天小程序
- android Socket實現(xiàn)簡單聊天功能以及文件傳輸
- Android 基于Socket的聊天室實例
- Android基于socket實現(xiàn)的簡單C/S聊天通信功能
- Android Socket實現(xiàn)多個客戶端即時通信聊天
相關(guān)文章
Android通過原生方式獲取經(jīng)緯度與城市信息的方法
這篇文章主要給大家介紹了關(guān)于Android通過原生方式獲取經(jīng)緯度與城市信息的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Android 7.0行為變更 FileUriExposedException解決方法
這篇文章主要介紹了Android 7.0行為變更 FileUriExposedException解決方法的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android編程使用AlarmManager設(shè)置鬧鐘的方法
這篇文章主要介紹了Android編程使用AlarmManager設(shè)置鬧鐘的方法,結(jié)合具體實例分析了Android基于AlarmManager實現(xiàn)鬧鐘功能的設(shè)置、取消、顯示等相關(guān)操作技巧,需要的朋友可以參考下2017-03-03

