1. import java.io.*;
    2. import java.net.Socket;
    3. //聊天室客户机:发送消息、接收别人发送的消息
    4. public class Client {
    5. public static void clientRequest() throws IOException {
    6. //建立客户机,与服务器建立连接
    7. Socket client = new Socket("localhost", 8888);
    8. //创建一个线程用于接收消息
    9. new Thread(new Receive(client)).start();
    10. //本线程专用于送发消息
    11. send.clientSend(client);
    12. }
    13. //封装内部类:发送消息
    14. private static class send{
    15. private static void clientSend(Socket client) throws IOException {
    16. boolean isRunning = true;
    17. String msg;
    18. System.out.println("已连接服务");
    19. //利用IO流进行数据传输
    20. //从键盘获取输入
    21. BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
    22. //并将获取到的内容发送出去
    23. DataOutputStream os = new DataOutputStream(client.getOutputStream());
    24. while (isRunning) {
    25. try {
    26. msg = is.readLine();
    27. os.writeUTF(msg);
    28. } catch (IOException e) {
    29. isRunning = false;
    30. System.out.println("服务被停止,发送失败!");
    31. is.close();
    32. os.close();
    33. client.close();
    34. }
    35. }
    36. }
    37. }
    38. //封装内部类:接收消息
    39. private static class Receive implements Runnable{
    40. Socket client;
    41. DataInputStream dis;
    42. boolean isRunning = true;
    43. //构造器
    44. private Receive(Socket client) {
    45. this.client = client;
    46. }
    47. //run方法:具体操作
    48. @Override
    49. public void run() {
    50. //具体操作:接收消息
    51. String result;
    52. while(isRunning){
    53. try {
    54. dis = new DataInputStream(client.getInputStream());
    55. result = dis.readUTF();
    56. System.out.println(result);
    57. } catch (IOException e) {
    58. isRunning = false;
    59. }
    60. }
    61. try {
    62. dis.close();
    63. } catch (IOException e) {
    64. e.printStackTrace();
    65. }
    66. }
    67. }
    68. }
    1. import java.net.Socket;
    2. //用户类:保存一个客户机的用户名和Socket
    3. public class User{
    4. String userName;
    5. Socket userSocket;
    6. public User(String name, Socket client){
    7. this.userName = name;
    8. this.userSocket = client;
    9. }
    10. }
    1. import java.io.*;
    2. import java.net.ServerSocket;
    3. import java.net.Socket;
    4. import java.util.concurrent.CopyOnWriteArrayList;
    5. //聊天室服务器:转发客户机发送的消息
    6. public class Server {
    7. //群聊容器
    8. private static CopyOnWriteArrayList<User> all = new CopyOnWriteArrayList<User>();
    9. public static void serverResponse() throws IOException {
    10. boolean isRunning = true;
    11. //建立服务器
    12. ServerSocket server = new ServerSocket(8888);
    13. System.out.println("服务启动");
    14. //监听端口,随时等待客户机连接,当一个客户机连接后,建立一条线程为其服务,随后继续监听端口
    15. while(isRunning){
    16. try{
    17. Socket client = server.accept();
    18. new Thread(new Channel(client)).start();//为这个客户机建立单独的消息转发服务
    19. System.out.println("一个客户机进行了连接");
    20. } catch (IOException e) {
    21. isRunning = false;
    22. System.out.println("服务停止!");
    23. server.close();
    24. }
    25. }
    26. }
    27. //封装内部类:转发器 提供消息转发服务:将客户机发送的消息转发给其他客户机
    28. private static class Channel implements Runnable{
    29. DataInputStream sis;
    30. DataOutputStream sos;
    31. Socket client;
    32. String name;
    33. //构造器
    34. private Channel(Socket client){
    35. try {
    36. //利用IO流进行数据传输
    37. this.client = client;
    38. sis = new DataInputStream(client.getInputStream());
    39. } catch (IOException e) {
    40. e.printStackTrace();
    41. }
    42. }
    43. //群聊
    44. private void group(String msg) throws IOException {
    45. for (User c : all) {//一个客户机发送消息后,遍历容器将该条消息转发给其他客户机
    46. if (c.userSocket != this.client) {
    47. sos = new DataOutputStream(c.userSocket.getOutputStream());
    48. sos.writeUTF(msg);
    49. }
    50. }
    51. }
    52. //run方法:具体操作
    53. @Override
    54. public void run() {
    55. //具体操作:获取用户名,并将用户类存入群聊容器
    56. try {
    57. boolean flag = true;
    58. while(flag){
    59. sos = new DataOutputStream(client.getOutputStream());
    60. sos.writeUTF("请输入您的用户名:");
    61. name = sis.readUTF();
    62. int i = 1;
    63. for (User c : all) {//遍历容器验证用户名是否存在
    64. if (c.userName.equals(name)) {
    65. sos.writeUTF("用户名已存在!");
    66. break;
    67. }else{
    68. i++;
    69. }
    70. }
    71. if(i > all.size())
    72. flag = false;
    73. }
    74. User user = new User(name, client);
    75. all.add(user);
    76. group("欢迎"+name+"加入聊天!");
    77. } catch (IOException e) {
    78. e.printStackTrace();
    79. }
    80. String msg;
    81. boolean isRunning = true;
    82. //具体操作:转发消息
    83. while(isRunning) {
    84. try {
    85. msg = sis.readUTF();
    86. //转发私聊消息:@xxx:msg
    87. if(msg.startsWith("@")) {
    88. int idx = msg.indexOf(":");
    89. String targetName = msg.substring(1, idx);//获取该条消息所@的用户的用户名
    90. msg = "来自"+name+"的私聊:"+msg.substring(idx+1);
    91. for (User c : all) {//遍历容器找到该条消息所@的用户后转发消息
    92. if (c.userName.equals(targetName)) {
    93. sos = new DataOutputStream(c.userSocket.getOutputStream());
    94. sos.writeUTF(msg);
    95. break;
    96. }
    97. }
    98. //转发公共群聊消息
    99. }else{
    100. msg = (name + ":" + msg);
    101. group(msg);
    102. }
    103. } catch (IOException e) {//客户机断开连接以后会进行以下操作
    104. isRunning = false;//停止对该客户机的转发服务
    105. all.removeIf(c -> c.userSocket == client);//将该客户机从容器中移除
    106. System.out.println("一个客户机断开了连接");
    107. }
    108. }
    109. try {
    110. //释放资源,随后该线程结束
    111. sis.close();
    112. } catch (IOException e) {
    113. e.printStackTrace();
    114. }
    115. }
    116. }
    117. }