前言:

本文是我在学习尚学堂JAVA300集第二季网络编程部分仿照视频内容实现而成

具体可以去尚学堂官网观看视频学习

一、实现思路

   实现聊天室的最核心部分就是JAVA的TCP网络编程。

  TCP 传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议 ,在Java中我们利用ServerSocket类来建立服务端,利用Socket类来建立客户端。这里要注意,在TCP中,Socket实际上是指

Server端与Client端建立的一个双向的流通道,我们利用这个流通道实现数据的传输。

  我们将聊天室分为两部分,客户端和服务端.

  对于客户端,主要有两个功能,信息的收与信息的发。因为这两个功能需要并行进行,并且要不停的进行收和发,所以将这两个功能抽象成两个实现Runnable接口的(Send,Recevice)类,每次客户端Client启动,建立一个Socket,并利用这个Socket建立一个收线程(Recevice类)和发线程(Send)类

  对于服务器端,因为我们要不停的监听是否有新的连接进来,所有要通过一个循环不停的接收,这里的接收函数是阻塞式的。因为我们要对所有的连接进行同时处理,所有我们将新得到连接抽象成一个实现Runnable接口的User类,利用多线程进程对每一个连接并行处理。为了方便多个连接之间的交互,我们将User类作为Server类的一个内部类使用。

二、实现过程

1.客户端

Client类:

package top.dlkkill.tcp.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket; public class Client { public static void main(String[] args) throws IOException {
//从控制台获得输入
BufferedReader console=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入您的名字:");
String name=console.readLine();
if(name.equals(""))
return;
Socket client=null;
try {
//建立新连接,注意这里创建好就已经连接上了,要保证服务端已经开启
client=new Socket("localhost", 8888);
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.err.println(name+"连接失败");
}
//两条线路,一条负责发,一条负责收
new Thread(new Send(client,name)).start();
new Thread(new Recevice(client)).start();
} }

Send类

package top.dlkkill.tcp.chat;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket; public class Send implements Runnable{ //负责写出,将信息传输到服务端
private DataOutputStream os;
//负责读取控制台输入
private BufferedReader console;
//线程标识
private boolean isRun=true; //通过死循环保证线程一直进行
@Override
public void run() {
// TODO Auto-generated method stub
while(isRun) {
send(getMsgFromConsole());
}
} //构造方法,利用Socket类获得流
public Send(Socket client,String name) {
// TODO Auto-generated constructor stub
try {
os=new DataOutputStream(client.getOutputStream());
console=new BufferedReader(new InputStreamReader(System.in));
send(name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isRun=false;
CloseUtil.closeAll(os,console);
}
} //发送函数
public void send(String msg) { try {
if(msg!=null&&!msg.equals("")) {
os.writeUTF(msg);
os.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isRun=false;
CloseUtil.closeAll(os,console);
}
} //从控制台不断读取信息
public String getMsgFromConsole() {
String msg=null;
try {
msg=console.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isRun=false;
CloseUtil.closeAll(os,console);
}
return msg;
}
}

Recevice类

package top.dlkkill.tcp.chat;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket; public class Recevice implements Runnable{ //负责读取服务端发送过来的信息
private DataInputStream is;
//线程标识
private boolean isRun=true; @Override
public void run() {
// TODO Auto-generated method stub
while(isRun){
recevice();
}
} public Recevice(Socket client) {
// TODO Auto-generated constructor stub
try {
is=new DataInputStream(client.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
CloseUtil.closeAll(is);
isRun=false;
}
} public void recevice() {
String msg=null;
try {
msg=is.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
CloseUtil.closeAll(is);
isRun=false;
}
System.out.println(msg);
} }

2.服务端

Server类(内部有一个User类)

package top.dlkkill.tcp.chat;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet; public class Server { //保存所有的连接
private HashSet<User> users;
//线程标识
private boolean run=true; public static void main(String[] args) { //创建一个Server类
Server server=new Server();
try {
//启动服务器
server.start();
} catch (IOException e) {
e.printStackTrace();
}
} public Server() {
run=true;
users=new HashSet<User>();
} public void start() throws IOException {
//创建一个服务器端
ServerSocket server=new ServerSocket(8888);
while(run) {
//不断接收一个新的连接,利用新连接创建一个User线程进行处理
Socket client= server.accept();
User user=new User(client);
users.add(user);
new Thread(user).start();
}
} public void stop() {
run=false;
} //代表一个连接,负责信息的接收与转发
private class User implements Runnable{ //记录连接用户的名字
private String name; public String getName() {
return name;
}
//负责接收
private DataInputStream is;
//负责发送
private DataOutputStream os;
//线程标识
private boolean isRun=true; public User(Socket client) { try {
is=new DataInputStream(client.getInputStream());
os=new DataOutputStream(client.getOutputStream());
isRun=true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isRun=false;
CloseUtil.closeAll(is,os);
}
try {
name=is.readUTF();
this.sendOther(new String("欢迎"+name+"进入聊天室"),true);
this.send(new String("系统:您已经进入了聊天室"));
}catch (Exception e) {
// TODO: handle exception
}
} @Override
public void run() {
// TODO Auto-generated method stub
while(isRun) {
this.sendOther(this.revice(),false);
}
} //接收信息
public String revice() {
String msg = null;
try {
msg=is.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return msg;
} //发送信息
public void send(String msg) {
try {
os.writeUTF(msg);
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} //将信息转发给其他用户,同时实现了私聊功能和系统信息功能
//因为是内部类,所以可以访问Server类中的private HashSet<User> users
//@XX:代表向XX发送私聊信息
public void sendOther(String msg,boolean admin) {
if(msg.startsWith("@")&&msg.contains(":")) {
String toname=msg.substring(1, msg.indexOf(":"));
String newmsg=msg.substring(msg.indexOf(":")+1);
for (User user : users) {
if(user.getName().equals(toname)) {
user.send(this.name+"悄悄的对你说:"+newmsg);
}
}
}else {
for (User client : users) {
if(client!=this) {
if(admin)
client.send("系统:"+":"+msg);
else
client.send(this.name+":"+msg);
}
}
}
}
}
}

3.工具类

CloseUtil类(负责关闭流)

package top.dlkkill.tcp.chat;

import java.io.Closeable;

public class CloseUtil {
public static void closeAll(Closeable ...io) {
for (Closeable closeable : io) {
try {
if(closeable!=null)
closeable.close();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}

Java利用TCP编程实现简单聊天室的更多相关文章

  1. java web利用mvc结构实现简单聊天室功能

    简单聊天室采用各种内部对象不适用数据库实现. 一个聊天室要实现的基本功能是:         1.用户登录进入聊天室, 2.用户发言 3.用户可以看见别人发言 刚才算是简单的需求分析了,现在就应该是进 ...

  2. JAVA基础知识之网络编程——-基于TCP通信的简单聊天室

    下面将基于TCP协议用JAVA写一个非常简单的聊天室程序, 聊天室具有以下功能, 在服务器端,可以接受客户端注册(用户名),可以显示注册成功的账户 在客户端,可以注册一个账号,并用这个账号发送信息 发 ...

  3. (ASP.net)利用Application对象制作简单聊天室

    1.共四个页面,Default.aspx默认主页,Default2.aspx聊天室 default3.aspx显示用户列表,default4.aspx显示聊天内容,添加一个Global.asax全局程 ...

  4. Java 多线程Socket编程通讯--实现聊天室代码

    1.创建服务器类 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import ja ...

  5. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  6. 如何利用WebSocket实现网页版聊天室

    花了将近一周的时间终于完成了利用WebSocket完成网页版聊天室这个小demo,期间还走过了一段"看似弯曲"的道路,但是我想其实也不算是弯路吧,因为你走过的路必将留下你的足迹.这 ...

  7. SpringBoot 搭建简单聊天室

    SpringBoot 搭建简单聊天室(queue 点对点) 1.引用 SpringBoot 搭建 WebSocket 链接 https://www.cnblogs.com/yi1036943655/p ...

  8. TCP/IP以及Socket聊天室带类库源码分享

    TCP/IP以及Socket聊天室带类库源码分享 最近遇到个设备,需要去和客户的软件做一个网络通信交互,一般的我们的上位机都是作为客户端来和设备通信的,这次要作为服务端来监听客户端,在这个背景下,我查 ...

  9. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

随机推荐

  1. Python_对Excel表进行操作

    1.使用Python统计Excel表中的行数 import xlrd # 计算一个工作簿中所有Sheet表的行数 def count_book(work_book): workbook = xlrd. ...

  2. Jmeter压测基础(二)——Badboy功能、Jmeter参数化、检查点、集合点、动态关联、图形监控

    Badboy 以下稍微介绍一下badboy的部分功能: 1.Record;play(badboy打开后默认是recording状态) 2.Assertion(检查点/断言) 3.Variable: t ...

  3. Map集合转成json数据

    maven项目需要导入一下依赖: <dependency> <groupId>net.sf.json-lib</groupId> <artifactId> ...

  4. springcloud第八步:hystrix解决服务雪崩

    断路器(Hystrix) 为什么需要 Hystrix? 在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用(RPC).为了保证其高可用,单个服务又必须集群部署.由于网络原因或者自 ...

  5. pc端字体大小自适应几种方法

    $(window).resize(function ()// 绑定到窗口的这个事件中 {  var whdef = 100/1920;// 表示1920的设计图,使用100PX的默认值  var wH ...

  6. YII - 打印 SQL

    $query = Order::find()->select(['order_sys_id'])->where(['order_car_id'=>'AA','order_status ...

  7. 学习MySQL过程中的随笔一

    第一天: 关于安装出现了很多问题,各种不懂的bug,没得法只能在网上查找解决方法,终于!!! 登录成功了,一下午的时间 附上参考资料:https://blog.csdn.net/weibo_boer/ ...

  8. java 写一个JSON解析的工具类

    上面是一个标准的json的响应内容截图,第一个红圈”per_page”是一个json对象,我们可以根据”per_page”来找到对应值是3,而第二个红圈“data”是一个JSON数组,而不是对象,不能 ...

  9. Cocos Creator JS web平台复制粘贴代码(亲测可用)

    Cocos Creator JS web平台复制粘贴代码(亲测可用) 1 webCopyString: function(str){ var input = str; const el = docum ...

  10. cdh安装spark遇到的几个BUG

    spark安装后启动: [zdwy@master spark]$ sbin/start-all.sh starting org.apache.spark.deploy.master.Master, l ...