Java Socket实现聊天室附1500行源代码

目录
  • 项目需求分析
    • 基础分析
    • 项目部分代码摘要
      • Dao的链表存储实现
      • ServerListen
      • ServerReceive
      • 再看一下客户端的ClientReceive
    • 项目问题
      • 选择框中出现的不是用户名
      • 服务端点击消息发送按钮没有反应
      • 不能显示在线人数
      • 服务端退出时没有消息

Java养成计划(打卡第31,2天)

内容管理:Sockect聊天室的实现

Java界面 使用了各种组件,对于这部分不了解的不用担心,目前掌握一个大概就OK

项目需求分析

需要完成一个简单聊天工具的界面及功能,实现服务器中转下的多客户端之间的通信,系统完成的功能有

  • 程序启动后能看到当前有那些机器上线,可弹出对话聊天框,可以在其中编辑要发送的聊天信息,并进行发送
  • 一旦某个网内的机器上线了,可即时通知,并能更新用户界面的用户列表
  • 双击某个列表项时,可弹出对话聊天框,可以在其中编辑要发送的信息并发送
  • 聊天界面人性化,下面时发送框,上面有已有聊天记录,并借助滚动条看到当次所有聊天记录
  • 当有人向本机器发送消息时,可显示用户接收到的信息,并且显示是谁所发,同时进行信息的回复

基础分析

首先这是一个聊天工具,使用的是C/S结构,要模拟就要使用net的Scocket和ServerSocket模拟客户端和服务端

这里综合运用了多种知识,已经不再是简单的java SE知识,其中界面编程占据主要代码,这里可以贴几张图看看效果,这是我肝了2天才肝完的,这里已经可以实现多态设备的连接

分为3个包

Sever包主要是服务器的相关代码,主要是实现与用户的交互

Dao包是模拟的数据库包,存储所有的用户信息,实现增删改的操作

Client是客户代码包,只要在电脑上运行这里的代码,就可以出现客户端界面,约定好ip和端口号就可以通信了。这里就真正实现了客户端型软件,只是软件功能简单,可以使用web编程实现另外一种架构
可以来看一下界面

再来看一下客户端和服务端的交流

项目部分代码摘要

Dao的链表存储实现

package Dao;

/**
 * 演示程序为了简化就不用数据库存储,使用单链表完成数据库各项功能
 * 这里一定要写测试代码检查各项功能是否可用
 * 最开开始我测试了add,del,find功能,却没有测试getCount功能,结果存在问题,后面突然放开测试才发现错误
 */
public class UserLinkList {
	private  Node head;
	private int count;

	public boolean addUser(Node client)
	{
		if(head == null)
		{//头节点也存储数据
			head = client;
			count++;
			return true;
		}
		else {
			Node p = head;
			for(;p.next != null;p = p.next);
			{
				p.next = client;
				count++;
				return true;
			}
		}
	}

	public int getCount() {
		return count;
	}

	public Node findUser(String name)
	{
		Node p = head;
		while(p != null )//p.next != null没有包含最后一个结点
		{
			if(p.username.equals(name))
			{
				return p;
			}
			p = p.next;
		}
		return null;
	}

	public Node findUser(int index)
	{
		int pos = 0;
		Node p = head;
		while(p != null&& pos < index)
		{
			p = p.next;
			pos++;
		}
		if(p != null&& pos == index)
		{
			return p;
		}
		return null;
	}

	public boolean delUser(Node client)
	{//删除后长度也要减少
		Node p = head;
		if(p.username.equals(client.username))
		{//删除头结点
			head = head.next;
			count--;
			return true;
		}
		while(p != null)
		{//忘记循环了
			if(p.next.username.equals(client.username))
			{
				p.next = p.next.next;
				count--;
				return true;
			}
			p = p.next;
		}
		return false;
	}

	/**
	 * 这里可以设置一个显示的方法,供检查使用
	 */
	public void display() {
		Node p = head;
		int pos = 1;
		while(p != null)
		{
			System.out.println("第"+pos + "个用户"+p.username);
			p = p.next;
			pos++;
		}
	}
}
/*
	public static void main(String[] args) {//经过测试发现没有问题,可以正常使用
		Node client1 = new Node();
		client1.username = "张三";
		Node client2 = new Node();
		client2.username = "李四";
		Node client3 = new Node();
		client3.username = "王五";
		//其他的就不测试了,反正该项就可以测试了
		UserLinkList userLinkList = new UserLinkList();//自动初始化
		userLinkList.addUser(client1);
		userLinkList.addUser(client2);
		userLinkList.addUser(client3);
//		userLinkList.display();
		Node node = userLinkList.findUser(0);
		userLinkList.delUser(node);
		userLinkList.display();
		System.out.println(userLinkList.getCount());
	}
*/

现在编写这段代码应当是非常简单的,注意一定要测试

ServerListen

简单看一下这个监听线程,可以监听用户是否上线

package Server;
/**
 * @author OMEY-PC
 *本程序的作用是实现服务器侦听的线程化,其中run方法通过client = new Node();创建一个客户端对象,通过client.socket = server.accept来设定接口,通过client.input
 *output来建立输入输出流
 */

import java.io.*;
import java.net.*;
import Dao.*; //连接数据
import javax.swing.*;

public class ServerListen extends Thread{
	ServerSocket server;
	JComboBox combobox;
	JTextArea textarea;
	JTextField textfield;
	UserLinkList userLinkList;
	Node client;
	ServerReceive recvThread;
	public boolean isStop;
	/**
	 * 聊天服务端的用户上下线侦听类
	 */
	public ServerListen(ServerSocket server,JComboBox combobox,JTextArea textarea,JTextField textField,UserLinkList userLinkList) {
		this.server = server;
		this.combobox = combobox;
		this.textarea = textarea;
		this.textfield = textField;
		this.userLinkList = userLinkList;
		isStop = false;
	}
	@Override
	public void run() {
		while(!isStop && !server.isClosed())//没有停止服务
		{
			try {
				client = new Node();
				client.socket = server.accept();//用来指代所连接的客户端
				client.output = new ObjectOutputStream(client.socket.getOutputStream());
				client.output.flush();
				client.input = new ObjectInputStream(client.socket.getInputStream());
				client.username = (String)client.input.readObject();
				//显示提示信息
			    combobox.addItem(client.username);//改成用户名
			    userLinkList.addUser(client);
			    textarea.append("用户" + client.username+"上线"+"\n");
			    textfield.setText("在线用户"+ userLinkList.getCount()+"人\n");

			    recvThread = new ServerReceive(textarea,textfield,combobox,client,userLinkList);
			    recvThread.start();//启动线程
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

ServerReceive

该线程实现服务器与用户之间的信息交互

package Server;
/**
 * @author OMEY-PC
 *服务器收发消息的类
 */

import java.net.ServerSocket;

import javax.swing.*;
import Dao.*;

public class ServerReceive extends Thread{
	JTextArea textarea;//消息展示域
	JTextField textfield;//文本输入域
	JComboBox combobox; //复选框
	Node client;//用户
	UserLinkList userLinkList;
	public boolean isStop;
	public ServerReceive(JTextArea textarea, JTextField textfield, JComboBox combobox, Node client,
			UserLinkList userLinkList) {
		this.textarea = textarea;
		this.textfield = textfield;
		this.combobox = combobox;
		this.client = client;
		this.userLinkList = userLinkList;
		isStop = false;
	}

	@Override
	public void run()
	{
		//向所有人发送用户的列表
		sendUserList();
		while(!isStop && !client.socket.isClosed())
		{
			try {//类型,对谁,状况,行为,信息
				String type = (String)client.input.readObject();
				if(type.equalsIgnoreCase("聊天信息"))
				{
					String toSomebody =(String)client.input.readObject();//从客户端接收信息
					String status = (String)client.input.readObject();
					String action = (String)client.input.readObject();
					String message = (String)client.input.readObject();
					String msg = client.username+" "+ action + "对"+ toSomebody +" 说 " + message + "\n";//接收的消息
					if(status.equalsIgnoreCase("悄悄话"))
					{
						msg = "[悄悄话]" + msg; //若为悄悄话,就在前面加上标识
					}
					textarea.append(msg);
					if(toSomebody.equalsIgnoreCase("所有人"))
					{
						sendToAll(msg);//这里是接受的用户消息,和之前的向所有人发消息不一样
					}
					else {//向用户发消息
						try {
							client.output.writeObject("聊天信息");
							client.output.flush();//刷新流
							client.output.writeObject(msg);
							client.output.flush();
						}catch (Exception e) {
							e.printStackTrace();
						}
						Node node = userLinkList.findUser(toSomebody);
						if(node != null)
						{
							node.output.writeObject("聊天信息");
							node.output.flush();
							node.output.writeObject(msg);//向选定信息发送信息
							node.output.flush();//刷新输出流缓冲区中的信息
						}
					}
			    }
				else if(type.equalsIgnoreCase("用户下线"))
				{
					Node node = userLinkList.findUser(client.username);
					userLinkList.delUser(node);
					String msg = "用户"+ client.username +"下线\n";
					int count = userLinkList.getCount();
					combobox.removeAllItems();
					combobox.addItem("所有人");
					int i = 0;
				    while(i < count)
				    {
				    	node = userLinkList.findUser(i);
				    	if(node == null)
				    	{
				    		i++;
				    		continue;
				    	}
				    	combobox.addItem(node.username);
				    	i++;
				    }
					combobox.setSelectedIndex(0);//选择第一个,所有人
					textarea.append(msg);
					textfield.setText("在线用户"+ userLinkList.getCount() +"人\n");

					sendToAll(msg);
					sendUserList();//重新发送用户列表
					break;
				}
		    }catch (Exception e) {
				e.printStackTrace();
			}
	    }
	}
	/**
	 * 向所有人发送消息
	 */
	public void sendToAll(String msg)
	{
		int count = userLinkList.getCount();
		int i = 0;
		while(i < count)
		{//给用户列表中的每一个人都发送消息
			Node node = userLinkList.findUser(i);
			if(node == null)
			{
				i++;
				continue;
			}
			try {//输出流
				node.output.writeObject("聊天信息");
				node.output.flush();
				node.output.writeObject(msg);//聊天消息写入输出流(to client)
				node.output.flush();
			}catch (Exception e) {
				e.printStackTrace();
			}
			i++;
		}
	}
	/**
	 * 向所有人发送用户列表
	 */
	public void sendUserList() {
		String userList = "";
		int count = userLinkList.getCount();
		int i = 0;
		while(i < count)
		{
			Node node = userLinkList.findUser(i);
			if(node == null)
			{
				i++;
				continue;
			}
			userList += node.username;
			userList += "\n";
			i++;
		}
		i = 0; //给每个人发送消息
		while(i < count)
		{
			Node node = userLinkList.findUser(i);
			if(node == null)
			{
				i++;
				continue;
			}
			try {
				node.output.writeObject("用户列表");
				node.output.flush();
				node.output.writeObject(userList);
				node.output.flush();
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		i++;
	}
}
/**
 * 本程序可以实现通过线程向所有人发送消息,用户列表,以及向选定的人发送聊天消息等,主要是是实现服务端收发消息的线程化,其中sendUserList()发送列表,
 * client.input.redObject()获取客户端发送到服务端的消息,通sendToAll(),将发送到发送到所有人的信息发送到各个客户端
 */

再看一下客户端的ClientReceive

该线程是实现客户端与系统之间的信息交互,注解丰富

package Client;

import java.io.*;
import java.net.*;

import javax.swing.*;

public class ClientReceive extends Thread{
	private JComboBox combobox;
	private JTextArea textarea;
	Socket socket;
	ObjectOutputStream output;
	ObjectInputStream input;
	JTextField showStatus;
	public ClientReceive(JComboBox combobox, JTextArea textarea, Socket socket, ObjectOutputStream output,
			ObjectInputStream input, JTextField showStatus) {
		this.combobox = combobox;
		this.textarea = textarea;
		this.socket = socket;
		this.output = output;
		this.input = input;
		this.showStatus = showStatus;
	}

	@Override
	public void run() {//从服务端获得消息
		while(!socket.isClosed())
		{
			try {
				String type = (String)input.readObject();//获得流,read读取信息
				if(type.equalsIgnoreCase("系统信息"))
				{
					String sysmsg = (String)input.readObject();
					textarea.append("系统信息" + sysmsg);
				}
				else if(type.equalsIgnoreCase("服务关闭"))
				{
					output.close();
					input.close();
					socket.close();
					textarea.append("服务器已经关闭!\n");
					break;
				}
				else if(type.equalsIgnoreCase("聊天信息"))
				{
					String message = (String)input.readObject();
					textarea.append(message);
				}
				else if(type.equalsIgnoreCase("用户列表"))
				{
					String userlist = (String)input.readObject();
					String[] usernames = userlist.split("\n"); //用换行符分隔
					combobox.removeAll();//先移出去
					int i = 0;
					combobox.addItem("所有人");
					while(i < usernames.length)
					{
						combobox.addItem(usernames[i]);
						i++;
					}
					combobox.setSelectedIndex(0);
					showStatus.setText("在线用户"+ usernames.length +" 人");
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

其余的界面的部分就不放出来了,代码太长,每个都有400多行,如果有兴趣,就到我的gitee上去浏览,后面会放上地址

项目问题

选择框中出现的不是用户名

查找相应模块发现是因为addItem中添加的时结点,而不是结点中的username,修改后正常

服务端点击消息发送按钮没有反应

查找监听器部分,发现监听器监听该部分代码写错,将button又写成sysMessage

不能显示在线人数

查找侦听线程,启动客户端发现抛出异常

Cannot invoke “javax.swing.JTextField.setText(String)” because “this.textfield” is null

textfield为空,查找问题源头;发现在构造方法中:the assignmen to variable has no effect;这是因为单词拼写错误,编译器并没有报错

服务端退出时没有消息

系统报错

Cannot read field “input” because “node” is null

意识到问题出在链表上,系统要求从0开始,而链表中的序号是从1开始的,修该链表中的findUser中的pos为0就解决

写这个程序写了两天,直接废了~~

到此这篇关于Java Socket实现聊天室附1500行源代码的文章就介绍到这了,更多相关Java Socket内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java Socket模拟实现聊天室

    使用Java Socket模拟实现了一个聊天室,实现了基本的私聊以及群聊.分为服务器端和客户端,下面我来介绍一下实现的步骤. 服务器端 服务器端是聊天室的核心所在,主要用来处理客户端的请求,先来看一下服务器端的主方法: public static void main(String[] args) { try { ExecutorService executorService = Executors.newFixedThreadPool(100);//最多容纳100个客户端聊天 ServerSoc

  • Java创建多线程局域网聊天室实例

    局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了一个多线程的聊天室,熟悉了一下服务器和客户机的操作. 1.TCP 要实现局域网连接,就必须知道信息传输的原理. 在局域网里面传输的信息都是以包的形式,我使用的TCP包传输数据,TCP包里面封装了IP报文. 下面这句话就是通过一个静态IPV4协议的类得到一个服务器的IP地址. address = InetAddress.getByName("192.168.43.86")

  • Java Socket+多线程实现多人聊天室功能

    本文实例为大家分享了Java Socket+多线程实现多人聊天室的具体代码,供大家参考,具体内容如下 思路简介 分为客户端和服务器两个类,所有的客户端将聊的内容发送给服务器,服务器接受后,将每一条内容发送给每一个客户端,客户端再显示在终端上. 客户端设计 客户端包含2个线程,1个用来接受服务器的信息,再显示,1个用来接收键盘的输入,发送给服务器. import java.io.IOException; import java.io.InputStream; import java.io.Outp

  • Java实现多线程聊天室

    本文实例为大家分享了Java实现多线程聊天室的具体代码,供大家参考,具体内容如下 用多线程来实现,功能会比单线程聊天室更加齐全,也更人性化一点. 多线程版本的聊天室 1. 功能分析: 实现用户注册,上线,下线 实现群聊和私聊 统计当前在线人数 2. 服务端实现 1.维护所有的在线用户 2.注册功能:客户端名称,添加到服务器的客户端集合里 3.群聊功能:客户端发送消息,所有的客户端都能接收到 4.私聊功能:客户端与指定客户端进发送和接收消息 5.退出功能: 从服务器客户端集合中移除客户端 3. 客

  • java课程设计做一个多人聊天室(socket+多线程)

    目录 课设要求 相关知识点 1.服务端能够看到所有在线用户 2.服务端能够强制用户下线 3.客户端能够看到所有在线用户 4.客户端要求能够向某个用户发送消息 5.运用JDBC实现持久化存储用户信息 6.使用JSONObject对象封装数据 7.使用Maven构建管理项目 类图 项目框架 核心代码 1.maven配置文件pom.xml 2.服务器端Server.java 4.客户端注册界面Register.java 5.客户端聊天界面Chat.java 6.用户实体User.java 7.JDBC

  • Java Socket实现聊天室附1500行源代码

    目录 项目需求分析 基础分析 项目部分代码摘要 Dao的链表存储实现 ServerListen ServerReceive 再看一下客户端的ClientReceive 项目问题 选择框中出现的不是用户名 服务端点击消息发送按钮没有反应 不能显示在线人数 服务端退出时没有消息 Java养成计划(打卡第31,2天) 内容管理:Sockect聊天室的实现 Java界面 使用了各种组件,对于这部分不了解的不用担心,目前掌握一个大概就OK 项目需求分析 需要完成一个简单聊天工具的界面及功能,实现服务器中转

  • Java Socket实现聊天室功能

    本文实例为大家分享了Java Socket实现聊天室的具体代码,供大家参考,具体内容如下 1 创建登录判断类UserLogin import java.util.HashSet; import java.util.Set; public class UserLogin {     public static boolean login(String username) {         Set<String> set = initUser();         // set中含有该usern

  • java socket实现聊天室 java实现多人聊天功能

    用java socket做一个聊天室,实现多人聊天的功能.看了极客学院的视频后跟着敲的.(1DAY) 服务端: 1. 先写服务端的类MyServerSocket,里面放一个监听线程,一启动就好 2. 实现服务端监听类ServerListener.java,用accept来监听,一旦有客户端连上,生成新的socket,就新建个线程实例ChatSocket.启动线程后就把线程交给ChatManager管理 3. 在ChatSocket中实现从客户端读取内容,把读取到的内容发给集合内所有的客户端 4.

  • Java实现局域网聊天室功能(私聊、群聊)

    本文实例为大家分享了Java实现局域网聊天室功能的具体代码,供大家参考,具体内容如下 Server 服务端 import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket;   /**  * 服务端  */ public class Server {       private static final int SERVER_PORT=8080

  • java实现简单聊天室单人版

    本文实例为大家分享了java实现简单聊天室的具体代码,供大家参考,具体内容如下 先整理下思路: 1.创建一个通信服务端,传入端口号和相关的流后等待客户端连接,并初始化图形界面. 2.创建一个JFrame,用于写出聊天的界面,这里界面名称由其他类传入. 3.把客户端创建的方法写进JFrame(当然这里很粗糙的方法) 4.设置按钮的监听事件,发送消息和离线功能 首先创建一个服务端的类 import java.io.IOException; import java.net.ServerSocket;

  • JAVA Netty实现聊天室+私聊功能的示例代码

    功能介绍 使用Netty框架实现聊天室功能,服务器可监控客户端上下限状态,消息转发.同时实现了点对点私聊功能.技术点我都在代码中做了备注,这里不再重复写了.希望能给想学习netty的同学一点参考. 服务器代码 服务器入口代码 package nio.test.netty.groupChat; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.chann

  • Java多线程局域网聊天室的实现

    局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了一个多线程的聊天室,熟悉了一下服务器和客户机的操作. 1.TCP 要实现局域网连接,就必须知道信息传输的原理. 在局域网里面传输的信息都是以包的形式,我使用的TCP包传输数据,TCP包里面封装了IP报文. 下面这句话就是通过一个静态IPV4协议的类得到一个服务器的IP地址. address = InetAddress.getByName("192.168.43.86")

  • Java NIO实现聊天室功能

    本文实例为大家分享了Java NIO实现聊天室功能的具体代码,供大家参考,具体内容如下 代码里面已经包含了必要的注释,这里不详述了.实现了基本的聊天室功能. 常量类: public class Constant { public static final int serverPort = 44444; } 服务端: package server; import java.io.IOException; import java.net.InetSocketAddress; import java.

  • Java实现在线聊天室(层层递进)

    本文实例为大家分享了Java实现在线聊天室的具体代码,供大家参考,具体内容如下 - 本文讲述了从实现单个多个客户的收发信息(基础简易版),到各种实现代码的封装(oop版),实现群聊(群聊过渡版),到最后实现私聊(终极版)的过程- 本文内容是在初步学习网络编程时,练习强化记忆时的学习总结- 主要利用了TCP网络编程和多线程- 如有问题,欢迎指出 综合案例:在线聊天室 需求:使用TCP的Socket实现一个聊天室 服务器端:一个线程专门发送消息,一个线程专门接收消息 客户端:一个线程专门发送消息,一

随机推荐