66 网络编程(五)——TCP多线程实现多人聊天室
思路
- 客户端读写各一个类,可以使内部类,实现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多线程实现多人聊天室的更多相关文章
- 基于tcp和多线程的多人聊天室-C语言
之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室. 具体的实现过程: 服务器端:绑定socket对象->设置监听数-> ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 【Chat】实验 -- 实现 C/C++下TCP, 服务器/客户端 "多人聊天室"
本次实验利用TCP/IP, 语言环境为 C/C++ 利用套接字Socket编程,以及线程处理, 实现Server/CLient 之间多人的聊天系统的基本功能. 结果大致如: 下面贴上代码(参考参考.. ...
- 网络编程初探--使用UDP协议的简易聊天室
UDP是一种无连接的传输层协议,提供快速不可靠的服务. 一.发送端 * 创建UDP发送端 * 步骤: * 1.建立UDP的Socket服务 * 2.将要发送的数据封装到数据包中 * 3.通过UDP的s ...
- C#网络编程之---TCP协议的同步通信(二)
上一篇学习日记C#网络编程之--TCP协议(一)中以服务端接受客户端的请求连接结尾既然服务端已经与客户端建立了连接,那么沟通通道已经打通,载满数据的小火车就可以彼此传送和接收了.现在让我们来看看数据的 ...
- Linux网络编程(五)
/*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...
- Java 网络编程 -- 基于TCP 模拟多用户登录
Java TCP的基本操作参考前一篇:Java 网络编程 – 基于TCP实现文件上传 实现多用户操作之前先实现以下单用户操作,假设目前有一个用户: 账号:zs 密码:123 服务端: public c ...
- 嵌入式linux的网络编程(1)--TCP/IP协议概述
嵌入式linux的网络编程(1)--TCP/IP协议概述 1.OSI参考模型及TCP/IP参考模型 通信协议用于协调不同网络设备之间的信息交换,它们建立了设备之间互相识别的信息机制.大家一定都听说过著 ...
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
随机推荐
- Android调用系统相机和相册并解决data为空,OOM,图片角度不对的问题
最近公司项目用到手机拍照的问题,好不容易在网上copy了一些代码,但是运行起来一大堆bug,先是三星手机上运行程序直接崩掉,debug了一下原来是onActivityResult中data返回为空,找 ...
- Kaldi语音识别快速入门
一.简介 Kaldi是使用C++编写的语音识别工具包,Apache License v2.0许可.主要供语音识别研究人员使用.Kaldi的目标和范围与HTK类似.目标是拥有易于修改和扩展的现代而灵活的 ...
- HP服务器重装centeos 6.3红屏错误码 Illegal Opcode
公司组装一个服务器要装centos 6.3 .出现一个问题 如果自动引导一切正常.如果手动分区重启后就会,红屏错误码 Illegal Opcode. 去网上问度娘各种不靠谱,有时说要 升级BIOS,从 ...
- 手写xpath定位公式
做web自动化,之前我们已经将环境搭建好了,现在的话总结下怎么定位元素的 最基本的元素定位是有6种: driver.find_element_by_id("") driver.fi ...
- 剑指offer-08 二叉树的下一个节点
剑指offer第8题,本来想找leetcode上对应的题,后来没找到,直接去牛客网上刷了. 题目描述: 给定一个二叉树和其中的一个结点(pNode),请找出中序遍历顺序的下一个结点并且返回.注意,树中 ...
- CodeForces 407E: k-d-sequence
题目传送门:CF407E. 题意简述: 给定非负整数 \(k,d\) 和一个长度为 \(n\)(\(1\le n\le 2\times 10^5\))的整数序列 \(a\). 求这个序列中最长的一个连 ...
- opencart卸载语言包要记得在后台进行设置否则会出错
今天ytkah在一个项目中把中文包卸载了,但是前端购买按钮变为空了,研究了一遍发现要把system - localisation - languages中的对应语言删除才可以.正确的卸载语言步骤是1. ...
- turtle模块
turtle(海龟)绘图用法 import turtle -->调出turtle库 setup()-->设置窗体大小和位置 turtle.setup(width,height,startx ...
- Flask视图之CBV示列
from flask import views, Flask app=Flask(__name__) class loginview( views.MethodView ): # 继承views. ...
- 洛谷 p3870 开关 线段树模板
这两天学了很长时间于是做了一道水题 我就用了模板,就连任何优化都没有 就AC了,复杂度也很爆炸10个点1500多毫秒 这个题就是把lazy[]改成记录下修改的次数,每次修改的时候mod 2,因为反过来 ...