经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
文本聊天室(TCP)
来源:cnblogs  作者:>歃血~红颜  时间:2018/10/17 9:10:06  对本文有异议

   

          以流式的Socket实现面向连接的TCP服务


 

  一.功能要求

     1.用户可以选择聊天服务器进行登录.

     2.用户使用用户名登录到聊天室,这个登录名就是用户在聊天

     室的昵称.

        3.可以选择群聊,广播信息,使所有用户都能看到聊天信息

     4.可以选择和某个用户私聊,其他用户无法得知聊天内容.

     5.聊天信息要试试反应到聊天记录中.

     6.用户登录退出时,要给其他用户发出通知.


  二.设计

    1.界面设计

      ..........发挥你的想象力.........

    2.整体设计

      聊天室整体采用C/S模式,客户端启动后,主动向服务器发出

      连接请求,建立Socket连接.服务器启动后,监听固定端口

      5210,当有客户连接请求时,便响应此请求,将此连接交由线

      程Talking类处理.

  


 

 

  1.来看服务器的代码实现

  1. 1 package jffx.blogs.net;
  2. 2
  3. 3 import java.io.*;
  4. 4 import java.net.*;
  5. 5 import java.util.*;
  6. 6
  7. 7 /**
  8. 8 * 代码文件: TalkRoomServer.java
  9. 9 * 功能描述: 管理服务器与客户端的活动连接
  10. 10 */
  11. 11 public class TalkRoomServer {
  12. 12 public static void main(String[] args) {
  13. 13 try {
  14. 14 //服务器端serversocket, 绑定端口(5210), 随意选(1024后的)
  15. 15 ServerSocket server = new ServerSocket(5210);
  16. 16
  17. 17 /**
  18. 18 * 容器来保存服务器与客户端的连接, 键为姓名,值为socket
  19. 19 */
  20. 20 Map<String, Socket> socketMap = new HashMap<>() ;
  21. 21
  22. 22 while(true) {
  23. 23 //监听客户端的连接, accept的方式是阻塞的
  24. 24 try {
  25. 25 Socket ss = server.accept();
  26. 26
  27. 27 //创建流
  28. 28 //采用缓冲流,提高效率
  29. 29 DataInputStream in = new DataInputStream(
  30. 30 new BufferedInputStream(ss.getInputStream())
  31. 31 ) ;
  32. 32 DataOutputStream out = new DataOutputStream(
  33. 33 new BufferedOutputStream(ss.getOutputStream())
  34. 34 ) ;
  35. 35
  36. 36 /**
  37. 37 * 在客户端设计时,一个新的用户登录的同时就向服务器发送其姓名
  38. 38 */
  39. 39 String name = in.readUTF() ;
  40. 40 //获取IP
  41. 41 String IP = ss.getInetAddress().toString() ;
  42. 42 //显示到服务器
  43. 43 System.out.println(name + " : " + IP) ;
  44. 44
  45. 45 //查看已监听的客户,并向他们发送新用户登录消息
  46. 46 Collection<Socket> values = socketMap.values() ;
  47. 47 Iterator<Socket> iter = values.iterator() ;
  48. 48 while(iter.hasNext()) {
  49. 49 Socket temp = iter.next() ;
  50. 50 DataOutputStream write = new DataOutputStream(temp.getOutputStream()) ;
  51. 51 write.writeUTF("Add:" + name + IP) ;
  52. 52 write.flush() ;
  53. 53 }
  54. 54 //将新用户添加到容器中
  55. 55 socketMap.put(name, ss) ;
  56. 56
  57. 57 /**
  58. 58 * 向新登录的用户发送都有谁在线
  59. 59 */
  60. 60 Set<String> names = socketMap.keySet() ;
  61. 61 Iterator<String> iterName = names.iterator() ;
  62. 62 while(iterName.hasNext()) {
  63. 63 String loginUser = iterName.next() ;
  64. 64 out.writeUTF("Add:" + loginUser + IP) ;
  65. 65 out.flush() ;
  66. 66 }
  67. 67
  68. 68
  69. 69 /**
  70. 70 * 创建新线程转发用户给服务器发送的消息
  71. 71 * 由于需要分
  72. 72 * 向某个人发送消息,即:私聊
  73. 73 * 向所有发送消息,即:广播.
  74. 74 * 我们采用修改处理客户端的发送方式:
  75. 75 * 在消息的基础上,给前面即消息前缀加上一些表示发送目标的字符串.
  76. 76 * 具体看Talking.java的处理方式
  77. 77 */
  78. 78 //由于客户有可能下线,所以需要将姓名和容器都传递给线程类
  79. 79 new Thread(new Talking(name, ss, socketMap)).start() ;
  80. 80
  81. 81 } catch (Exception ex) {
  82. 82 ex.printStackTrace() ;
  83. 83 }
  84. 84 }
  85. 85 } catch (Exception ex) {
  86. 86 ex.printStackTrace() ;
  87. 87 }
  88. 88 }
  89. 89 }

 

 

 

 

下面这个是单独处理每个用户的线程代码.

  大概思路是这样的:先读取这个用户的发送的消息,然后进行解析,拆分,

      分情况发送给客户端;如果由用户退出了聊天室,将用户从所在的

      Socket容器中剔除,并给所有客户发送这个用户退出的消息.

 

 

  1. 1 package jffx.blogs.net;
  2. 2
  3. 3 import java.io.*;
  4. 4 import java.net.*;
  5. 5 import java.util.*;
  6. 6
  7. 7 /**
  8. 8 * 代码文件:Talking.java
  9. 9 * 功能描述:线程类转发用户的数据
  10. 10 */
  11. 11 public class Talking implements Runnable {
  12. 12 String name ;
  13. 13 Socket connecter ;
  14. 14 Map<String, Socket> socketMap = null ;
  15. 15 public Talking(String name, Socket socket, Map<String, Socket> socketMap) {
  16. 16 this.name = name ;
  17. 17 this.connecter = socket ;
  18. 18 this.socketMap = socketMap ;
  19. 19 }
  20. 20
  21. 21 @Override
  22. 22 public void run() {
  23. 23 try {
  24. 24 DataInputStream in = new DataInputStream(
  25. 25 new BufferedInputStream(connecter.getInputStream())
  26. 26 ) ;
  27. 27
  28. 28 while(true) {
  29. 29 String words = in.readUTF() ;
  30. 30 /**
  31. 31 * 我们约定,客户端发送("name@text")这种格式的消息
  32. 32 * 不过用户不需要处理,我们交由客户端程序在发送消息时自动加上
  33. 33 */
  34. 34 String [] tokens = words.split("@") ;
  35. 35 String sendName = tokens[0] ;
  36. 36 String text = tokens[1] ;
  37. 37
  38. 38 if("All".equals(sendName)) {
  39. 39 //容器的值为Socket变量
  40. 40 Collection<Socket> sockets = socketMap.values() ;
  41. 41 Iterator<Socket> iter = sockets.iterator() ;
  42. 42 while(iter.hasNext()) {
  43. 43 //创建流.并以固定格式写出
  44. 44 Socket sendSocket = iter.next() ;
  45. 45 DataOutputStream out = new DataOutputStream(sendSocket.getOutputStream()) ;
  46. 46 out.writeUTF("Text:" + text) ;
  47. 47 out.flush() ;
  48. 48 }
  49. 49 } else { //私聊
  50. 50 Socket sendSocket = socketMap.get(sendName) ;
  51. 51 DataOutputStream out = new DataOutputStream(sendSocket.getOutputStream()) ;
  52. 52 out.writeUTF("Text:" + text) ;
  53. 53 out.flush() ;
  54. 54 }
  55. 55 }
  56. 56 } catch (Exception ex) {
  57. 57 ex.printStackTrace() ;
  58. 58 } finally { //当登陆的用户退出后,就会跳出while(true)
  59. 59 try {
  60. 60 /**
  61. 61 * 查找登陆的用户,删除服务器与其的连接,并发送给所有的客户端
  62. 62 */
  63. 63 this.socketMap.remove(this.name) ;
  64. 64 Collection<Socket> sockets = this.socketMap.values() ;
  65. 65 Iterator<Socket> iter = sockets.iterator() ;
  66. 66 while(iter.hasNext()) {
  67. 67 Socket sender = iter.next() ;
  68. 68 DataOutputStream out = new DataOutputStream(sender.getOutputStream()) ;
  69. 69 out.writeUTF("Del:" + this.name) ;
  70. 70 out.flush() ;
  71. 71 }
  72. 72 } catch (Exception ex) {
  73. 73 ex.printStackTrace() ;
  74. 74 }
  75. 75 }
  76. 76 }
  77. 77 }

 

 

 

至于客户端,留给明天.呵呵...........

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号