通訊-聊天室(JAVA)
阿新 • • 發佈:2021-02-01
技術標籤:通訊
如果之前沒有接觸過通訊方面的知識,請移步https://blog.csdn.net/S_G_G/article/details/113482830。
在有了初步嘗試之後,我們可以試著寫一個聊天室。
其實只多了一個問題要解決:併發。
我們的基本思路是:
1、伺服器端接受客戶部分另寫一個繼承於Thread類的Receiver類來實現。
2、伺服器端,對於每個客戶,都建立一個NetConn物件(也繼承於Thread類)來實現與客戶的通訊。
3、每個客戶端也建立一個NetConn物件(與伺服器端的NetConn物件不同)來實現與伺服器端的通訊。
這樣就能保證伺服器端接受客戶和傳輸資料不衝突,客戶之間與伺服器通訊也不衝突。
由於伺服器端傳送資料時要傳送給所有客戶,所以我用一個ArrayList來存所有的NetConn物件,並且將這個ArrayList專門放在ClientList類中。
用swing的JTextField元件來實現編輯和獲取要傳送的訊息的功能。
用swing的JTextArea元件來實現顯示接收到的訊息的功能。
伺服器端的流程圖如下:
伺服器端Server類(主類)程式碼
import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.net.ServerSocket; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JTextArea; import javax.swing.JTextField; public class Server{ private ServerSocket ss; private JTextArea ta; private Server(){ //伺服器端介面初始化 JFrame jf=new JFrame("聊天室-伺服器"); jf.setSize(500, 500); JButton btn=new JButton("傳送"); jf.add(btn); JTextField tf=new JTextField(20); ta=new JTextArea(20,30); jf.add(tf); jf.add(ta); jf.setDefaultCloseOperation(3); jf.setLayout(new FlowLayout()); jf.setVisible(true); btn.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { String msg=tf.getText(); ClientList.send(msg); tf.setText(""); } }); this.work(); } private void work(){ //核心程式碼 try { ss=new ServerSocket(9999); Receiver r=new Receiver(ss,ta); r.start(); } catch (IOException e) {e.printStackTrace();} } public static void main(String[] args){ Server s1=new Server(); } }
伺服器端Receiver類程式碼
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JTextArea; public class Receiver extends Thread{ private ServerSocket ss; private JTextArea ta; Receiver(ServerSocket s,JTextArea t){ ss=s; ta=t; } public void run(){ while(true){ //不停地接收客戶,建立NetConn物件並加入ArrayList中 try { Socket client=ss.accept(); NetConn nc=new NetConn(client,ta); nc.start(); ClientList.list.add(nc); } catch (IOException e) { e.printStackTrace();} } } }
伺服器端NetConn類程式碼
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import javax.swing.JTextArea;
public class NetConn extends Thread{
private Socket client;
private JTextArea ta;
private DataInputStream dis;
private DataOutputStream dos;
NetConn(Socket s,JTextArea t){
client=s;
ta=t;
}
public void send(String msg){ //向該客戶傳送訊息
byte[] data=msg.getBytes();
int l=data.length;
try {
dos.writeInt(l);
dos.write(data);
}
catch (IOException e) {e.printStackTrace();}
}
public void run(){ //接收該客戶發來的訊息
try {
dis=new DataInputStream(client.getInputStream());
dos=new DataOutputStream(client.getOutputStream());
while (true){
int l=dis.readInt();
byte[] data=new byte[l];
dis.read(data);
String msg=new String(data);
ta.append(msg+"\r\n");
}
}
catch (IOException e) {e.printStackTrace();}
}
}
伺服器端ClientList類程式碼
import java.util.ArrayList;
public class ClientList {
public static ArrayList<NetConn> list=new ArrayList();
public static void send(String s){
for (int i=list.size()-1;i>=0;i--){
NetConn nc=list.get(i);
nc.send(s);
}
}
}
客戶端Client類(主類)程式碼
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Client {
private void work(){ //客戶端介面初始化
JFrame jf=new JFrame("聊天室-客戶端");
jf.setSize(500, 500);
JButton btn=new JButton("傳送");
jf.add(btn);
JTextField tf=new JTextField(20);
JTextArea ta=new JTextArea(20,30);
jf.add(tf);
jf.add(ta);
jf.setDefaultCloseOperation(3);
jf.setLayout(new FlowLayout());
jf.setVisible(true);
NetConn nc=new NetConn(ta); //建立該客戶對應的NetConn物件
if (!nc.connect()) return; //將連線伺服器部分寫在NetConn類裡便於判斷要不要繼續執行下面的程式碼
nc.start();
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String msg=tf.getText();
nc.send(msg);
tf.setText("");
}
});
}
public static void main(String[] args){
Client c=new Client();
c.work();
}
}
客戶端NetConn類程式碼
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JTextArea;
public class NetConn extends Thread{
private Socket s;
private JTextArea ta;
private DataInputStream dis;
private DataOutputStream dos;
NetConn(JTextArea t){
ta=t;
}
public void send(String msg){ //向伺服器傳送訊息
byte[] data=msg.getBytes();
int l=data.length;
try {
dos.writeInt(l);
dos.write(data);
}
catch (IOException e) {e.printStackTrace();}
}
public void run(){ //接收伺服器發來的訊息
try {
while (true){
int l=dis.readInt();
byte[] data=new byte[l];
dis.read(data);
String msg=new String(data);
ta.append(msg+"\r\n");
}
}
catch (IOException e) {e.printStackTrace();}
}
public boolean connect(){
try {
s=new Socket("192.168.0.102",9999);
dis=new DataInputStream(s.getInputStream());
dos=new DataOutputStream(s.getOutputStream());
return true;
}
catch (UnknownHostException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
return false;
}
}