思路

  • 客户端读写各一个类,可以使内部类,实现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. 【转载】C#的ArrayList使用Contains方法判断是否包含某个元素

    在C#的编程开发中,ArrayList集合是一个常用的非泛型类集合,在ArrayList集合中可以使用Contains方法判断是否包含某个元素数据,如果包含则返回true,否则返回false,Cont ...

  2. JavaScript中的类方法、对象方法、原型方法

    类方法:也叫函数方法,在JavaScript中函数也是一个对象,所以可以为函数添加属性以及方法: 对象方法:包括构造函数中的方法以及其原型上面的方法: 原型方法:一般用于对象实例共享,在原型上面添加该 ...

  3. 剑指:链表中倒数第k个节点

    题目描述 输入一个链表,输出该链表中倒数第k个结点. 解法 pre 指针走 k-1 步.之后 cur 指针指向 phead,然后两个指针同时走,直至 pre 指针到达尾结点. 即cur与pre始终相距 ...

  4. Linux搭建邮件服务器Postfix+Dovecot+MySQL+PHP

    用于搭建的服务器信息 阿里云 Centos 6.5 32位 安装过程1.安装Postfix 版本(2:2.6.6-8.el6) yum -y install postfix 安装完成还需要替换系统自带 ...

  5. MySQL索引(九)

    一.索引介绍 1.1 什么是索引 索引就好比一本书的目录,它会让你更快的找到内容. 让获取的数据更有目的性,从而提高数据库检索数据的性能. 分为以下四种: BTREE:B+树索引(基本上都是使用此索引 ...

  6. 【JSTL】JSTL标签库的常用标签

    一.JSTL技术 1.JSTL概述 JSTL(JSP Standard Tag Library),JSP标准标签库,可以嵌入在jsp页面中使用标签的形式完成业务逻辑等功能.jstl出现的目的同el一样 ...

  7. 词向量---ELMO

    1.ELMo(Embeddings from Language Models ) RNN-based language models(trained from lots of sentences) E ...

  8. 洛谷P2365 任务安排(斜率优化dp)

    传送门 思路: 最朴素的dp式子很好考虑:设\(dp(i,j)\)表示前\(i\)个任务,共\(j\)批的最小代价. 那么转移方程就有: \[ dp(i,j)=min\{dp(k,j-1)+(sumT ...

  9. 第06节-开源蓝牙协议BTStack框架分析

    本篇博客根据韦东山的视频,整理所得. 本篇博客讲解BTStack的框架,首先来看一下硬件的结构: 蓝牙模块接在电脑上,或是接在开发板上.不论接在哪,我们都需要编写程序来控制这个蓝牙模块. . 我们需要 ...

  10. 20180610模拟赛T3——书本整理

    [问题描述] 小明的书架上放了许多书,为了使书架变得整洁,小明决定整理书架,他将所有书按高度大小排列,这样排了之后虽然整齐了许多,但小明发现,书本的宽度不同,导致书架看上去还是有些凌乱.小明把这个凌乱 ...