热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:Java利用TCP编程实现简单聊天室

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java利用TCP编程实现简单聊天室相关的知识,希望对你有一定的参考价值。前言:

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java利用TCP编程实现简单聊天室相关的知识,希望对你有一定的参考价值。



前言:

本文是我在学习尚学堂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 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();
}

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 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();
}
}
}
}

推荐阅读
  • 2017-2018年度《网络编程与安全》第五次实验报告
    本报告详细记录了2017-2018学年《网络编程与安全》课程第五次实验的具体内容、实验过程、遇到的问题及解决方案。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • Python + Pytest 接口自动化测试中 Token 关联登录的实现方法
    本文将深入探讨 Python 和 Pytest 在接口自动化测试中如何实现 Token 关联登录,内容详尽、逻辑清晰,旨在帮助读者掌握这一关键技能。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • 深入解析Java多线程与并发库的应用:空中网实习生面试题详解
    本文详细探讨了Java多线程与并发库的高级应用,结合空中网在挑选实习生时的面试题目,深入分析了相关技术要点和实现细节。文章通过具体的代码示例展示了如何使用Semaphore和SynchronousQueue来管理线程同步和任务调度。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • ListView简单使用
    先上效果:主要实现了Listview的绑定和点击事件。项目资源结构如下:先创建一个动物类,用来装载数据:Animal类如下:packagecom.example.simplelis ... [详细]
  • 本文详细介绍了Java编程中的基本运算符,包括算术、赋值、关系和逻辑运算符,并深入探讨了三元运算符的使用。此外,还讲解了如何使用Scanner类进行用户输入处理以及if和switch语句等流程控制结构。 ... [详细]
  • 本文介绍了如何使用JFreeChart库创建一个美观且功能丰富的环形图。通过设置主题、字体和颜色等属性,可以生成符合特定需求的图表。 ... [详细]
  • 本文详细介绍了Java中的注解功能,包括如何定义注解类型、设置注解的应用范围及生命周期,并通过具体示例展示了如何利用反射机制访问注解信息。 ... [详细]
  • 在Java应用程序开发过程中,FTP协议被广泛用于文件的上传和下载操作。本文通过Jakarta Commons Net库中的FTPClient类,详细介绍如何实现文件的上传和下载功能。 ... [详细]
  • ▶书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall算法可能含负环的有边权有向图任意两点之间的最短路径●有边权有向图的邻接矩阵1 ... [详细]
  • 最近同事提了一个需求过来,他觉得项目对于第三方日志记录的太多了,只想记录一些业务相关的日志减少对于框架日志的显示。具体要求就是对于框架日志只显示warn等级以上的,而业务日志显示info等级以上 ... [详细]
author-avatar
chenyanni1030_430
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有