思路

  • 客户端读写各一个类,可以使内部类,实现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. Spring Boot2(八):性感banner,在线发牌

    本文在个人技术博客[鸟不拉屎]同步发布,详情可猛戳 亦可扫描文章末尾二维码关注个人公众号[鸟不拉屎] emmm,没有啥前言 玩过SpringBoot的都知道,SpringBoot启动的时候,默认会在控 ...

  2. Java程序员的魔法杖-Arthas 3.1.2版本发布了

    Arthas已经成为我日常运维.线上排查的必备之品,听说最近更新版本了,今天这篇文章看下又增加了什么新的能力. Arthas是Alibaba开源的Java诊断工具,深受开发者喜爱. Github:ht ...

  3. java获取客户端请求IP地址(公网ip)

    之前写了一个获取ip地址的方法,但是放网上一查显示此Ip地址是局域网ip地址,要是想获取请求端的真实公网ip地址怎么样了,看了一些别人的博客后发现,想要获取客户端的公网ip必须借助第三方. packa ...

  4. Bash Shell如何实现动态变量

    有时需要遍历所有变量,但是如何生成变量名之后,再取到变量名里的值呢? 具体方法 测试动态变量的脚本: #!/bin/bash a=1 b=abc abc1='12345abc' tmp1=$(eval ...

  5. Elasticsearch+x-pack认证license过期处理

    介绍: x-pack是Elasticsearch中的一个plugin,主要功能是实现认证功能 报错: 类似下面这样的报错,是因为licese过期导致的 解决: 1.首先去Elasticsearch的官 ...

  6. Httpclient文件上传

    public static void upload(String url,File file,String filename) { CloseableHttpClient httpclient = H ...

  7. Fiddler抓包设置

    介绍 Fiddler 在 PC 端和移动端,模拟器抓取数据包 Fiddler抓取PC端数据包: 这里 Fiddler 抓取网页客户端的数据包时,其原理就是在 客户端/浏览器 和 服务器端 之间,加上了 ...

  8. jquery-ui提供的拖拽方法

    项目当中遇到了任意拖动div标签的功能,找到了jqueryui提供的draggable的插件,这个插件可以实现任意的div的移动,也可以移动到整个屏幕或者在父元素的范围内进行移动. 插件的api    ...

  9. httprunner学习25-文件上传multipart/form-data

    前言 httprunner上传文件接口,其实跟requests上传文件的接口是一样的,之前在python接口系列里面有案例 python接口自动化16-multipart/form-data上传图片 ...

  10. 字符串format()方法的基本使用

    <模板字符串>.format(<逗号分隔的参数>) 其中,模板字符串是一个由字符串和槽组成的字符串,用来控制字符串和变量的显示效果.槽用大括号({})表示,对应format() ...