思路

  • 客户端读写各一个类,可以使内部类,实现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. Navicat连接mysql报错1862

    昨天重新设置了mysql的密码 因为之前一直都是不用密码登录的 因为是公司数据库还是要密码 但是加了密码我今天打开 然后再控制台重新设置一下密码就好了 mysql -u root -p SET PAS ...

  2. 查看LINUX系统的配置

    # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/cpuinfo # 查看CPU信息 # hostn ...

  3. SwitchGame---MybatisPLus

    //实体类package com.example.spring.entity; import cn.afterturn.easypoi.excel.annotation.Excel;import cn ...

  4. Spring框架快速入门

    ssm框架是目前最流行的框架之一.他包括Spring,springMVC,mybatis.今天来简单介绍一下spring. 1.spring是什么? 答:spring是一个轻量级的框架. 2.两大核心 ...

  5. 微信小程序+php 授权登陆,完整代码

    先上图        实现流程: 1.授权登陆按钮和正文信息放到了同一个页面,未授权的时候显示登陆按钮,已授权的时候隐藏登陆按钮,显示正文信息,当然也可以授权和正文分开成两个页面,在授权页面的onlo ...

  6. ML-逻辑回归推导

    认识 是一个经典的二元(y=0 或 y=1) 分类算法, 不是回归 输入特征还是线性回归, 输出是 [0,1] 的一个概率值, 其判别函数的形式为: \(P(y=1|x) = \frac {1}{1+ ...

  7. Spring通过配置类加载实体bean

    以下4个java类都在都一个包下: 1.定义接口 public interface AA { void play(); } 2.定义实体bean //组件注解,表明该类是一个组件 @Component ...

  8. 如何使用Activator.CreateInstance创建一个列表<T>,其中T在运行时是未知的?

    参考网址:https://cloud.tencent.com/developer/ask/185965 using System; using System.Collections.Generic; ...

  9. Java精通并发-Condition编程模式详解与分析

    继续上一次https://www.cnblogs.com/webor2006/p/11890688.html的Condition接口说明进行阅读: 上面这个程序会在之后手动来实现一下,说实话这种写法在 ...

  10. Wpf DataGrid动态添加列,行数据(一)

    由于最近有这方面的需求,而且刚接触wpf不久,在网上找了很多方法,都不是使用MVVM模式的,因为DataGrid的列不能绑定 这就难受了,我想了个折中的方法,这个是使用了MVVMLight的消息机制, ...