思路

  • 客户端读写各一个类,可以使内部类,实现Runnable。读写类都与服务器端建立连接,一个收,一个发。
  • 客户端实现接收和转发。多线程实现每个客户端的连接(使与各客户端的连接独立)。
  • 服务器端中创建一个公共缓冲池,用于存放消息。通过服务器中的转发方法转发给个客户端。

客户端 代码

  1. package _20191218;
  2. import java.io.DataInputStream;
  3. import java.io.DataOutputStream;
  4. import java.io.IOException;
  5. import java.net.Socket;
  6. import java.net.UnknownHostException;
  7. import java.util.Scanner;
  8.  
  9. /**
  10. * 多人聊天室,客户端,实时发送接收数据,要实现多线程
  11. */
  12.  
  13. public class TCPMultipleChatClient {
  14. public static void main(String[] args) {
  15. System.out.println("-------局域网聊天室-----------");
  16. Scanner scan1 = new Scanner(System.in);
  17. System.out.print("请输入您的昵称:");
  18. String username = scan1.nextLine();
  19. String address = "176.195.108.53";//服务器地址
  20. int port = 6788;//服务器程序端口
  21. Socket client = null;
  22. try {
  23. client = new Socket(address,port);
  24. System.out.println("成功登入,可以开始聊天了!");
  25. System.out.println("------------------------");
  26. } catch (UnknownHostException e) {
  27. System.err.println("服务器连接失败");
  28. } catch (IOException e) {
  29. System.err.println("服务器连接失败");
  30. }
  31. /**
  32. * 启动接收器与发送器
  33. */
  34. new Thread(new Sender(client),username).start();
  35. new Thread(new Receiver(client)).start();
  36. }
  37. }
  38. //发送器:实现Runnable
  39. class Sender implements Runnable{
  40. private boolean flag = true;//服务器存活为 true
  41. //输出流
  42. private DataOutputStream dos;
  43. //构造器:初始化
  44. public Sender(Socket client) {
  45. try {
  46. dos = new DataOutputStream(client.getOutputStream());
  47. } catch (IOException e) {
  48. System.err.println("服务器未开启,连接失败");
  49. }
  50. }
  51. public void sendMessage() {
  52. Scanner scan = new Scanner(System.in);
  53. String message = scan.nextLine();
  54. try {
  55. dos.writeUTF(Thread.currentThread().getName()+":"+message);
  56. dos.flush();
  57. } catch (IOException e) {
  58. System.err.println("Sender:服务器关闭");
  59. flag = false;
  60. }
  61. }
  62. public void run() {
  63. while(flag) {
  64. sendMessage();
  65. try {
  66. Thread.sleep(500);
  67. } catch (InterruptedException e) {
  68. e.printStackTrace();
  69. }
  70. }
  71. }
  72. }
  73. //接收器:实现Runnable
  74. class Receiver implements Runnable{
  75. private boolean flag = true;//服务器存活为 true
  76. //输入流
  77. private DataInputStream dis;
  78. public Receiver(Socket client) {
  79. try {
  80. dis = new DataInputStream(client.getInputStream());
  81. } catch (IOException e) {
  82. e.printStackTrace();
  83. }
  84. }
  85. //读取消息
  86. public void readMessage() {
  87. try {
  88. System.out.println(dis.readUTF());
  89. } catch (IOException e) {
  90. System.err.println("Reciver:服务器关闭");
  91. flag =false;
  92. }
  93. }
  94. public void run() {
  95. while(flag) {
  96. readMessage();
  97. try {
  98. Thread.sleep(500);
  99. } catch (InterruptedException e) {
  100. e.printStackTrace();
  101. }
  102. }
  103. }
  104. }
  105. //}

  

服务器端 代码

  1. package _20191218;
  2.  
  3. import java.io.DataInputStream;
  4. import java.io.DataOutputStream;
  5. import java.io.IOException;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9.  
  10. /**
  11. * 多人聊天室,服务端,实时转发数据
  12. */
  13. public class TCPMultipleChatServer {
  14. public static void main(String[] args) {
  15. System.out.println("服务端开启");
  16. //创建服务器端
  17. ServerSocket server = null;
  18. try {
  19. server = new ServerSocket(6788);//服务器端口
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. //容器
  24. Container container = new Container();
  25. //循环监听
  26. while(true) {
  27. //阻塞监听连接请求
  28. try {
  29. Socket client = server.accept();
  30. System.out.println("一位用户成功连接");
  31. container.doCount();
  32. //开启接收器
  33. new Thread(new Receiver(client,container)).start();
  34. //开启转发器
  35. new Thread(new Transmit(client,container)).start();
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  41.  
  42. static class Container{
  43. // StringBuffer wrap = new StringBuffer();
  44. static int userCount = 0;//当前用户量
  45. private int now = 0;//已转发量
  46. private String[] strs = new String[1024];//消息队列
  47. private int i = 0;//消息计数器
  48. public void add(String message) {
  49. strs[i]=message;
  50. i++;
  51. }
  52. public static void doCount() {//用户量加一
  53. userCount++;
  54. }
  55. public void subUserCount() {//用户量减一
  56. userCount--;
  57. }
  58. public void reset() {
  59. if(now == userCount) {
  60. strs = new String[1024];
  61. now = 0;
  62. }
  63. }
  64. }
  65. static class Receiver implements Runnable{
  66. private boolean flag = true;
  67. private Container container;
  68. private DataInputStream dis;
  69. public Receiver(Socket client,Container container) {
  70. this.container = container;
  71. try {
  72. dis = new DataInputStream(client.getInputStream());
  73. } catch (IOException e) {
  74. e.printStackTrace();
  75. }
  76. }
  77. //读取消息
  78. public void readMessage() {
  79. try {
  80. //存入容器
  81. String str = "";
  82. if(!(str = dis.readUTF()).equals("")) {
  83. container.add(str);
  84. }
  85.  
  86. } catch (IOException e) {
  87. flag = false;
  88. System.err.println("Read:用户已离开会话");
  89. container.subUserCount();
  90. }
  91. }
  92. public void run() {
  93. while(flag) {
  94. readMessage();
  95. }
  96. }
  97. }
  98. //转发
  99. static class Transmit implements Runnable{
  100. private boolean flag = true;
  101. private Container container;
  102. private DataOutputStream dos;
  103. public Transmit(Socket client, Container container) {
  104. this.container = container;
  105. try {
  106. this.dos = new DataOutputStream(client.getOutputStream());
  107. } catch (IOException e) {
  108. flag = false;
  109. System.err.println("Transmit:用户已离开会话");
  110. }
  111. }
  112.  
  113. public void run() {
  114. while(flag) {
  115. transmit();
  116. try {
  117. Thread.sleep(500);
  118. } catch (InterruptedException e) {
  119. e.printStackTrace();
  120. }
  121. }
  122. }
  123. public void transmit() {
  124. for(String str : container.strs) {
  125. try {
  126. if(str==null) {
  127. continue;
  128. }
  129. System.out.println("已转发消息:"+str);
  130. container.now++;
  131. dos.writeUTF(str);
  132. dos.flush();
  133. } catch (IOException e) {
  134. e.printStackTrace();
  135. }
  136. }
  137. container.reset();//转发完后清空
  138.  
  139. }
  140. }
  141. }

  

演示

服务器端运行一个,客户端运行多个。

66 网络编程(五)——TCP多线程实现多人聊天室的更多相关文章

  1. 基于tcp和多线程的多人聊天室-C语言

    之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室. 具体的实现过程: 服务器端:绑定socket对象->设置监听数-> ...

  2. 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  3. 【Chat】实验 -- 实现 C/C++下TCP, 服务器/客户端 "多人聊天室"

    本次实验利用TCP/IP, 语言环境为 C/C++ 利用套接字Socket编程,以及线程处理, 实现Server/CLient 之间多人的聊天系统的基本功能. 结果大致如: 下面贴上代码(参考参考.. ...

  4. 网络编程初探--使用UDP协议的简易聊天室

    UDP是一种无连接的传输层协议,提供快速不可靠的服务. 一.发送端 * 创建UDP发送端 * 步骤: * 1.建立UDP的Socket服务 * 2.将要发送的数据封装到数据包中 * 3.通过UDP的s ...

  5. C#网络编程之---TCP协议的同步通信(二)

    上一篇学习日记C#网络编程之--TCP协议(一)中以服务端接受客户端的请求连接结尾既然服务端已经与客户端建立了连接,那么沟通通道已经打通,载满数据的小火车就可以彼此传送和接收了.现在让我们来看看数据的 ...

  6. Linux网络编程(五)

    /*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...

  7. Java 网络编程 -- 基于TCP 模拟多用户登录

    Java TCP的基本操作参考前一篇:Java 网络编程 – 基于TCP实现文件上传 实现多用户操作之前先实现以下单用户操作,假设目前有一个用户: 账号:zs 密码:123 服务端: public c ...

  8. 嵌入式linux的网络编程(1)--TCP/IP协议概述

    嵌入式linux的网络编程(1)--TCP/IP协议概述 1.OSI参考模型及TCP/IP参考模型 通信协议用于协调不同网络设备之间的信息交换,它们建立了设备之间互相识别的信息机制.大家一定都听说过著 ...

  9. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

随机推荐

  1. Sharding-Jdbc概念与使用技巧

    1. Sharding-Jdbc概念与使用技巧 此讲解版本为4.0.0-RC1,目前最新的版本 2019年5月21日发布 1.1. 绑定表 指分片规则一致的主表和子表.例如:t_order表和t_or ...

  2. CSS泣鬼神

    博主网站 一.CSS介绍和语法 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 每个CSS样式由两个组成部分:选择器和声明.声明又包括属性和属性值.每个声明 ...

  3. loadrunner 基本操作

    1.录制(录制选项) 2.回放(运行时设置) 3.添加事物 4.参数化 5.内容检查 6.添加集合点 1.在脚本中添加集合点函数如下: lr_rendezvous("集合点") / ...

  4. Hibernate框架学习1

    框架是什么 1.框架是用来提高开发效率的 2.封装了好了一些功能.我们需要使用这些功能时,调用即可.不需要再手动实现. 3.所以框架可以理解成是一个半成品的项目.只要懂得如何驾驭这些功能即可. orm ...

  5. Scrapy的中间件(二)

    爬虫中间件 爬虫中间件的用法与下载器中间件非常相似,只是它们的作用对象不同.下载器中间件的作用对象是请求request和返回response:爬虫中间件的作用对象是爬虫,更具体地来说,就是写在spid ...

  6. div垂直居中水平居中css

    width: 860px; height: 500px; position: absolute; margin-left: -430px; margin-top: -250px; top: 50%; ...

  7. ABP .net framework版 的发布

    先正常的发布流程走 特别的如下图

  8. django -- ORM查询

    前戏 在我们之前操作ORM中,你也许是启动Django项目,通过地址访问固定的函数,或者在pycharm里的python console里执行,第一种比较麻烦,而且每次都要启动项目,写路由,第二种虽然 ...

  9. linux定时器的实现方法

    Linux提供定时器机制,可以指定在未来的某个时刻发生某个事件,定时器的结构如下: struct timer_list { struct list_head list; unsigned long e ...

  10. 图的遍历 | 1131地铁图: dfs复杂模拟题

    这题在搞清楚思路绕过坑后,还是可以写的出通过sample data的代码的.但是不能AC,让我很气. 最后查清原因:还是对dfs本质理解的不够. wa代码: vis[s]=1; dfs(s,e,0); ...