最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java Socket實現(xiàn)聊天室附1500行源代碼

 更新時間:2021年10月18日 11:08:27   作者:碼農(nóng)C風(fēng)  
Socket是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層,它是一組接口。本篇文章手把手帶你通過Java Socket來實現(xiàn)自己的聊天室,大家可以在過程中查缺補漏,溫故而知新

Java養(yǎng)成計劃(打卡第31,2天)

內(nèi)容管理:Sockect聊天室的實現(xiàn)

Java界面 使用了各種組件,對于這部分不了解的不用擔(dān)心,目前掌握一個大概就OK

項目需求分析

需要完成一個簡單聊天工具的界面及功能,實現(xiàn)服務(wù)器中轉(zhuǎn)下的多客戶端之間的通信,系統(tǒng)完成的功能有

  • 程序啟動后能看到當(dāng)前有那些機器上線,可彈出對話聊天框,可以在其中編輯要發(fā)送的聊天信息,并進行發(fā)送
  • 一旦某個網(wǎng)內(nèi)的機器上線了,可即時通知,并能更新用戶界面的用戶列表
  • 雙擊某個列表項時,可彈出對話聊天框,可以在其中編輯要發(fā)送的信息并發(fā)送
  • 聊天界面人性化,下面時發(fā)送框,上面有已有聊天記錄,并借助滾動條看到當(dāng)次所有聊天記錄
  • 當(dāng)有人向本機器發(fā)送消息時,可顯示用戶接收到的信息,并且顯示是誰所發(fā),同時進行信息的回復(fù)

基礎(chǔ)分析

首先這是一個聊天工具,使用的是C/S結(jié)構(gòu),要模擬就要使用net的Scocket和ServerSocket模擬客戶端和服務(wù)端

這里綜合運用了多種知識,已經(jīng)不再是簡單的java SE知識,其中界面編程占據(jù)主要代碼,這里可以貼幾張圖看看效果,這是我肝了2天才肝完的,這里已經(jīng)可以實現(xiàn)多態(tài)設(shè)備的連接

分為3個包

Sever包主要是服務(wù)器的相關(guān)代碼,主要是實現(xiàn)與用戶的交互

Dao包是模擬的數(shù)據(jù)庫包,存儲所有的用戶信息,實現(xiàn)增刪改的操作

Client是客戶代碼包,只要在電腦上運行這里的代碼,就可以出現(xiàn)客戶端界面,約定好ip和端口號就可以通信了。這里就真正實現(xiàn)了客戶端型軟件,只是軟件功能簡單,可以使用web編程實現(xiàn)另外一種架構(gòu)
可以來看一下界面

在這里插入圖片描述

再來看一下客戶端和服務(wù)端的交流

在這里插入圖片描述

項目部分代碼摘要

Dao的鏈表存儲實現(xiàn)

package Dao;

/**
 * 演示程序為了簡化就不用數(shù)據(jù)庫存儲,使用單鏈表完成數(shù)據(jù)庫各項功能
 * 這里一定要寫測試代碼檢查各項功能是否可用
 * 最開開始我測試了add,del,find功能,卻沒有測試getCount功能,結(jié)果存在問題,后面突然放開測試才發(fā)現(xiàn)錯誤
 */
public class UserLinkList {
	private  Node head;
	private int count;

	public boolean addUser(Node client)
	{
		if(head == null)
		{//頭節(jié)點也存儲數(shù)據(jù)
			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沒有包含最后一個結(jié)點
		{
			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))
		{//刪除頭結(jié)點
			head = head.next;
			count--;
			return true;
		}
		while(p != null)
		{//忘記循環(huán)了
			if(p.next.username.equals(client.username))
			{
				p.next = p.next.next;
				count--;
				return true;
			}
			p = p.next;
		}
		return false;
	}
	
	/**
	 * 這里可以設(shè)置一個顯示的方法,供檢查使用
	 */
	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) {//經(jīng)過測試發(fā)現(xiàn)沒有問題,可以正常使用
		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());
	}
*/

現(xiàn)在編寫這段代碼應(yīng)當(dāng)是非常簡單的,注意一定要測試

ServerListen

簡單看一下這個監(jiān)聽線程,可以監(jiān)聽用戶是否上線

package Server;
/**
 * @author OMEY-PC
 *本程序的作用是實現(xiàn)服務(wù)器偵聽的線程化,其中run方法通過client = new Node();創(chuàng)建一個客戶端對象,通過client.socket = server.accept來設(shè)定接口,通過client.input
 *output來建立輸入輸出流
 */

import java.io.*;
import java.net.*;
import Dao.*; //連接數(shù)據(jù)
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;
	/**
	 * 聊天服務(wù)端的用戶上下線偵聽類
	 */
	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())//沒有停止服務(wù)
		{
			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

該線程實現(xiàn)服務(wù)器與用戶之間的信息交互

package Server;
/**
 * @author OMEY-PC
 *服務(wù)器收發(fā)消息的類
 */

import java.net.ServerSocket;

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

public class ServerReceive extends Thread{
	JTextArea textarea;//消息展示域
	JTextField textfield;//文本輸入域
	JComboBox combobox; //復(fù)選框
	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()
	{
		//向所有人發(fā)送用戶的列表
		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; //若為悄悄話,就在前面加上標(biāo)識
					}
					textarea.append(msg);
					if(toSomebody.equalsIgnoreCase("所有人"))
					{
						sendToAll(msg);//這里是接受的用戶消息,和之前的向所有人發(fā)消息不一樣
					}
					else {//向用戶發(fā)消息
						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);//向選定信息發(fā)送信息
							node.output.flush();//刷新輸出流緩沖區(qū)中的信息
						}
					}
			    }
				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();//重新發(fā)送用戶列表
					break;
				}
		    }catch (Exception e) {
				e.printStackTrace();
			}
	    }
	}
	/**
	 * 向所有人發(fā)送消息
	 */
	public void sendToAll(String msg)
	{
		int count = userLinkList.getCount();
		int i = 0;
		while(i < count)
		{//給用戶列表中的每一個人都發(fā)送消息
			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++;
		}
	}
	/**
	 * 向所有人發(fā)送用戶列表
	 */
	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; //給每個人發(fā)送消息
		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++;
	}	
}
/**
 * 本程序可以實現(xiàn)通過線程向所有人發(fā)送消息,用戶列表,以及向選定的人發(fā)送聊天消息等,主要是是實現(xiàn)服務(wù)端收發(fā)消息的線程化,其中sendUserList()發(fā)送列表,
 * client.input.redObject()獲取客戶端發(fā)送到服務(wù)端的消息,通sendToAll(),將發(fā)送到發(fā)送到所有人的信息發(fā)送到各個客戶端
 */

再看一下客戶端的ClientReceive

該線程是實現(xiàn)客戶端與系統(tǒng)之間的信息交互,注解豐富

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() {//從服務(wù)端獲得消息
		while(!socket.isClosed())
		{
			try {
				String type = (String)input.readObject();//獲得流,read讀取信息
				if(type.equalsIgnoreCase("系統(tǒng)信息"))
				{
					String sysmsg = (String)input.readObject();
					textarea.append("系統(tǒng)信息" + sysmsg);
				}
				else if(type.equalsIgnoreCase("服務(wù)關(guān)閉"))
				{
					output.close();
					input.close();
					socket.close();
					textarea.append("服務(wù)器已經(jīng)關(guān)閉!\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上去瀏覽,后面會放上地址

項目問題

選擇框中出現(xiàn)的不是用戶名

查找相應(yīng)模塊發(fā)現(xiàn)是因為addItem中添加的時結(jié)點,而不是結(jié)點中的username,修改后正常

服務(wù)端點擊消息發(fā)送按鈕沒有反應(yīng)

查找監(jiān)聽器部分,發(fā)現(xiàn)監(jiān)聽器監(jiān)聽該部分代碼寫錯,將button又寫成sysMessage

不能顯示在線人數(shù)

查找偵聽線程,啟動客戶端發(fā)現(xiàn)拋出異常

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

textfield為空,查找問題源頭;發(fā)現(xiàn)在構(gòu)造方法中:the assignmen to variable has no effect;這是因為單詞拼寫錯誤,編譯器并沒有報錯

服務(wù)端退出時沒有消息

系統(tǒng)報錯

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

意識到問題出在鏈表上,系統(tǒng)要求從0開始,而鏈表中的序號是從1開始的,修該鏈表中的findUser中的pos為0就解決

寫這個程序?qū)懥藘商?,直接廢了~~

到此這篇關(guān)于Java Socket實現(xiàn)聊天室附1500行源代碼的文章就介紹到這了,更多相關(guān)Java Socket內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 用java實現(xiàn)跳動的小球示例代碼

    用java實現(xiàn)跳動的小球示例代碼

    這篇文章主要介紹了用java實現(xiàn)跳動的小球,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 深入解讀Java三大集合之map list set的用法

    深入解讀Java三大集合之map list set的用法

    集合彌補了數(shù)組的缺陷,它比數(shù)組更靈活更實用,可大大提高軟件的開發(fā)效率,而且不同的集合適用于不同的場合,這篇文章帶你了解Java的三大集合map、list、set用法
    2021-11-11
  • spring boot 添加admin監(jiān)控的方法

    spring boot 添加admin監(jiān)控的方法

    這篇文章主要介紹了spring boot 添加admin監(jiān)控的相關(guān)知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-02-02
  • 一文帶你搞懂Maven的繼承與聚合

    一文帶你搞懂Maven的繼承與聚合

    這篇文章主要為大家詳細(xì)介紹了Maven的繼承和聚合以及二者的區(qū)別,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-07-07
  • 淺談javaSE GUI (Action事件)

    淺談javaSE GUI (Action事件)

    下面小編就為大家?guī)硪黄獪\談javaSE GUI (Action事件)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • 基于SpringBoot實現(xiàn)自動裝配返回屬性的設(shè)計思路

    基于SpringBoot實現(xiàn)自動裝配返回屬性的設(shè)計思路

    這篇文章主要介紹了基于SpringBoot實現(xiàn)自動裝配返回屬性,這里涉及到的技術(shù)知識點有注解解析器,為什么用ResponseBodyAdvice這里解析?不在Filter,Interceptors,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-03-03
  • java 中enum的使用方法詳解

    java 中enum的使用方法詳解

    這篇文章主要介紹了java 中enum的使用方法詳解的相關(guān)資料,希望通過本文能幫助到大家,理解掌握java 中enum的使用方法,需要的朋友可以參考下
    2017-09-09
  • Java實現(xiàn)局域網(wǎng)IP地址掃描

    Java實現(xiàn)局域網(wǎng)IP地址掃描

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)局域網(wǎng)IP地址掃描,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Java實現(xiàn)Excel導(dǎo)入導(dǎo)出數(shù)據(jù)庫的方法示例

    Java實現(xiàn)Excel導(dǎo)入導(dǎo)出數(shù)據(jù)庫的方法示例

    這篇文章主要介紹了Java實現(xiàn)Excel導(dǎo)入導(dǎo)出數(shù)據(jù)庫的方法,結(jié)合實例形式分析了java針對Excel的讀寫及數(shù)據(jù)庫操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2017-08-08
  • 基于springioc bean 的幾個屬性介紹

    基于springioc bean 的幾個屬性介紹

    下面小編就為大家?guī)硪黄趕pringioc bean 的幾個屬性介紹。小編覺得挺不錯的,現(xiàn)在就想給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09

最新評論

灯塔市| 潢川县| 彝良县| 子长县| 襄樊市| 米泉市| 新泰市| 鄄城县| 昂仁县| 黑水县| 常熟市| 虞城县| 彭州市| 新源县| 永新县| 周至县| 玉田县| 集贤县| 胶州市| 沅江市| 大足县| 南木林县| 福建省| 德安县| 宜兰县| 甘孜| 温宿县| 略阳县| 冕宁县| 万州区| 绥阳县| 玉树县| 东乡族自治县| 田林县| 东莞市| 南靖县| 安阳市| 金山区| 和政县| 栾川县| 河间市|