前言
前幾天沒什麼事兒,在學習UDP和TCP傳輸協議,順手做了一個基於UDP協議的聊天小程序,同時複習了Java的GUI知識。程序運行截圖展示
1.運行程序,生成第一個窗口,輸入要監聽的端口號:1234(示例端口號)
2.再次運行程序,生成第二個聊天窗口,並且要輸入端口號:4321(示例端口號)
3.然後,兩個聊天窗口之間便可以對話了。
3.程序代碼解讀
首先,貼上全部代碼,稍後會慢慢解釋每一部分。/**
*
*/
package com.bert.udp;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* @author Bert
* 2019.03.09
*/
public class GuiChat extends JFrame {
private static final int DEFAULT_PORT = 8899;
//把主窗口分爲 NORTH.CENTER.SOUTH 三部分
private JLabel stateLB; //顯示監聽狀態
private JTextArea centerTextArea; //顯示聊天記錄
private JPanel sourthPanel; //最下面的面板
private JTextArea inputTextArea; //聊天輸入框
private JPanel bottomPanel; //放置IP輸入框,按鈕等
private JTextField ipTextField; //IP輸入框
private JTextField remotePortTF; //端口號輸入框
private JButton sendBT; //發送按鈕
private JButton clearBT; //清除按鈕
private DatagramSocket datagramSocket; //發送數據用的載體
/*
* 在構造方法中完成界面初始化,Socket連接初始化,和建立監聽狀態
*/
public GuiChat() {
setUPUI();
initSocket();
setListener();
}
/*
* 在 main方法中創建一個GuiChat類的對象,便是運行了程序;
*/
public static void main(String [] args) {
new GuiChat();
}
/*
* 初始化聊天界面
*/
private void setUPUI() { //聊天頁面初始化
setTitle("GUI聊天程序---出自JaffyMore"); //窗口標題欄設置
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //窗口關閉時觸發動作:退出程序
setSize(400, 400); //窗口默認尺寸設置
setResizable(false); //窗口大小不允許改動
setLocationRelativeTo(null); //窗口居中
//設置窗口中的North部分
stateLB = new JLabel("當前還未啓動監聽");
stateLB.setHorizontalAlignment(JLabel.RIGHT);
//窗口中的Center部分
centerTextArea = new JTextArea();
centerTextArea.setEditable(false);
centerTextArea.setBackground(new Color(211, 211, 211));
//窗口中的South部分
sourthPanel = new JPanel(new BorderLayout());
inputTextArea = new JTextArea(5,20);
bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,5,5));
ipTextField = new JTextField("127.0.0.1",8);
remotePortTF = new JTextField(String.valueOf(DEFAULT_PORT),3);
sendBT =new JButton("發送");
clearBT = new JButton("清屏");
bottomPanel.add(ipTextField);
bottomPanel.add(remotePortTF);
bottomPanel.add(sendBT);
bottomPanel.add(clearBT);
sourthPanel.add(new JScrollPane(inputTextArea),BorderLayout.CENTER);
sourthPanel.add(bottomPanel,BorderLayout.SOUTH);
add(stateLB,BorderLayout.NORTH);
add(new JScrollPane(centerTextArea), BorderLayout.CENTER);
add(sourthPanel, BorderLayout.SOUTH);
setVisible(true);
}
private void setListener() {//爲按鈕添加監聽事件
sendBT.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//獲取發送的目標IP和端口號
final String ipAddress = ipTextField.getText();
final String remotePort = remotePortTF.getText();
//判斷IP地址和端口號是否爲空
if(ipAddress == null ||ipAddress.trim().equals("")
||remotePort == null || remotePort.trim().equals("")){
JOptionPane.showMessageDialog(GuiChat.this, "請輸入IP地址和端口號");
return;
}
if(datagramSocket == null || datagramSocket.isClosed()) {
JOptionPane.showMessageDialog(GuiChat.this, "監聽不成功");
return;
}
//獲取需要發送的內容
String sendContent = inputTextArea.getText();
byte[] buf = sendContent.getBytes();
try {
//將發送的內容顯示到自己的聊天記錄中
centerTextArea.append("我對" + ipAddress + ":" +
remotePort + "說 \n" + inputTextArea.getText() +"\n\n" );
//添加內容後,使滾動條自動滾動到最低端
centerTextArea.setCaretPosition(centerTextArea.getText().length());
//發送數據
DatagramPacket packet = new DatagramPacket(buf,buf.length,
InetAddress.getByName(ipAddress),Integer.parseInt(remotePort));
datagramSocket.send(packet);
inputTextArea.setText("");
}catch(IOException e1) {
JOptionPane.showMessageDialog(GuiChat.this, "出錯了,本次發送失敗");
e1.printStackTrace();
}
}
});
//爲ClearBT 按鈕添加事件監聽器
clearBT.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
centerTextArea.setText("當前聊天內容爲空,哈哈哈");
}
});
}
private void initSocket() {
int port = DEFAULT_PORT;
while(true) {
try {
if(datagramSocket != null && !datagramSocket.isClosed()) {
datagramSocket.close();
}
try {
//判斷端口號範圍
port = Integer.parseInt(JOptionPane.showInputDialog(this,
"請輸入端口號","端口號",JOptionPane.QUESTION_MESSAGE));
if(port <1 || port >65535) {
throw new RuntimeException("端口號超出範圍" + port);
}
}catch(Exception e) {
JOptionPane.showMessageDialog(null, "你輸入的端口號不正確" );
continue;
}
//啓動DataGramSocket
datagramSocket = new DatagramSocket(port);
startListen();
stateLB.setText("正在監聽端口號:" + port);
break;
}catch(SocketException e) {
JOptionPane.showMessageDialog(this, "端口號已經被佔用,請重新輸入" );
stateLB.setText("當前還未啓動監聽");
}
}
}
private void startListen() { //創建線程進行消息接收
new Thread() {
private DatagramPacket datagramPacket;
public void run() {
byte [] buf = new byte[1024];
//創建數據包
datagramPacket = new DatagramPacket(buf, buf.length);
while(!datagramSocket.isClosed()) {
try {
datagramSocket.receive(datagramPacket);
centerTextArea.append(datagramPacket.getAddress().getHostAddress()
+ ":" + ((InetSocketAddress) datagramPacket.getSocketAddress()
).getPort() +"對我說: \n" + new String(datagramPacket.getData(),0,datagramPacket.getLength())
+"\n\n" );
}catch(IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
}