Android Socket實現(xiàn)多個客戶端即時通信聊天
聊天室的原理是這樣的,一個客戶端與服務器建立通訊成功,即客戶端socket連接到服務器的ServerSocket之后,服務器端程序將對應的socket加入到容器中,為每一個socket創(chuàng)建一條線程,服務器端讀到客戶端發(fā)來的信息之后,遍歷該容器,給容器中的每個socket發(fā)送一次,就完成了所有客戶端廣播。當客戶端離開時,向服務器發(fā)送一條斷開連接信息,從服務器端斷開socket,將容器中的對應socket移除掉。
圖:
服務器端Server,java:
accept通信后,為該socket建立一條線程,開啟循環(huán)讀寫操作
/** ?* Created by konghao on 2017/11/8. ?*/ public class Server { ? ? ? static List<Socket> cons = new LinkedList<Socket>(); ? ? private static Socket socket = null; ? ? ? public static class ServerThread extends Thread{ ? ? ? ? private Socket s; ? ? ? ? ? public ServerThread(Socket socket){ ? ? ? ? ? ? this.s = socket; ? ? ? ? ? ? cons.add(s); ? ? ? ? } ? ? ? ? ? @Override ? ? ? ? public void run(){ ? ? ? ? ? ? System.out.print("新用戶加入\n"); ? ? ? ? ? ? System.out.print("當前在線數(shù)量:"+cons.size()+"\n"); ? ? ? ? ? ? try{ ? ? ? ? ? ? ? ? while(true){ ? ? ? ? ? ? ? ? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); ? ? ? ? ? ? ? ? ? ? String mess;// = br.readLine(); ? ? ? ? ? ? ? ? ? ? //保存信息 ? ? ? ? ? ? ? ? ? ? if((mess=br.readLine())!=null) { ? ? ? ? ? ? ? ? ? ? ? ? if(mess.equals("-用戶退出-")){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? s.close(); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? System.out.print("客戶端:" + mess + "\n"); ? ? ? ? ? ? ? ? ? ? ? ? BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); ? ? ? ? ? ? ? ? ? ? ? ? //為了證明是服務器返回的數(shù)據(jù),我對mess修改在發(fā)送到客戶端 ? ? ? ? ? ? ? ? ? ? ? ? //這里修改廣播到所有客戶端 ? ? ? ? ? ? ? ? ? ? ? ? for (Socket so : cons){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? BufferedWriter buffw = new BufferedWriter(new OutputStreamWriter(so.getOutputStream())); ? ? ? ? ? ? ? ? ? ? ? ? ? ? String str = "服務器>>"+mess+"\n"; ? ? ? ? ? ? ? ? ? ? ? ? ? ? buffw.write(str); ? ? ? ? ? ? ? ? ? ? ? ? ? ? buffw.flush(); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? // ? ? ? ? ? ? ? ? ? ? ? ? //單客戶端通信 ? ? ? ? ? ? ? ? ? ? ? ? /* ? ? ? ? ? ? ? ? ? ? ? ? String str = "服務器>>"+mess+"\n"; ? ? ? ? ? ? ? ? ? ? ? ? bw.write(str); ? ? ? ? ? ? ? ? ? ? ? ? bw.flush(); ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? ? ? System.out.print("用戶退出!\n"); ? ? ? ? ? ? ? ? cons.remove(s); ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? this.interrupt(); ? ? ? ? ? ? ? ? //e.printStackTrace(); ? ? ? ? ? ? }catch (NullPointerException e) { ? ? ? ? ? ? ? ? System.out.print("NullPointerException"); ? ? ? ? ? ? }finally { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? s.close(); ? ? ? ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? ? ? ? ? System.out.print("IOException-2"); ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? } ? ? ? public static void main(String[] args) throws IOException { ? ? ? ? ? ServerSocket ss = new ServerSocket(30001); ? ? ? ? while(true){ ? ? ? ? ? ? Socket s = ss.accept(); ? ? ? ? ? ? new Thread(new ServerThread(s)).start(); ? ? ? ? } ? ? } }
安卓客戶端:
進入活動時候創(chuàng)建一條線程,完成socket連接,和循環(huán)監(jiān)聽接受服務器發(fā)來的消息。當發(fā)送按鈕按下后,向服務器發(fā)送消息。退出活動時候,向服務器發(fā)送結束通信信息,服務器收到后關閉socket。
ChatRoomActivity.java
public class ChatRoomActivity extends Activity implements View.OnClickListener{ ? ? private Socket socket = null; ? ? private EditText edit; ? ? private Button send,disconnect; ? ? private RecyclerView msg_recyclerView; ? ? private MsgAdapter adapter; ? ? private List<Msg> msgs = new ArrayList<Msg>();//存儲消息容器 ? ? private String name = ""; ? ? private static final int UPDATE = 1; ? ? ? @Override ? ? protected void onCreate(Bundle savedInstanceState) { ? ? ? ? super.onCreate(savedInstanceState); ? ? ? ? setContentView(R.layout.activity_chat_room); ? ? ? ? ? Intent intent = getIntent(); ? ? ? ? name = intent.getStringExtra("name"); ? ? ? ? Log.d("孔昊",name); ? ? ? ? ? //從服務器讀數(shù)進程 ? ? ? ? new Thread(new Runnable() { ? ? ? ? ? ? private String msg_get=""; ? ? ? ? ? ? @Override ? ? ? ? ? ? public void run() { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? socket = new Socket(); ? ? ? ? ? ? ? ? ? ? socket.connect(new InetSocketAddress("公網(wǎng)IP", 30001), 5000); ? ? ? ? ? ? ? ? ? ? ? //input ? ? ? ? ? ? ? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); ? ? ? ? ? ? ? ? ? ? ? while((msg_get=br.readLine())!=null){ ? ? ? ? ? ? ? ? ? ? ? ? Message message = new Message(); ? ? ? ? ? ? ? ? ? ? ? ? Bundle bundle = new Bundle(); ? ? ? ? ? ? ? ? ? ? ? ? Log.d("孔昊",msg_get); ? ? ? ? ? ? ? ? ? ? ? ? bundle.putString("msg",msg_get); ? ? ? ? ? ? ? ? ? ? ? ? message.setData(bundle); ? ? ? ? ? ? ? ? ? ? ? ? message.what = UPDATE; ? ? ? ? ? ? ? ? ? ? ? ? handler.sendMessage(message); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? }).start(); ? ? ? ? ? edit = (EditText) findViewById(R.id.edit); ? ? ? ? send = (Button) findViewById(R.id.send); ? ? ? ? send.setOnClickListener(this); ? ? ? ? disconnect = (Button) findViewById(R.id.disconnect); ? ? ? ? disconnect.setOnClickListener(this); ? ? ? ? ? msg_recyclerView = (RecyclerView) findViewById(R.id.msg_view); ? ? ? ? LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); ? ? ? ? msg_recyclerView.setLayoutManager(linearLayoutManager); ? ? ? ? adapter = new MsgAdapter(msgs); ? ? ? ? msg_recyclerView.setAdapter(adapter); ? ? } ? ? ? Handler handler = new Handler(){ ? ? ? ? ? @Override ? ? ? ? public void handleMessage(Message msg){ ? ? ? ? ? ? super.handleMessage(msg); ? ? ? ? ? ? switch (msg.what){ ? ? ? ? ? ? ? ? //更新消息列表 ? ? ? ? ? ? ? ? case UPDATE:{ ? ? ? ? ? ? ? ? ? ? Bundle bundle = msg.getData(); ? ? ? ? ? ? ? ? ? ? String msg_get = bundle.getString("msg"); ? ? ? ? ? ? ? ? ? ? Msg msg1 = new Msg(msg_get); ? ? ? ? ? ? ? ? ? ? msgs.add(msg1); ? ? ? ? ? ? ? ? ? ? adapter.notifyDataSetChanged(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? } ? ? }; ? ? ? //向服務器發(fā)數(shù)據(jù)進程 ? ? class SocketThread extends Thread{ ? ? ? ? private String msg; ? ? ? ? //Socket socket; ? ? ? ? ? public SocketThread(String m){ ? ? ? ? ? ? msg = m; ? ? ? ? } ? ? ? ? ? @Override ? ? ? ? public void run(){ ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); ? ? ? ? ? ? ? ? bw.write(msg); ? ? ? ? ? ? ? ? bw.newLine(); ? ? ? ? ? ? ? ? bw.flush(); ? ? ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? } ? ? ? @Override ? ? public void onClick(View v) { ? ? ? ? switch(v.getId()){ ? ? ? ? ? ? case R.id.send:{ ? ? ? ? ? ? ? ? String s = name +":"+ edit.getText().toString(); ? ? ? ? ? ? ? ? edit.setText(""); ? ? ? ? ? ? ? ? new Thread(new SocketThread(s)).start(); ? ? ? ? ? ? } ? ? ? ? ? ? break; ? ? ? ? ? ? case R.id.disconnect:{ ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? //socket.shutdownOutput(); ? ? ? ? ? ? ? ? ? ? //socket.shutdownInput(); ? ? ? ? ? ? ? ? ? ? //socket.close(); ? ? ? ? ? ? ? ? ? ? BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); ? ? ? ? ? ? ? ? ? ? bw.write("-用戶退出-"); ? ? ? ? ? ? ? ? ? ? bw.newLine(); ? ? ? ? ? ? ? ? ? ? bw.flush(); ? ? ? ? ? ? ? ? ? ? //發(fā)送message,更新UI ? ? ? ? ? ? ? ? ? ? Message message = new Message(); ? ? ? ? ? ? ? ? ? ? Bundle bundle = new Bundle(); ? ? ? ? ? ? ? ? ? ? bundle.putString("msg","你已經(jīng)退出聊天!"); ? ? ? ? ? ? ? ? ? ? message.setData(bundle); ? ? ? ? ? ? ? ? ? ? message.what = UPDATE; ? ? ? ? ? ? ? ? ? ? handler.sendMessage(message); ? ? ? ? ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? ? ? ? ? //Log.d("孔昊","斷開連接"); ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? break; ? ? ? ? } ? ? } ? ? ? //back事件 ? ? ? @Override ? ? public void onBackPressed(){ ? ? ? ? try { ? ? ? ? ? ? BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); ? ? ? ? ? ? bw.write("-用戶退出-"); ? ? ? ? ? ? bw.newLine(); ? ? ? ? ? ? bw.flush(); ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? super.onBackPressed(); ? ? } ? }
服務器端收到的信息:
另附java控制臺作為客戶端代碼:
/** ?* Created by konghao on 2017/11/8. ?*/ public class Client { ? ? private static String name; ? ? private static Socket socket; ? ? public static void main(String[] args) { ? ? ? ? try { ? ? ? ? ? ? name = "孔昊"; ? ? ? ? ? ? Socket s = new Socket("112.74.92.125",30001); ? ? ? ? ? ? socket = s; ? ? ? ? ? ? System.out.println("客戶端IP:"+s.getLocalAddress()+"端口"+s.getPort()); ? ? ? ? ? ? //構建IO流 ? ? ? ? ? ? BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); ? ? ? ? ? ? ? //建立鍵盤輸入: ? ? ? ? ? ? Scanner scanner = new Scanner(System.in); ? ? ? ? ? ? while(true){ ? ? ? ? ? ? ? ? System.out.println("請輸入發(fā)送消息內容:"); ? ? ? ? ? ? ? ? bw.write(name+":"+scanner.nextLine()+"\n"); ? ? ? ? ? ? ? ? bw.newLine(); ? ? ? ? ? ? ? ? bw.flush(); ? ? ? ? ? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); ? ? ? ? ? ? ? ? //讀取服務器返回的消息數(shù)據(jù) ? ? ? ? ? ? ? ? System.out.println(s.getInetAddress().getLocalHost()+":"+s.getPort()+">>"+br.readLine()); ? ? ? ? ? ? } ? ? ? ? ? } catch (UnknownHostException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? }finally { ? ? ? ? ? ? try{ ? ? ? ? ? ? ? ? socket.close(); ? ? ? ? ? ? }catch (IOException e){ ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android實現(xiàn)打開各種文件的intent方法小結
這篇文章主要介紹了Android實現(xiàn)打開各種文件的intent方法,結合實例形式總結分析了Android針對HTML、圖片文件、pdf文件、文本文件、音頻文件、視頻文件等的intent打開方法,需要的朋友可以參考下2016-08-08Android XmlPullParser 方式解析 Xml 文檔
這篇文章主要介紹了Android XmlPullParser 方式解析 Xml 文檔的相關資料,需要的朋友可以參考下2017-06-06Android中的ViewPager視圖滑動切換類的入門實例教程
Android中ViewPager通常與Fragments組件共同使用來實現(xiàn)視圖切換功能,本文就帶大家一起來學習Android中的ViewPager視圖滑動切換類的入門實例教程:2016-06-06Android動態(tài)給ViewPager添加Indicator導航
這篇文章主要為大家詳細介紹了Android動態(tài)給ViewPager添加Indicator導航的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02