java服務端對多個客戶端的群聊功能程式碼實現
阿新 • • 發佈:2019-01-06
以下程式碼可以實現服務端傳送一條訊息,多個客戶端可以同時收到這條訊息,同時客戶端可以單獨的和服務端通訊
需要注意的是,此時服務端只需要一個傳送訊息的程序
服務端程式碼:
/**
* 實現多個客戶端對應一個服務端進行通訊
*
* @author wangjue
*
*/
public class MyServer {
private ArrayList<Socket> list = new ArrayList<Socket>();
public static void main(String[] args) {
MyServer ms = new MyServer();
ms.initServer(10010);
}
public void initServer(int port) {
try {
ServerSocket server = new ServerSocket(port);
System.out.println("服務端正等待客戶端連線...");
/*
* 啟動發訊息的執行緒
* 因為是一個服務端對應多個客戶端,因此傳送訊息的執行緒只需要一個,不需要隨著客戶端的個數增加而增加
*/
SendThread st = new SendThread(list);
new Thread(st).start();
// 表示可以連線多個客戶端
while (true) {
Socket socket = server.accept();
list.add(socket);
System.out.println("已經有一個客戶端連線上來了...");
//啟動收訊息的執行緒
RecieveThread rt = new RecieveThread(socket);
new Thread(rt).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 接收客戶端不斷傳來訊息的執行緒
*
* @author wangjue
*
*/
public class RecieveThread implements Runnable {
private Socket socket;
private String recieveMsg;
public RecieveThread(Socket socket) {
this.socket = socket;
}
public String getRecieveMsg() {
return recieveMsg;
}
@Override
public void run() {
try {
InputStream ips = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int t = ips.read();
// 收到換行符為止
while (t != '\n') {
bos.write(t);
t = ips.read();
}
byte[] b = bos.toByteArray();
recieveMsg = new String(b);
System.out.println(recieveMsg);
bos.reset();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 傳送訊息給多個客戶端的執行緒
* @author wangjue
*
*/
public class SendThread implements Runnable {
private ArrayList<Socket> list;
public SendThread(ArrayList<Socket> list) {
this.list = list;
}
@Override
public void run() {
try {
while (true) {
//wait for scanner input,scanner是阻塞性,若沒有輸出內容,程式碼會停止不往下執行
Scanner sc = new Scanner(System.in);
String msg = "服務端說:" + sc.nextLine() + "----" + new Date(System.currentTimeMillis()) + "\n";
//通過for迴圈依次取出所有已經連上的socket物件,將服務端發出的訊息寫到輸入流
for (int i = 0; i < list.size(); i++) {
OutputStream ops = list.get(i).getOutputStream();
ops.write(msg.getBytes());
ops.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客戶端程式碼
public class MyClient {
public static void main(String[] args) {
MyClient mc = new MyClient();
mc.initClient("127.0.0.1", 10010);
}
public void initClient(String host, int port) {
try {
Socket socket = new Socket(host, port);
talkUI ui = new talkUI();
ui.initUI();
// 啟動收訊息的執行緒
RecieveThread rt = new RecieveThread(socket, ui);
new Thread(rt).start();
// 啟動發訊息的執行緒
SendThread st = new SendThread(socket, ui);
new Thread(st).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 接收服務端傳來的訊息並顯示在面板
* @author wangjue
*
*/
public class RecieveThread implements Runnable {
private Socket socket;
private talkUI ui;//傳入面板物件,呼叫getArea1方法獲取area1物件
public RecieveThread(Socket socket,talkUI ui) {
this.socket = socket;
this.ui = ui;
}
@Override
public void run() {
try {
InputStream ips = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int t = ips.read();
while (t != '\n') {
bos.write(t);
t = ips.read();
}
byte[] b = bos.toByteArray();
//收到服務端傳來的訊息
String msg = new String(b);
//將訊息顯示在訊息面板上
ui.getArea1().append(msg+"\n");
//將服務端的訊息接收到並顯示在面板後,清空輸入流,下次收到訊息後就不會顯示上次已經收到的訊息
bos.reset();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 向服務端傳送訊息
* @author wangjue
*
*/
public class SendThread implements Runnable {
private Socket socket;
private talkUI ui;
public SendThread(Socket socket, talkUI ui) {
this.socket = socket;
this.ui = ui;
}
@Override
public void run() {
try {
ui.ops = socket.getOutputStream();
while (true) {
if(ui.sendMsg2!=null){
byte[] b = ui.sendMsg2.getBytes();
ui.ops.write(b);
ui.ops.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 聊天面板
* @author wangjue
*
*/
public class talkUI implements ActionListener{
private JTextArea area1 = new JTextArea(15,30);
private JTextArea area2 = new JTextArea(10,30);
public OutputStream ops;
//在對話方塊輸入的內容
private String sendMsg;
//傳給服務端的內容
public String sendMsg2;
public JTextArea getArea1() {
return area1;
}
public void initUI() {
JFrame jf = new JFrame();
jf.setTitle("私人聊天室");
jf.setSize(400,600);
FlowLayout layout = new FlowLayout();
jf.setLayout(layout);
//顯示面板
area1.setEditable(false);
jf.add(area1);
//輸入面板
jf.add(area2);
//傳送按鈕
JButton btn = new JButton("傳送");
jf.add(btn);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
btn.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
sendMsg = area2.getText();
sendMsg2 = sendMsg+"\n"; //傳給服務端的訊息要加入換行符,服務端才能知道什麼時候結束接收
//輸入的內容要顯示在面板上
area1.append("自己說:"+sendMsg+"----"+new Date(System.currentTimeMillis())+"\n");
//點擊發送後,輸入面板要清空
area2.setText("");
//要每點選一次傳送就要將內容寫入輸出流中
try {
ops.write(sendMsg2.getBytes());
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
結果顯示