1. 程式人生 > 其它 >通訊-聊天室(JAVA)

通訊-聊天室(JAVA)

技術標籤:通訊

如果之前沒有接觸過通訊方面的知識,請移步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;
	}
}