是不是試了很多次都沒有達到自己想要的效果呢?
沒關係,看到這你就已經有收穫了
一、動圖效果展示
二、服務端代碼(核心)
光說不練歪把子
package socket_study03;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 服務端最終版
* 1.多線程
* 2.代碼封裝
*
* 功能: 羣聊、私聊實現
*
* 私聊格式說明:@xxx:msg
*
* @author 放牛娃學編程(公衆號)
*
*/
public class Server {
//存放客戶端的容器
private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<Channel>();
//一個channel就代表一個客戶端(將其封裝成一個類)
static class Channel implements Runnable{
private DataOutputStream dos;
private DataInputStream dis;
private boolean flag;
private String name;
private Socket socket;
//構造器,用於數據初始化
public Channel(Socket socket)
{
this.socket = socket;
flag = true;
try
{
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
//獲取聊天暱稱(也就是客戶端發送的備註)
this.name = receive();
//當客戶加入聊天室後,發送歡迎信息
this.send("歡迎"+name+"進入到越擼越禿羣聊中");
//給其它成員發"某某"加入到越擼越禿羣聊中"
this.sendOthers(name+"加入到越擼越禿羣聊中", true);
}
catch(IOException e)
{
this.flag = false;
this.release();
}
}
//接收消息
public String receive()
{
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
release();
}
return msg;
}
//發送消息(發給自己)
public void send(String msg)
{
if(!msg.equals(""))
{
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
release();
}
}
}
/**
* 1.羣聊、發給除了自己以外的人
* 2.私聊、規定數據格式@xxx:msg
* @param msg
* @param isSys, 用來區分是否是系統消息,true爲是,反之不是
*/
public void sendOthers(String msg, boolean isSys)
{
boolean isPrivate = msg.startsWith("@");
if(isPrivate) //私聊消息
{
//獲取冒號下標(便於截取名字)
int index = msg.indexOf(":");
//截取名字(@人的備註)
String targetName = msg.substring(1, index);
//截取@的信息
msg = msg.substring(index + 1);
//遍歷容器,找到要@的人
for(Channel other: all)
{
if(other.name.equals(targetName))
{
other.send(this.name + "敲敲對你說:"+ msg); //私聊
break; //目標找到,發完私聊消息退出遍歷
}
}
}
else //不是私聊信息
{
//發給其它人,除自己以外,其實就是羣聊
for(Channel other:all)
{
if(other != this) //this就代表自己,本通道
{
if(!isSys)
{
other.send(this.name+"說:"+msg); //不是系統消息
}
else
{
other.send(msg); //系統消息
}
}
}
}
}
//釋放資源
public void release()
{
this.flag = false;
Utils.release(dos, dis, socket);
//退出
all.remove(this);
sendOthers(this.name+"離開了該羣聊……", true);
}
//線程體
@Override
public void run() {
// TODO Auto-generated method stub
while(flag)
{
//接收消息
String msg = receive();
//羣聊發消息(類似羣發)
if(!msg.equals(""))
{
sendOthers(msg, false); //不是系統消息
}
}
}
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
System.out.println("-----這是服務端----------");
//獲取ServerSocket管道
ServerSocket sSocket = new ServerSocket(9898);
while(true)
{
//獲取客戶端的socket
Socket client = sSocket.accept();
System.out.println("一個客戶端連接成功");
Channel channel = new Channel(client);
//將每個客戶端添加到容器中,進行統一管理
all.add(channel);
//啓動線程
new Thread(channel).start();
}
}
}
三、bug吐槽
- 遇到問題不要懷疑自己的智商,你比誰都聰明呢!!,有問題可以留言哈
- 如何運行該項目? 把服務端、客戶端代碼都準備好,然後先啓動服務端、再多開幾個客戶端就行了
- 如何獲取完整項目? 如何獲取服務端代碼或者是整個項目? 關注公衆號後回覆:羣聊項目。或者加我微信我親自發你也行。
- 如何只獲取客戶端代碼? 點這就有了呀:Java聊天室----多線程實現羣聊、私聊、系統消息(有動圖演示呀呀呀)
- 小夥伴們,這個聊天項目測試通過的哈,它能夠完成既定目標(羣聊、私聊、系統回覆),請放心去嘗試的呀!!!
如果遇到問題,沒關係,多去折騰就完事了,也歡迎小夥伴們留言交流學習。
四、分享交流
最後有興趣一起交流的,可以關注我的公衆號:這裏你能夠學到很實用的技巧,不是常用的我不說,公衆號回覆提取碼即可獲取以下學習資料啦啦啦啦,喜歡就拿去吧!!
(鏈接時常會失效,若出現此類情況,可以加我微信:17722328325(加時請備註:學習資料))
-
Java web從入門到精通電子書
-
Python機器學習電子書
-
Python400集(北京尚學堂)
-
JavaScript項目案例、經典面試題
-
Java300集(入門、精通)
-
Java後端培訓機構錄集(同事培訓內部提供)
-
IO流文檔
-
JavaEE面試題及其參考答案文檔
-
JavaSE面試題及其參考答案文檔
-
java多線程技術文檔
-
java網絡編程文檔
7~11都是之前同學花錢買來備戰找實習的,需要的我也分享出去了。