多個(gè)客戶端--多人聊天+私聊

2019-07-09 22:34 更新

在多人聊天室的基礎(chǔ)上增加了私聊功能。 實(shí)現(xiàn)方法:在Send類中添加name區(qū)別客戶端,用于客戶端;在MyChannel中添加name區(qū)別客戶端連接,用于服務(wù)端。 1.服務(wù)端

  1. import java.io.DataInputStream;
  2. import java.io.DataOutputStream;
  3. import java.io.IOException;
  4. import java.net.ServerSocket;
  5. import java.net.Socket;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. /**
  9. * 創(chuàng)建服務(wù)器
  10. * 發(fā)送數(shù)據(jù):輸出流
  11. * 接收數(shù)據(jù):輸入流
  12. */
  13. public class MyServer {
  14. //存放服務(wù)端與客戶端的連接
  15. private List<MyChannel> all = new ArrayList<>();
  16. public static void main(String[] args) throws IOException {
  17. new MyServer().start();
  18. }
  19. public void start() throws IOException {
  20. ServerSocket server = new ServerSocket(8888);
  21. while(true) {
  22. Socket socket = server.accept();
  23. MyChannel myChannel = new MyChannel(socket);
  24. all.add(myChannel);
  25. new Thread(myChannel).start();
  26. }
  27. }
  28. /**
  29. * 一個(gè)客戶端一條道路,
  30. * 一個(gè)客戶端一個(gè)線程。
  31. * 1.輸入流
  32. * 2.輸出流
  33. * 3.接收數(shù)據(jù)
  34. * 4.發(fā)送數(shù)據(jù)
  35. * 成員內(nèi)部類,靜態(tài)方法不能訪問。
  36. */
  37. class MyChannel implements Runnable{
  38. //輸入流
  39. private DataInputStream dis;
  40. //輸出流
  41. private DataOutputStream dos;
  42. //控制線程的標(biāo)識(shí)符
  43. private boolean isRunning = true;
  44. //名稱 給每個(gè)連接命名,區(qū)別客戶端 不考慮重名
  45. private String name;
  46. //初始化建立管道
  47. public MyChannel(Socket socket) {
  48. try {
  49. dis = new DataInputStream(socket.getInputStream());
  50. dos = new DataOutputStream(socket.getOutputStream());
  51. name = dis.readUTF();
  52. send("歡迎您進(jìn)入聊天室!");//發(fā)送給自己客戶端
  53. sendOthers(name + "進(jìn)入了聊天室!", true); //發(fā)給其他的客戶端
  54. } catch (IOException e) {
  55. e.printStackTrace();
  56. CloseUtil.closeAll(dis, dos);
  57. all.remove(this);
  58. isRunning = false;
  59. }
  60. }
  61. //讀取數(shù)據(jù)
  62. private String receive() {
  63. String msg = "";
  64. try {
  65. msg = dis.readUTF();
  66. } catch (IOException e) {
  67. e.printStackTrace();
  68. CloseUtil.closeAll(dis, dos);
  69. all.remove(this);
  70. isRunning = false;
  71. }
  72. return msg;
  73. }
  74. //發(fā)送給this數(shù)據(jù)
  75. private void send(String msg) {
  76. if(msg == null || msg.equals("")) {
  77. return;
  78. }
  79. try {
  80. dos.writeUTF(msg);
  81. dos.flush();
  82. } catch (IOException e) {
  83. e.printStackTrace();
  84. CloseUtil.closeAll(dis, dos);
  85. all.remove(this);
  86. isRunning = false;
  87. }
  88. }
  89. //發(fā)送給其他客戶端
  90. private void sendOthers(String msg, boolean isSysMsg) {
  91. //是否為私聊
  92. if(msg.startsWith("@") && msg.indexOf(":") != -1) {//向一個(gè)特定的人發(fā)消息,格式為@xxx:message
  93. //獲取name
  94. String name = msg.substring(1, msg.indexOf(":"));
  95. //獲取內(nèi)容
  96. String content = msg.substring(msg.indexOf(":") + 1);
  97. for(MyChannel other:all) {
  98. if(other.name.equals(name)) {
  99. other.send(this.name + "對(duì)您悄悄地說:" + content);
  100. }
  101. }
  102. } else {//向全體發(fā)消息
  103. //遍歷容器
  104. for(MyChannel other : all) {
  105. if(other == this) {
  106. continue;
  107. }
  108. if(isSysMsg) {//是系統(tǒng)消息
  109. //發(fā)送給其他客戶端
  110. other.send("系統(tǒng)信息:" + msg);
  111. } else {//不是系統(tǒng)消息
  112. //發(fā)送給其他客戶端
  113. other.send(name + "對(duì)所有人說:" + msg);
  114. }
  115. }
  116. }
  117. }
  118. @Override
  119. public void run() {
  120. while(isRunning) {
  121. sendOthers(receive(), false);
  122. }
  123. }
  124. }
  125. }

2.客戶端

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import java.net.Socket;
  5. /**
  6. * 創(chuàng)建客戶端:發(fā)送數(shù)據(jù)+接收數(shù)據(jù)
  7. * 發(fā)送數(shù)據(jù):輸出流
  8. * 接收數(shù)據(jù):輸入流
  9. * 輸出流和輸入流應(yīng)該彼此獨(dú)立,使用線程處理。
  10. * 加入名稱。
  11. */
  12. public class MyClient {
  13. public static void main(String[] args) throws IOException {
  14. //通過名稱判斷不同的客戶 端,存放在Send類中。
  15. System.out.println("請(qǐng)輸入名稱:");
  16. BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  17. String name = br.readLine();
  18. if(name.equals("")) {
  19. return;
  20. }
  21. Socket client = new Socket("localhost", 8888);
  22. //發(fā)送 控制臺(tái)輸入并發(fā)送到服務(wù)端
  23. new Thread(new Send(client, name)).start();//一條路徑
  24. //接收 接收服務(wù)端數(shù)據(jù)并打印
  25. new Thread(new Receive(client)).start();//一條路徑
  26. }
  27. }

發(fā)送數(shù)據(jù)線程

  1. import java.io.BufferedReader;
  2. import java.io.DataOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.Socket;
  6. /**
  7. * 發(fā)送數(shù)據(jù) 線程
  8. */
  9. public class Send implements Runnable{
  10. //控制臺(tái)輸入流
  11. private BufferedReader console;
  12. //管道輸出流
  13. private DataOutputStream dos;
  14. //控制線程的標(biāo)識(shí)符
  15. private boolean isRunning = true;
  16. //名稱 不考慮重名
  17. private String name;
  18. //初始化建立管道
  19. public Send(Socket socket, String name) {
  20. try {
  21. console = new BufferedReader(new InputStreamReader(System.in));
  22. dos = new DataOutputStream(socket.getOutputStream());
  23. this.name = name;
  24. send(name);
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. isRunning = false;
  28. CloseUtil.closeAll(dos, console);
  29. }
  30. }
  31. /**
  32. * 1.從控制臺(tái)接收數(shù)據(jù)
  33. * 2.向服務(wù)端發(fā)送數(shù)據(jù)
  34. */
  35. //1.從控制臺(tái)接收數(shù)據(jù)
  36. private String getMsgFromConsole() {
  37. String msg = "";
  38. try {
  39. msg = console.readLine();
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. isRunning = false;
  43. CloseUtil.closeAll(dos, console);
  44. }
  45. return msg;
  46. }
  47. //2.向服務(wù)端發(fā)送數(shù)據(jù)
  48. private void send(String msg) {
  49. try {
  50. if(msg != null && !msg.equals("")) {
  51. dos.writeUTF(msg);
  52. dos.flush();//強(qiáng)制刷新
  53. }
  54. } catch (IOException e) {
  55. e.printStackTrace();
  56. isRunning = false;
  57. CloseUtil.closeAll(dos, console);
  58. }
  59. }
  60. @Override
  61. public void run() {
  62. //線程體
  63. while(isRunning) {
  64. send(getMsgFromConsole());
  65. }
  66. }
  67. }

接收數(shù)據(jù)線程

  1. import java.io.DataInputStream;
  2. import java.io.IOException;
  3. import java.net.Socket;
  4. public class Receive implements Runnable{
  5. //輸入流
  6. private DataInputStream dis;
  7. //線程標(biāo)識(shí)符
  8. private boolean isRunning = true;
  9. //初始化建立管道
  10. public Receive(Socket socket) {
  11. try {
  12. dis = new DataInputStream(socket.getInputStream());
  13. } catch (IOException e) {
  14. e.printStackTrace();
  15. isRunning = false;
  16. CloseUtil.closeAll(dis);
  17. }
  18. }
  19. /**
  20. * 接收數(shù)據(jù)
  21. */
  22. private String receive() {
  23. String msg = "";
  24. try {
  25. msg = dis.readUTF();
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. isRunning = false;
  29. CloseUtil.closeAll(dis);
  30. }
  31. return msg;
  32. }
  33. @Override
  34. public void run() {
  35. //線程體
  36. while(isRunning) {
  37. System.out.println(receive());
  38. }
  39. }
  40. }

3.關(guān)閉流工具類

  1. import java.io.Closeable;
  2. import java.io.IOException;
  3. /**
  4. * 關(guān)閉io流的工具
  5. */
  6. public class CloseUtil {
  7. public static void closeAll(Closeable... io) {
  8. for(Closeable temp : io) {
  9. try {
  10. if(temp != null) {
  11. temp.close();
  12. }
  13. } catch (IOException e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. }
  18. }
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)