思路

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

客户端 代码

package _20191218;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner; /**
* 多人聊天室,客户端,实时发送接收数据,要实现多线程
*/ public class TCPMultipleChatClient {
public static void main(String[] args) {
System.out.println("-------局域网聊天室-----------");
Scanner scan1 = new Scanner(System.in);
System.out.print("请输入您的昵称:");
String username = scan1.nextLine();
String address = "176.195.108.53";//服务器地址
int port = 6788;//服务器程序端口
Socket client = null;
try {
client = new Socket(address,port);
System.out.println("成功登入,可以开始聊天了!");
System.out.println("------------------------");
} catch (UnknownHostException e) {
System.err.println("服务器连接失败");
} catch (IOException e) {
System.err.println("服务器连接失败");
}
/**
* 启动接收器与发送器
*/
new Thread(new Sender(client),username).start();
new Thread(new Receiver(client)).start();
}
}
//发送器:实现Runnable
class Sender implements Runnable{
private boolean flag = true;//服务器存活为 true
//输出流
private DataOutputStream dos;
//构造器:初始化
public Sender(Socket client) {
try {
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
System.err.println("服务器未开启,连接失败");
}
}
public void sendMessage() {
Scanner scan = new Scanner(System.in);
String message = scan.nextLine();
try {
dos.writeUTF(Thread.currentThread().getName()+":"+message);
dos.flush();
} catch (IOException e) {
System.err.println("Sender:服务器关闭");
flag = false;
}
}
public void run() {
while(flag) {
sendMessage();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//接收器:实现Runnable
class Receiver implements Runnable{
private boolean flag = true;//服务器存活为 true
//输入流
private DataInputStream dis;
public Receiver(Socket client) {
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//读取消息
public void readMessage() {
try {
System.out.println(dis.readUTF());
} catch (IOException e) {
System.err.println("Reciver:服务器关闭");
flag =false;
}
}
public void run() {
while(flag) {
readMessage();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//}

  

服务器端 代码

package _20191218;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner; /**
* 多人聊天室,服务端,实时转发数据
*/
public class TCPMultipleChatServer {
public static void main(String[] args) {
System.out.println("服务端开启");
//创建服务器端
ServerSocket server = null;
try {
server = new ServerSocket(6788);//服务器端口
} catch (IOException e) {
e.printStackTrace();
}
//容器
Container container = new Container();
//循环监听
while(true) {
//阻塞监听连接请求
try {
Socket client = server.accept();
System.out.println("一位用户成功连接");
container.doCount();
//开启接收器
new Thread(new Receiver(client,container)).start();
//开启转发器
new Thread(new Transmit(client,container)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
} static class Container{
// StringBuffer wrap = new StringBuffer();
static int userCount = 0;//当前用户量
private int now = 0;//已转发量
private String[] strs = new String[1024];//消息队列
private int i = 0;//消息计数器
public void add(String message) {
strs[i]=message;
i++;
}
public static void doCount() {//用户量加一
userCount++;
}
public void subUserCount() {//用户量减一
userCount--;
}
public void reset() {
if(now == userCount) {
strs = new String[1024];
now = 0;
}
}
}
static class Receiver implements Runnable{
private boolean flag = true;
private Container container;
private DataInputStream dis;
public Receiver(Socket client,Container container) {
this.container = container;
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//读取消息
public void readMessage() {
try {
//存入容器
String str = "";
if(!(str = dis.readUTF()).equals("")) {
container.add(str);
} } catch (IOException e) {
flag = false;
System.err.println("Read:用户已离开会话");
container.subUserCount();
}
}
public void run() {
while(flag) {
readMessage();
}
}
}
//转发
static class Transmit implements Runnable{
private boolean flag = true;
private Container container;
private DataOutputStream dos;
public Transmit(Socket client, Container container) {
this.container = container;
try {
this.dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
flag = false;
System.err.println("Transmit:用户已离开会话");
}
} public void run() {
while(flag) {
transmit();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void transmit() {
for(String str : container.strs) {
try {
if(str==null) {
continue;
}
System.out.println("已转发消息:"+str);
container.now++;
dos.writeUTF(str);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
container.reset();//转发完后清空 }
}
}

  

演示

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

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. ES6 变量与解构(二)

    一.变量的声明与使用 [测试示例需要在node环境中测试,浏览器环境下并不完全兼容ES6代码]ES6中可以使用 {} 来包含任意一段代码,被 {} 包裹的内容称为一个代码块(局部作用域) let关键字 ...

  2. js正则只能包含小写数字分割符,切不能以分割符开头和结尾

    const version = /^(?!_)(?!.*-$)[a-z0-9_]+$/; 1.一个正则表达式,只含有数字.小写字母.中划线不能以中划线开头和结尾: ^(?!-)(?!.*-$)[a-z ...

  3. Android调用系统相机和相册并解决data为空,OOM,图片角度不对的问题

    最近公司项目用到手机拍照的问题,好不容易在网上copy了一些代码,但是运行起来一大堆bug,先是三星手机上运行程序直接崩掉,debug了一下原来是onActivityResult中data返回为空,找 ...

  4. Spring Security :CsrfFilter过滤器

    spring security框架提供的默认登录页面,会有一个name属性值为_csrf的隐藏域: 这是框架在用户访问登录页面之前就生成的,保存在内存中,当用户提交表单的时候会跟着一起提交: 然后会经 ...

  5. VirtualBox打开VMware虚拟机

    下载安装VirtualBox 打开VirtualBox,选择新建 设置如下: 之后就可以直接打开虚拟机了.

  6. Python从零开始——安装与运行

  7. rhel7学习第五天

    管道命令符的功能的确强大!

  8. matplot 绘制定制饼图

    1.普通风格 代码 import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = 'SimHei' # 使图形中的中文正常编码显示 ...

  9. MAZE(2019年牛客多校第二场E题+线段树+矩阵乘法)

    题目链接 传送门 题意 在一张\(n\times m\)的矩阵里面,你每次可以往左右和下三个方向移动(不能回到上一次所在的格子),\(1\)表示这个位置是墙,\(0\)为空地. 现在有\(q\)次操作 ...

  10. python操作mysql(增、删、改、查)

    用python操作数据库,特别是做性能测试造存量数据时特别简单方便,比存储过程方便多了. 连接数据库 前提:安装mysql.python,参考:https://www.cnblogs.com/Uncl ...