私聊功能跟你截屏的這段代碼沒有關(guān)系,首先你是多人聊天室,肯定要開連接池來解決線程問題,每個客戶端都有自己對象創(chuàng)建的流,正常大家在公共聊天時,socket服務器向所有對象的流同一發(fā)送消息,當私聊時需要先找到對應對象的流,服務器單獨向該流發(fā)送消息就可以實現(xiàn)私聊功能了。
成都創(chuàng)新互聯(lián)主營惠來網(wǎng)站建設(shè)的網(wǎng)絡公司,主營網(wǎng)站建設(shè)方案,成都App制作,惠來h5微信小程序開發(fā)搭建,惠來網(wǎng)站營銷推廣歡迎惠來等地區(qū)企業(yè)咨詢
建議你在創(chuàng)建對象時,將每個對象的昵稱和流存入一個map集合,私聊時通過昵稱來找到對應的流。
UDP也可以和TCP那樣遍歷list然后發(fā)送啊
客戶端向外面開一個UDP端口接受數(shù)據(jù)報
然后服務器這邊要是有消息要發(fā)送就直接發(fā)送數(shù)據(jù)報包就可以了嘛
UDP都不用保持著連接的,比TCP還簡單些
另外也可以用組播來實現(xiàn),搜索下java UDP 組播,你能找到不少實例性的代碼,也有聊天室的代碼
給你一個簡單的實現(xiàn)吧,注意一定要先運行MyServer.java
//MyCilent.java
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MyClient extends JFrame implements ActionListener{
JTextField tf;
JTextArea tx;
JButton bt;
PrintWriter out;
public MyClient(){
tf=new JTextField(20);
tx=new JTextArea();
tx.setLineWrap(true);
tx.setWrapStyleWord(true);
JPanel pan=new JPanel();
JScrollPane jsp=new JScrollPane(tx);
add(jsp,"Center");
bt=new JButton("SEND");
bt.addActionListener(this);
pan.add(tf);
pan.add(bt);
add(pan,"South");
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
setTitle("THE CLIENT");
setSize(400,300);
setVisible(true);
try{
Socket socket=new Socket("127.0.0.1",1680);
out=new PrintWriter(socket.getOutputStream(),true);
InputStreamReader in = new InputStreamReader(socket.getInputStream());
BufferedReader sin=new BufferedReader(in);
String s;
while(true){
s=sin.readLine();
tx.append("#Server Said#: "+s+"\n");
}
}catch(Exception e){
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==bt){
tx.append("@Client Said@: "+tf.getText()+"\n");
out.println(tf.getText());
tf.setText("");
}
}
public static void main(String[] args){
MyClient mct = new MyClient();
}
}
//MyServer.java
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MyServer extends JFrame implements ActionListener{
JTextField tf;
JTextArea tx;
JButton bt;
JScrollPane jsp;
JPanel pan;
PrintWriter out;
public MyServer(){
tx=new JTextArea();
tx.setLineWrap(true);
tx.setWrapStyleWord(true);
jsp=new JScrollPane(tx);
tf=new JTextField(20);
bt=new JButton("SEND");
bt.addActionListener(this);
pan=new JPanel();
pan.add(tf);
pan.add(bt);
add(pan,"South");
add(jsp,"Center");
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
setTitle("THE SERVER");
setSize(400,300);
setVisible(true);
try{
ServerSocket server = new ServerSocket(1680);
Socket socket = server.accept();
InputStreamReader in = new InputStreamReader(socket.getInputStream());
BufferedReader sin=new BufferedReader(in);
out=new PrintWriter(socket.getOutputStream(),true);
while(true){
String s=sin.readLine();
tx.append("@Client Said@: "+s+"\n");
}
}catch(Exception e){
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==bt){
String st = tf.getText();
tx.append("#Server Said#: "+st+"\n");
out.println(st);
tf.setText("");
}
}
public static void main(String[] args){
MyServer msr = new MyServer();
}
}
import java.io.InputStream;
import java.io.DataInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.BufferedReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.util.Date;
class Server
{
public Server()
{
try
{
ServerSocket s=new ServerSocket(8888);
Socket ss=s.accept();
OutputStream out=ss.getOutputStream();
DataOutputStream dout=new DataOutputStream(out);
InputStream in=ss.getInputStream();
DataInputStream din=new DataInputStream(in);
System.out.print(din.readUTF()+"!");
dout.writeUTF("你已經(jīng)連接到服務器"+"\t"+"你的地址:"+ss.getInetAddress()+"\t"
+"你的鏈接端口:"+ss.getLocalPort()+"\n");
new ReadMessage(din).start();
new SendMessage(dout).start();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new Server();
}
}
//接受客戶端信息
class ReadMessage extends Thread
{
private DataInputStream din;
public ReadMessage(DataInputStream din)
{
this.din=din;
}
public void run()
{
String str;
try
{
while (true)
{
str=din.readUTF();
System.out.println(new Date().toLocaleString()+"客戶端說:"+str);
if (str.equals("bye"))
{
System.out.println("客戶端下線!");
break;
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
// 發(fā)出服務器信息
class SendMessage extends Thread
{
private DataOutputStream dout;
public SendMessage(DataOutputStream dout)
{
this.dout=dout;
}
public void run()
{
InputStreamReader inr=new InputStreamReader(System.in);
BufferedReader buf=new BufferedReader(inr);
String str;
try
{
while(true)
{
str=buf.readLine();
dout.writeUTF(str);
if (str.equals("bye"))
{
System.out.println("服務器退出!");
System.exit(1);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
import java.io.InputStream;
import java.io.DataInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.BufferedReader;
import java.net.Socket;
import java.io.IOException;
import java.util.Date;
class Client
{
public Client()
{
try
{
Socket s=new Socket("192.168.1.2",8888);
InputStream in=s.getInputStream();
DataInputStream din=new DataInputStream(in);
OutputStream out=s.getOutputStream();
DataOutputStream dout=new DataOutputStream(out);
dout.writeUTF("服務器你好!我是客戶端");
System.out.println(din.readUTF());
new Thread(new SenderMessage(dout)).start();
new Thread(new ReaderMessage(din)).start();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new Client();
}
}
class ReaderMessage implements Runnable
{
private DataInputStream din;
public ReaderMessage(DataInputStream din)
{
this.din=din;
}
public void run()
{
String str;
try
{
while(true)
{
str=din.readUTF();
System.out.println(new Date().toLocaleString()+"服務器說:"+str);
if (str.equals("bye"))
{
System.out.println("服務器已經(jīng)關(guān)閉,此程序自動退出!");
break;
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
class SenderMessage implements Runnable
{
private DataOutputStream dout;
public SenderMessage(DataOutputStream dout)
{
this.dout=dout;
}
public void run()
{
String str;
InputStreamReader inf=new InputStreamReader(System.in);
BufferedReader buf=new BufferedReader(inf);
try
{
while (true)
{
str=buf.readLine();
dout.writeUTF(str);
if (str.equals("bye"))
{
System.out.println("客戶端自己退出!");
System.exit(1);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
package API_Day09;
import java.io.BufferedReader;
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.Socket;
import java.util.Scanner;
/**
* 控制臺聊天程序
* 客戶端應用程序
* @author Jacob
*
*/
public class chatClient
{
//客戶端用于與服務端連接的Socket
private Socket clientSocket;
/**
* 構(gòu)造方法,客戶端初始化
*/
public chatClient()
{
try
{
/*
* socket(String host, int port)
* 地址: IP地址,用來定位網(wǎng)絡上的計算機
* 端口: 用來找到遠端計算機上用來連接的服務端應用程序
*/
clientSocket = new Socket("localhost",12580);
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 客戶端昵稱驗證方法
* @param 為Scanner
*/
private void inputNickName(Scanner scan) throws Exception
{
String nickName = null;
//創(chuàng)建輸出流
PrintWriter pw = new PrintWriter(
new OutputStreamWriter(clientSocket.getOutputStream(),
"UTF-8"),true);
//創(chuàng)建輸入流
BufferedReader br = new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream(),"UTF-8"));
while(true)
{
System.out.println("請創(chuàng)建您的昵稱:");
nickName = scan.nextLine();
if (nickName.trim().equals(""))
{
System.out.println("昵稱不得為空");
}
else
{
pw.println(nickName);
String pass = br.readLine();
if(pass!=null!pass.equals("OK"))
{
System.out.println("昵稱已經(jīng)被占用,請更換!");
}
else
{
System.out.println("你好!"+nickName+"可以開始聊天了");
break;
}
}
}
}
/*
* 客戶端啟動的方法
*/
public void start()
{
try
{
/*
* 創(chuàng)建Scanner,讀取用戶輸入內(nèi)容
* 目的是設(shè)置客戶端的昵稱
*/
Scanner scanner = new Scanner(System.in);
inputNickName(scanner);
/*
* 將用于接收服務器端發(fā)送過來的信息的線程啟動
*/
Runnable run = new GetServerMsgHandler();
Thread t = new Thread(run);
t.start();
/*
* 建立輸出流,給服務端發(fā)信息
*/
OutputStream os = clientSocket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
PrintWriter pw = new PrintWriter(osw,true);
while(true)
{
pw.println(scanner.nextLine());
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(clientSocket !=null)
{
try
{
clientSocket.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
/**
* 該線程體用來循環(huán)讀取服務端發(fā)送過來的信息
* 并輸出到客戶端的控制臺
* @param args
*/
class GetServerMsgHandler implements Runnable
{
@Override
public void run()
{
try
{
InputStream is = clientSocket.getInputStream();
InputStreamReader isr = new InputStreamReader(is,"UTF-8");
BufferedReader br = new BufferedReader(isr);
String msgString = null;
while((msgString = br.readLine())!= null)
{
System.out.println("服務端提示:"+ msgString);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
chatClient client = new chatClient();
client.start();
}
}
package API_Day09;
import java.io.BufferedReader;
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.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 控制臺聊天程序
* 服務端應用程序
* @author Jacob
*
*/
public class chatServer
{
/**
* ServerSocket 是運行在服務端的Socket
* 用來監(jiān)聽端口,等待客戶端的連接,
* 一旦連接成功就會返回與該客戶端通信的Socket
*/
private ServerSocket serverSocket;
/**
* 創(chuàng)建線程池來管理客戶端的連接線程
* 避免系統(tǒng)資源過度浪費
*/
private ExecutorService threadPool;
/**
* 該屬性用來存放客戶端之間私聊的信息
*/
private MapString,PrintWriter allOut;
/**
* 構(gòu)造方法,服務端初始化
*/
public chatServer()
{
try
{
/*
* 創(chuàng)建ServerSocket,并申請服務端口
* 將來客戶端就是通過該端口連接服務端程序的
*/
serverSocket = new ServerSocket(12580);
/*
* 初始化Map集合,存放客戶端信息
*/
allOut = new HashMapString, PrintWriter();
/*
* 初始化線程池,設(shè)置線程的數(shù)量
*/
threadPool = Executors.newFixedThreadPool(10);
/*
* 初始化用來存放客戶端輸出流的集合,
* 每當一個客戶端連接,就會將該客戶端的輸出流存入該集合;
* 每當一個客戶端斷開連接,就會將集合中該客戶端的輸出流刪除;
* 每當轉(zhuǎn)發(fā)一條信息,就要遍歷集合中的所有輸出流(元素)
* 因此轉(zhuǎn)發(fā)的頻率高于客戶端登入登出的頻率,
* 還是應該使用ArrayList來存儲元素,僅限群聊,私聊不行
* allOut = new ArrayListPrintWriter();
*/
}
catch (Exception e)
{
e.printStackTrace();
}
}
/*
* 將客戶端的信息以Map形式存入集合中
*/
private void addOut(String key,PrintWriter value)
{
synchronized(this)
{
allOut.put(key, value);
}
}
/*
* 將給定的輸出流從共享集合中刪除
* 參數(shù)為客戶端nickName,作為Map的key鍵
*/
private synchronized void removeOut(String key)
{
allOut.remove(key);
System.out.println("當前在線人數(shù)為:"+ allOut.size());
}
/*
* 將給定的消息轉(zhuǎn)發(fā)給所有客戶端
*/
private synchronized void sendMsgToAll(String message)
{
for(PrintWriter out: allOut.values())
{
out.println(message);
System.out.println("當前在線人數(shù)為:"+ allOut.size());
}
}
/*
* 將給定的消息轉(zhuǎn)發(fā)給私聊的客戶端
*/
private synchronized void sendMsgToPrivate(String nickname,String message)
{
PrintWriter pw = allOut.get(nickname); //將對應客戶端的聊天信息取出作為私聊內(nèi)容發(fā)送出去
if(pw!=null)
{
pw.println(message);
System.out.println("當前在線私聊人數(shù)為:"+ allOut.size());
}
}
/**
* 服務端啟動的方法
*/
public void start()
{
try
{
while(true)
{
/*
* 監(jiān)聽10086端口
*/
System.out.println("等待客戶端連接... ... ");
/*
* Socket accept() 這是一個阻塞方法,會一直在10086端口進行監(jiān)聽
* 直到一個客戶端連接上,此時該方法會將與這個客戶端進行通信的Socket返回
*/
Socket socket = serverSocket.accept();
System.out.println("客戶端連接成功! ");
/*
* 啟動一個線程,由線程來處理客戶端的請求,這樣可以再次監(jiān)聽
* 下一個客戶端的連接了
*/
Runnable run = new GetClientMsgHandler(socket);
threadPool.execute(run); //通過線程池來分配線程
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* 該線程體用來處理給定的某一個客戶端的消息,循環(huán)接收客戶端發(fā)送
* 的每一個字符串,并輸出到控制臺
* @author Jacob
*
*/
class GetClientMsgHandler implements Runnable
{
/*
* 該屬性是當前線程處理的具體的客戶端的Socket
* @see java.lang.Runnable#run()
*/
private Socket socket;
/*
* 獲取客戶端的地址信息
* private String hostIP;
*/
/*
* 獲取客戶端的昵稱
*/
private String nickName;
/*
* 創(chuàng)建構(gòu)造方法
*/
public GetClientMsgHandler(Socket socket)
{
this.socket = socket;
/*
* 獲取遠端客戶的Ip地址信息
* 保存客戶端的IP地址字符串
* InetAddress address = socket.getInetAddress();
* hostIP = address.getHostAddress();
*/
}
/*
* 創(chuàng)建內(nèi)部類來獲取昵稱
*/
private String getNickName() throws Exception
{
try
{
//服務端的輸入流讀取客戶端發(fā)送來的昵稱輸出流
InputStream iin = socket.getInputStream();
InputStreamReader isr =
new InputStreamReader(iin,"UTF-8");
BufferedReader bReader = new BufferedReader(isr);
//服務端將昵稱驗證結(jié)果通過自身的輸出流發(fā)送給客戶端
OutputStream out = socket.getOutputStream();
OutputStreamWriter iosw =
new OutputStreamWriter(out,"UTF-8");
PrintWriter ipw = new PrintWriter(iosw,true);
//讀取客戶端發(fā)來的昵稱
String nameString = bReader.readLine();
while(true)
{
if(nameString.trim().length()==0)
{
ipw.println("FAIL");
}
if(allOut.containsKey(nameString))
{
ipw.println("FAIL");
}
else
{
ipw.println("OK");
return nameString;
}
nameString = bReader.readLine();
}
}
catch(Exception e)
{
throw e;
}
}
@Override
public void run()
{
PrintWriter pw = null;
try
{
/*
* 通過客戶端的Socket獲取客戶端的輸出流
* 用來將消息發(fā)送給客戶端
*/
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
pw = new PrintWriter(osw,true);
/*
* 將客戶昵稱和其所說的話作為元素存入共享集合HashMap中
*/
nickName = getNickName();
addOut(nickName, pw);
Thread.sleep(100);
/*
* 服務端通知所有客戶端,某用戶登錄
*/
sendMsgToAll("[系統(tǒng)通知]:歡迎**"+nickName+"**登陸聊天室!");
/*
* 通過客戶端的Socket獲取輸入流
* 讀取客戶端發(fā)送來的信息
*/
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is,"UTF-8");
BufferedReader br = new BufferedReader(isr);
String msgString = null;
while((msgString = br.readLine())!=null)
{
//驗證是否是私聊
if(msgString.startsWith("@"))
{
/*
* 私聊格式:@昵稱:內(nèi)容
*/
int index = msgString.indexOf(":");
if(index =0)
{
//獲取昵稱
String name = msgString.substring(1,index);
String info = msgString.substring(index+1,msgString.length());
info = nickName + "對你說:"+ info;
//將私聊信息發(fā)送出去
sendMsgToPrivate(name, info);
//服務端不在廣播私聊的信息
continue;
}
}
/*
* 遍歷所有輸出流,將該客戶端發(fā)送的信息轉(zhuǎn)發(fā)給所有客戶端
*/
System.out.println(nickName+"說:"+ msgString);
sendMsgToAll(nickName+"說:"+ msgString);
}
}
catch (Exception e)
{
/*
* 因為Win系統(tǒng)用戶的客戶端斷開連接后,br.readLine()方法讀取
* 不到信息就會拋出異常,而Linux系統(tǒng)會持續(xù)發(fā)送null;
* 因此這里就不在將捕獲的異常拋出了。
*/
}
finally
{
/*
* 當執(zhí)行到此處時,說明客戶端已經(jīng)與服務端斷開連接
* 則將該客戶端存在共享集合中的輸出流刪除
*/
removeOut(nickName);
/*
* 通知所有客戶端,某某客戶已經(jīng)下線
*/
sendMsgToAll("[系統(tǒng)通知]:"+nickName + "已經(jīng)下線了。");
/*
* 關(guān)閉socket,則通過Socket獲取的輸入輸出流也一同關(guān)閉了
*/
if(socket!=null)
{
try
{
socket.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args)
{
chatServer server = new chatServer();
server.start();
}
}
我的作業(yè),供你參考
UDP 是廣播的,如果是做實時的聊天,就開兩個線程、不需要服務器端。一個專門接收、一個做發(fā)送