基于java TCP实现网络通信聊天室《建议收藏附完整源码》

2年前 (2022) 程序员胖胖胖虎阿
393 0 0

🍅 作者主页:Java李杨勇 

🍅 简介:Java领域优质创作者🏆、Java李杨勇公号作者✌  简历模板、学习资料、面试题库、技术互助【关注我,都给你】

🍅 欢迎点赞 👍 收藏 ⭐留言 📝   

🍅  文末获取源码联系方式 📝  

1.1 前言

在信息化社会的今天,网络飞速发展,人们对网络的依赖越来越多,越来越离不开网 络,由此而产生的聊天工具越来越多,类似 MSNQQ,网络聊天时一类的聊天系统的发展日 新月异,因此产生了制作一个类似 QQ的网络聊天工具的想法,且通过制作该程序还能更好 的学习网络软件编程知识。 网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯。 网编程中有两 个主要的问题, 一个是如何准确的定位网络上一台或多台主机, 另一个就是找到主机后如何 可靠高效的进行数据传输。 在 TCP/IP 协议中 IP 层主要负责网络主机的定位,

数据传输的路 由,由 IP 地址可以唯一地确定 Internet 上的一台主机。 而 TCP层则提供面向应用的可靠的 或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心 IP 层是如何处理数 据的。 目前较为流行的网络编程模型是客户机

/ 服务器( C/S)结构。 即通信双方一方作为服 务器等待客户提出请求并予以响应。 客户则在需要服务时向服务器提出申请。

服务器一般作 为守护进程始终运行, 监听网络端口, 一旦有客户请求, 就会启动一个服务进程来响应该客 户,同时自己继续监听服务端口,使后来的客户也得到响应的服务。

1.2 设计要求

本课程设计的目标是利用套接字 socket ()设计一个聊天程序,该程序基于 C/S 模式, 客户机器向服务器发聊天请求,服务器应答并能显示客户机发过来的信息。

1.3 设计目的

通过设计一个网络聊天程序,对套接字、数据报通讯、 URL、与 URLConnectiom 的相关知 识有详细的了解和充分的认识。能将相关的只是运用到相关的实践中去。

1.4 功能实现

聊天室共分为客户端和服务端两部分,

服务器程序主要负责侦听客户端发来的消息,

客户 端需要登录到相应的服务器才可以实现正常的聊天功能。

服务器的主要功能有

1) 在特定端口上进行侦听,等待客户连接

2) 用户可以配置服务器的监听端口3) 向已经连接服务器的客户发送系统消息

5) 当停止服务时,断开所有用户的连接

客户端的主要功能

1) 连接到已经开启聊天服务的服务端

2) 用户可以配置要连接服务器端的 ip 地址和端口号

3) 用户可以配置连接后显示的用户名

4) 当服务器开启时。用户可以随时登陆

5) 用户可以向所有人或一个人发送消息

1.5 知识基础

应用到的java知识点有:

1. Thread 线程

线程池,线程启动,接口等。客户端,服务器端都用到了线程

2. Socket

使用了socket进行端口监听和数据传递

new Socket("localhost",port);

3. Swing图形化

简单的按钮,输入框,弹框等

4. 数据流

字符流包装、缓冲字符输出流包装、

PrintWrite(new OutputStream(new socket(".."),"UTF-8"),true)

部分代码:

定义服务器端的界面,添加事件侦听与事件处理。调用 start Socket方法来实现 服务端用户上线与下线的侦听, 调用 Socket类来实现服务器端的消息的 收发。

package chat;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 聊天室服务端
 * @author 李杨勇
 *
 */
public class Server {
	//运行在服务端的Socket 用来接收客户端的连接。 
	private ServerSocket server;
	//线程池
	private ExecutorService threadPool;
	//存放所有客户端输出流的共享集合
	private List<PrintWriter> allOut;
	
	/**
	 * 构造方法,用来初始化服务端
	 */
	public Server(){
		try {
			/*
			 * 初始化共享集合
			 */
			allOut = new ArrayList<PrintWriter>();
			
			/*
			 * 读取配置文件
			 * java.util.Properties
			 * 
			 */
			Properties properties = new Properties();
			/*
			 * void load(InputStream in)
			 * 该方法用于读取给定的流中的数据,然后进行解析
			 * 
			 * 我们可以使用FileInputStream这个流来读取我们
			 * 定义的配置文件config.properties,所以我们可以
			 * 创建这个流,然后将该流作为参数传给load方法。
			 * 这样Properties就可以通过FileInputStream读取
			 * 我们的配置文件了。
			 */
			FileInputStream fis 
				= new FileInputStream("config.properties");
			properties.load(fis);
			
			//获取服务端端口号
			/*
			 * String getProperty(String key)
			 * 给定配置文件中等号左面的内容,可以获取对应的
			 * 值
			 * serverport=8088
			 */
			String port = properties.getProperty("serverport");
			System.out.println("服务端口:"+port);
			/*
			 * 初始化ServerSocket时要传入一个参数
			 * 该参数就是服务端对外开启的服务端口
			 * 客户端就是通过该端口与服务端进行连接的
			 */
			server = new ServerSocket(Integer.parseInt(port));
			
			/*
			 *  获取线程的数量阿萨德
			 */
			String threadCount 
							= properties.getProperty("threadcount");
			System.out.println("线程池线程数量:"+threadCount);
			
			/*
			 * 初始化线程池
			 */
			threadPool = Executors.newFixedThreadPool(Integer.parseInt(threadCount));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 向共享集合中添加一个输出流
	 * @param out
	 */
	public synchronized void addOut(PrintWriter out){
		allOut.add(out);
	}
	/**
	 * 从共享集合中删除给定的输出流
	 * @param out
	 */
	public synchronized void removeOut(PrintWriter out){
		allOut.remove(out);
	}
	/**
	 * 遍历共享集合中的所有输出流,将给定的消息发送给所有
	 * 的客户端
	 * @param message
	 */
	public synchronized void sendMessageToAllClient(String message){
		for(PrintWriter out : allOut){
			out.println(message);
		}
	}
	
	
	
	/**
	 * 服务端开始工作的方法
	 */
	public void start(){
		try {
			/*
			 * Socket accept()
			 * 该方法是ServerSocket开始监听8088端口,这个方法
			 * 是一个阻塞方法,直到一个客户端连接为止,若客户端
			 * 连接了,会返回一个Socket,这个Socket就是用来与
			 * 该客户端进行通讯的。
			 */
			while(true){
				System.out.println("等待一个客户端连接...");
				Socket socket = server.accept();
				System.out.println("一个客户端连接了!");
				
				/*
				 * 启动一个线程,并将刚刚连接的客户端的Socket
				 * 传给它,让它去处理与这个客户端的交互。
				 */
				ClientHandler clientHandler
									= new ClientHandler(socket);
//				Thread t = new Thread(clientHandler);
//				t.start();
				threadPool.execute(clientHandler);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		Server server = new Server();
		server.start();
	}
	
	/**
	 * 该内部类是为服务端服务的。用来与一个客户端进行
	 * 交互的。
	 * @author 李杨勇
	 */
	class ClientHandler implements Runnable{
		/*
		 * 该线程用来交互的客户端的Socket
		 */
		private Socket socket;
		/*
		 * 该客户端的昵称
		 */
		private String nickName;
		
		public ClientHandler(Socket socket){
			this.socket = socket;
			/*
			 * 获取远程计算机的地址信息
			 */
			InetAddress address = socket.getInetAddress();
			//获取远程计算机的地址
			String add = address.getHostAddress();
			System.out.println(add+"上线了!");
			
		}
		
		public void run() {
			PrintWriter pw = null;
			try {
				/*
				 * 通过Socket获取输出流,用于将消息发送给
				 * 客户端
				 */
				OutputStream out = socket.getOutputStream();
				OutputStreamWriter osw
							= new OutputStreamWriter(out,"UTF-8");
				pw = new PrintWriter(osw,true);
				
				//将该客户端的输出流放入共享集合中
				addOut(pw);
				
				/*
				 * InputStream getInputStream()
				 * Socket的该方法用来获取远程计算机发送过来的数据
				 */
				InputStream in = socket.getInputStream();
				
				InputStreamReader isr
							= new InputStreamReader(in,"UTF-8");
				
				BufferedReader br = new BufferedReader(isr);
				/*
				 * 首先读取一行字符串,因为客户端发送过来的第一
				 * 行字符串是该客户端的昵称,读取到后将其设置到
				 * 属性nickName上
				 */
				nickName = br.readLine();
				
				/*
				 * 广播,该用户上线了
				 */
				sendMessageToAllClient("["+nickName+"]上线了");
				
				
				//读取客户端发送过来的一行字符串
				/*
				 * 使用BufferedReader的readLine方法读取客户端发送
				 * 过来的一行字符串时,由于客户端所使用的操作系统
				 * 不同,这里在客户端与服务端断开连接后,该方法的
				 * 反应是不同的。
				 */
				String message = null;
				while((message = br.readLine())!=null){
					//将读取到的内容转发给所有客户端
					sendMessageToAllClient(nickName+"说:"+message);
				}				
			
			} catch (Exception e) {
				
			} finally{
				//将该客户端的输出流从共享集合中删除
				removeOut(pw);
				
				//广播,通知所有客户端该用户下线了
				sendMessageToAllClient("["+nickName+"]下线了.");
				/*
				 * 将该客户端的socket关闭。
				 * 关闭socket同时也就将使用它获取的输入流与
				 * 输出流关掉了。
				 */
				try {
					socket.close();
				} catch (IOException e) {
				}
			}
			
		}
		
	}
	
}



功能实现截图:

首先启动server服务:

基于java TCP实现网络通信聊天室《建议收藏附完整源码》

 然后启动client:

client可以启动多个

基于java TCP实现网络通信聊天室《建议收藏附完整源码》

基于java TCP实现网络通信聊天室《建议收藏附完整源码》

这样一个简单的基于Java TCP模拟的聊天室完成了 

课程总结:

通过本次课程设计是我对网络通信的知识有了更深的了解。 加深了对 TCP/UDP协议具体 连接过程的理解。同时对套接字、数据报通讯、 URL、与 URLConnectiom 的相关知识有了充 分的认识。并将这些知识运用到具体的案例中去。本次课程设计不仅运用到套接字的知识, 同时运用到 java 中的 GUI 编程,在设计框架中运用到各种组件与布局,通过服务器和客户 端主框架的设计, 对 GUI编程中的各种组件和布局有了更清晰地了解。 将书本上所学的知识成功运用到实践中去。 通过本次课程设计使自己对在 Java 中所学的 Swing 组件, 面板容器, 事件处理,线程的创建、同步,输入输出处理,内部类,异常处理,和网络通信的知识有了 一个复习和运用。培养了自己的编程能力,将学习和实践结合起来。 在 Java 的学习过程中,往往程序自己看得懂,但是需把所学知识运用到实践中去时,往 往会遇到这样那样的问题, 本次课程设计极大了锻炼了自己的动手能力, 同时也使自己明白 了只有动手做才会将课本上的知识变为自己的。 只有自己参与实践, 才能发现问题, 解决问题,在解决问题的过程中提升自己的能力。 希望自己以后能更多的将理论结合实践,再动手 的过程中提高自己的编程能力和软件设计能力。

代码获取:

java TCP网络通信聊天室(源码+报告论文6000字)

相关Java实战项目精彩推送

基于java ssm springboot+VUE疫情防疫系统系统前后端分离设计和实现

基于java springboot+mybatis电影售票网站管理系统前台+后台设计和实现

基于java ssm springboot+mybatis酒庄内部管理系统设计和实现

基于JAVA springboot+mybatis智慧生活分享平台设计和实现

基于Java springboot+vue+redis前后端分离家具商城平台系统设计和实现

基于JAVA SSM springboot实现的抗疫物质信息管理系统设计和实现

查看更多博主首页更多实战项目 >>>

Java李杨勇 

获取源码:

总体来说这个项目功能相对还是比较简单优秀的、适合初学者作为课程设计和毕业设计参考 

查看下方微信公众号获取联系方式~

精彩系列推荐

Java毕设项目精品实战案例《100套》

HTML5大作业实战案例《100套》

相关文章

暂无评论

暂无评论...