Android實(shí)現(xiàn)C/S聊天室
Java中能接受其他通信實(shí)體鏈接請(qǐng)求的類是ServerSocket,ServerSocket對(duì)象用于監(jiān)聽來自客戶端的Socket鏈接,如果沒有鏈接,它將一直等待。如果接收到一個(gè)客戶端Socket的連接請(qǐng)求,ServerSocket的accept()方法將返回一個(gè)與客戶端Socket對(duì)應(yīng)的Socket(每個(gè)TCP連接有兩個(gè)Socket),否則該方法將一直阻塞,線程也被阻塞。
服務(wù)端思路:服務(wù)端應(yīng)該包含多個(gè)線程,每個(gè)Socket對(duì)應(yīng)一個(gè)線程,這個(gè)線程負(fù)責(zé)讀取該Socket對(duì)應(yīng)輸入流的數(shù)據(jù)(從客戶端發(fā)送過來的數(shù)據(jù)),并將讀到的數(shù)據(jù)向每個(gè)Socket輸出流發(fā)送一次(將一個(gè)客戶端發(fā)送過來的數(shù)據(jù)“廣播”給其他客戶端)。
服務(wù)端代碼:
//服務(wù)端主類 public class MyServer { public static List<Socket> socketList = Collections.synchronizedList(new ArrayList<Socket>()); public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(30000); while (true) { //此行代碼會(huì)阻塞,將一直等待別人的連接 Socket s = ss.accept(); socketList.add(s); //每當(dāng)客戶端連接后啟動(dòng)一個(gè)ServerThread線程為該客戶端服務(wù) new Thread(new ServerThread(s)).start(); } } }
public class ServerThread implements Runnable { //定義當(dāng)前線程所處理的Socket Socket s = null; //該線程所處理的Socket對(duì)應(yīng)的輸入流 BufferedReader br = null; public ServerThread(Socket s) throws IOException { this.s = s; //初始化該Socket對(duì)應(yīng)的輸入流 br = new BufferedReader(new InputStreamReader(s.getInputStream())); } @Override public void run() { try { String content = null; //采用循環(huán)不斷地從Socket中讀取客戶端發(fā)送來的數(shù)據(jù) while ((content = readFromClient()) != null) { //遍歷socketList中的每個(gè)Socket //將讀到的內(nèi)容向每個(gè)Socket發(fā)送一次 for (Socket s : MyServer.socketList) { PrintStream ps = new PrintStream(s.getOutputStream()); ps.println(content); } } } catch (IOException e) { e.printStackTrace(); } } //定義讀取客戶端數(shù)據(jù)的方法 private String readFromClient() { try { return br.readLine(); } //如果捕獲到異常,則表明該Socket對(duì)應(yīng)的客戶端已經(jīng)關(guān)閉 catch (IOException e) { //刪除該Socket MyServer.socketList.remove(s); } return null; } }
客戶端思路:將用戶輸入的數(shù)據(jù)寫入Socket對(duì)應(yīng)的輸入流中;開啟一個(gè)子線程讀取Socket對(duì)應(yīng)輸入流中的數(shù)據(jù)(從服務(wù)端發(fā)送過來的數(shù)據(jù)),并通過Handler將讀取的數(shù)據(jù)發(fā)送到主線程來更新UI。
//用戶界面Activity public class MainActivity extends Activity { private EditText mReceiverMsg; private Button mSendBtn; private EditText mSendMsg; Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Log.d("mainActivity" , "okk"); mReceiverMsg.append(msg.obj.toString()); } }; private Socket s; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); initView(); initSocket(); mSendBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { sendData(); } }); } private void initSocket() { new Thread() { @Override public void run() { try { s = new Socket("192.168.1.101" , 30000); new Thread(new ClientThread(s , handler)).start(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } private void initView() { mReceiverMsg = (EditText) findViewById(R.id.receiver_message); mSendMsg = (EditText) findViewById(R.id.send_message); mSendBtn = (Button) findViewById(R.id.send_button); } private void sendData() { try { //獲取該Socket對(duì)應(yīng)的輸出流 PrintStream ps = new PrintStream(s.getOutputStream()); if (TextUtils.isEmpty(mSendMsg.getText())) { Toast.makeText(this , "請(qǐng)輸入信息" , Toast.LENGTH_LONG).show(); return; } ps.println(mSendMsg.getText().toString()); } catch (IOException e) { e.printStackTrace(); } } }
public class ClientThread implements Runnable { //該線程負(fù)責(zé)處理的Socket private Socket ss; //該線程所處理的Socket對(duì)應(yīng)的輸入流 BufferedReader br = null; Handler handler; public ClientThread(Socket s , Handler handler) throws IOException { this.ss = s; this.handler = handler; br = new BufferedReader(new InputStreamReader(ss.getInputStream())); } @Override public void run() { try { String content = null; while ((content = br.readLine()) != null) { Message msg = new Message(); msg.obj = content; handler.sendMessage(msg); } } catch (IOException e) { e.printStackTrace(); } } }
先運(yùn)行上面程序中的MyServer類,該類運(yùn)行只是作為服務(wù)端。再啟動(dòng)多個(gè)模擬器,運(yùn)行安裝客戶端的程序作為多個(gè)客戶端,然后可以再任何一個(gè)客戶端通過Edit輸入一些內(nèi)容,點(diǎn)擊發(fā)送就可以在任何一個(gè)客戶端看到剛剛輸入的內(nèi)容。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)簡(jiǎn)單C/S聊天室應(yīng)用
- Android Socket通信實(shí)現(xiàn)簡(jiǎn)單聊天室
- Android使用Websocket實(shí)現(xiàn)聊天室
- Android使用多線程進(jìn)行網(wǎng)絡(luò)聊天室通信
- android socket聊天室功能實(shí)現(xiàn)
- Android 基于Socket的聊天室實(shí)例
- Android編寫簡(jiǎn)單的聊天室應(yīng)用
- Android中基于XMPP協(xié)議實(shí)現(xiàn)IM聊天程序與多人聊天室
- Android文本視圖TextView實(shí)現(xiàn)聊天室效果
相關(guān)文章
利用SurfaceView實(shí)現(xiàn)下雨與下雪動(dòng)畫效果詳解(Kotlin語法)
這篇文章主要給大家介紹了關(guān)于利用SurfaceView實(shí)現(xiàn)下雨與下雪動(dòng)畫效果的相關(guān)資料,需要一些基本的View知識(shí)和會(huì)一些基礎(chǔ)Kotlin語法,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09Android線性布局與相對(duì)布局的實(shí)現(xiàn)
大家好,本篇文章主要講的是Android線性布局與相對(duì)布局的實(shí)現(xiàn),感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02Android TextView中文字通過SpannableString設(shè)置屬性用法示例
這篇文章主要介紹了Android TextView中文字通過SpannableString設(shè)置屬性用法,結(jié)合實(shí)例形式分析了TextView控件中SpannableString類相關(guān)屬性的使用技巧,需要的朋友可以參考下2016-08-08Android實(shí)現(xiàn)登錄界面記住密碼的存儲(chǔ)
這篇文章主要為大家詳細(xì)介紹了Android SharedPreferrences實(shí)現(xiàn)登錄界面記住密碼的存儲(chǔ),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Android fragment實(shí)現(xiàn)多個(gè)頁(yè)面切換效果
這篇文章主要為大家詳細(xì)介紹了fragment實(shí)現(xiàn)多個(gè)頁(yè)面切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04