下午在公司闲的蛋疼,花了2个小时整了个局域网的聊天工具玩。界面模仿飞鸽传书,基于UDP协议,只有最基本的聊天功能。代码结构也比较乱,有兴趣的可以拿去玩玩。import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map;
import java.util.UUID;import javax.swing.JFrame;import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.border.EtchedBorder;
import javax.swing.table.DefaultTableModel;import java.awt.SystemColor;
import javax.swing.ScrollPaneConstants;
import java.awt.Color;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JLabel;public class Msg extends JFrame {
private static final long serialVersionUID = 3170335398335303363L;
private String uname = "qq"; private DatagramSocket server;// UDP
private InetAddress broadcastAddress;// 廣播地址
private int port;// 監聽端口 private final Map<String, UserInfo> userTable = new Hashtable<String, UserInfo>();// 用戶列表
private final String guid = UUID.randomUUID().toString().replace("-", "").toUpperCase();// 本機唯一標識 private JTable table;
private JTextArea textArea;
private JLabel lblNewLabel_1; public Msg() throws SocketException {
this(5413);
} public Msg(int port) throws SocketException {
this.port = port; getContentPane().setLayout(null);
getContentPane().setBackground(SystemColor.control); JButton btnNewButton = new JButton("刷新");
btnNewButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
refresh();
}
});
btnNewButton.setBackground(SystemColor.control);
btnNewButton.setBounds(299, 119, 83, 28);
getContentPane().add(btnNewButton); JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(12, 12, 275, 135);
getContentPane().add(scrollPane); table = new JTable(new DefaultTableModel(new Object[][] { { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, }, new String[] { "\u7528\u6236\u540D", "IP", "GUID" }) {
private static final long serialVersionUID = -6259343924352571655L; public boolean isCellEditable(int row, int column) {
return false;
}
});
table.setBackground(new Color(255, 255, 255));
scrollPane.setViewportView(table);
table.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null)); JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(12, 159, 370, 104);
getContentPane().add(scrollPane_1); textArea = new JTextArea();
textArea.setLineWrap(true);
textArea.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if ((e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER) || (e.isAltDown() && e.getKeyCode() == KeyEvent.VK_S)) {
sendMessage();
}
}
});
scrollPane_1.setViewportView(textArea); JButton button = new JButton("發送");
button.setBackground(SystemColor.control);
button.setBounds(141, 275, 83, 28);
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
sendMessage();
}
});
getContentPane().add(button); JButton button_1 = new JButton("關閉");
button_1.setBackground(SystemColor.control);
button_1.setBounds(22, 275, 83, 28);
button_1.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
Msg.this.dispatchEvent(new WindowEvent(Msg.this, WindowEvent.WINDOW_CLOSING));
}
});
getContentPane().add(button_1); JLabel lblNewLabel = new JLabel("當前在線人數");
lblNewLabel.setBounds(299, 29, 83, 18);
getContentPane().add(lblNewLabel); lblNewLabel_1 = new JLabel("0");
lblNewLabel_1.setBounds(305, 59, 55, 18);
getContentPane().add(lblNewLabel_1);

JLabel lblNewLabel_2 = new JLabel("Alt+S或Ctrl+Enter發送");
lblNewLabel_2.setBounds(242, 280, 140, 18);
getContentPane().add(lblNewLabel_2); this.setSize(400, 348);
setBackground(SystemColor.control);
setResizable(false);
setTitle("局域網聊天");
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
try {
sendBroadcast((guid + "2").getBytes(), broadcastAddress);
} catch (Exception e2) {
}
}
}); try { uname = JOptionPane.showInputDialog("請輸入你的暱稱");
uname = uname == null ? "匿名" : uname;
server = new DatagramSocket(port); broadcastAddress = InetAddress.getByName("255.255.255.255"); new AcceptBroadcastThread().start();// 啟動監聽
sendBroadcast((guid + "0" + uname).getBytes(), broadcastAddress);// 發送全網廣播,通知上線
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "端口" + port + "被佔用!");
System.exit(0);
}
} /**
 * 向外發送數據
 * 
 * @param data
 * @param address
 * @throws IOException
 */
public void sendBroadcast(byte[] data, InetAddress address) throws IOException {
DatagramPacket dp = new DatagramPacket(data, data.length, address, port);
server.send(dp);
} /**
 * 刷新列表
 */
public void refresh() {
// 清空列表
userTable.clear();
DefaultTableModel tableModel = ((DefaultTableModel) table.getModel());
for (int j = table.getRowCount(); j > 0; j--) {
tableModel.removeRow(j - 1);
}
try {
sendBroadcast((guid + "3" + uname).getBytes(), broadcastAddress);// 重新發送全網廣播,通知上線
} catch (Exception e) {
}
} public void alertMessage(final String msg) {
new Thread() {
public void run() {
JOptionPane.showMessageDialog(Msg.this, msg);
};
}.start();
} /**
 * 發送文字消息
 */
public void sendMessage() {
int[] selectRows = table.getSelectedRows();
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
String msg = guid + "1" + textArea.getText();
byte[] data = string2Bytes(msg);
for (int i = 0, j = selectRows.length; i < j; i++) {
String key = (String) tableModel.getValueAt(selectRows[i], 2);
UserInfo ui = key == null ? null : userTable.get(key);
if (ui != null) {
try {
textArea.setText("");
sendBroadcast(data, ui.getIpAddress());
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "發送消息到" + ui.getName() + "(" + ui.getIpAddress().getHostAddress() + ")失敗!", "發送失敗", JOptionPane.ERROR_MESSAGE);
}
}
}
} private byte[] string2Bytes(String str) {
try {
return str.getBytes("UTF-8");
} catch (Exception e) {
}
return null;
} class UserInfo { private String guid;
private String name;
private InetAddress ipAddress; public String getGuid() {
return guid;
} public void setGuid(String guid) {
this.guid = guid;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public InetAddress getIpAddress() {
return ipAddress;
} public void setIpAddress(InetAddress ipAddress) {
this.ipAddress = ipAddress;
}
} class AcceptBroadcastThread extends Thread {
public void run() {
while (true) {
try {
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
server.receive(dp); String msg = new String(dp.getData(), 0, dp.getLength(), "UTF-8");// 解析廣播數據包
String uid = msg.substring(0, 32);
String type = msg.substring(32, 33); if (type.equals("0") || type.equals("3")) {
UserInfo ui = new UserInfo();
ui.setGuid(uid);
ui.setName(msg.substring(33));
ui.setIpAddress(dp.getAddress()); // 刷新請求,只響應不做其他處理
if (userTable.containsKey(ui.getGuid()) && type.equals("3")) {
sendBroadcast((guid + "0" + uname).getBytes(), broadcastAddress);
} // 上線通知
if (!userTable.containsKey(ui.getGuid())) {
userTable.put(ui.getGuid(), ui);// 將新用戶添加到用戶表
lblNewLabel_1.setText("" + userTable.size()); sendBroadcast((guid + "0" + uname).getBytes(), broadcastAddress);// 響應非本機廣播
((DefaultTableModel) table.getModel()).insertRow(0, new String[] { ui.getName(), ui.getIpAddress().getHostAddress(), ui.getGuid() });
}
} else if (type.equals("1")) {
UserInfo ui = userTable.get(uid);
alertMessage(ui.getName() + "(" + ui.getIpAddress().getHostAddress() + ")-" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\r\n" + msg.substring(33));
} else {
userTable.remove(uid);// 移除用戶
lblNewLabel_1.setText("" + userTable.size()); DefaultTableModel tableModel = ((DefaultTableModel) table.getModel());
for (int i = 0, j = table.getRowCount(); i < j; i++) {
if (tableModel.getValueAt(i, 2).equals(uid)) {
tableModel.removeRow(i);
}
}
}
} catch (Exception e) {
}
}
}
} public static void main(String[] args) throws Exception {
Msg msg = new Msg();
msg.setVisible(true);
}
}

解决方案 »

  1.   

    恩,不错!学习一下UDP,只用TCP写过。
      

  2.   

    楼主的代码里没怎么用布局管理器啊。好奇的问下你是用windowbulider开发的么
      

  3.   

    不爱用布局管理器,用windowbulider调了下位置和尺寸
      

  4.   


    public class Messenger extends JFrame {
    private static final long serialVersionUID = 3170335398335303363L; private final String guid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); private final int online = 0;
    private final int offline = 1;
    private final int message = 2;
    private final int refresh = 3; private JScrollPane spUser;
    private JTable tabUser;
    private JButton btnRefresh;
    private JPanel paSeparator;
    private JScrollPane spEdit;
    private JTextArea taEdit;
    private JButton btnClose;
    private JButton btnSend;
    private JLabel lblOnline;
    private JLabel lblOnlineNum; private DatagramSocket ds;
    private String userName = "匿名";
    private Map<String, User> userTable = new Hashtable<String, Messenger.User>();
    private JLabel lblNewLabel; public Messenger() {
    generateWindow();// 生成窗體
    setUserName();// 設置用戶名
    listen();// 開始監聽消息
    broadcast(online);// 廣播上線消息
    } /**
     * 設置用戶名稱
     */
    public void setUserName() {
    String str = JOptionPane.showInputDialog("請輸入您的用戶名,最多6個字符");
    if (str != null && str.trim().length() != 0) {
    // userName = toUTF8(userName);
    userName = str.trim();
    if (userName.length() > 6) {
    userName = userName.substring(0, 6);
    }
    }
    } /**
     * 發送消息
     */
    public void send() {
    try {
    String msg = taEdit.getText();
    taEdit.setText("");
    byte[] data = (msg == null) ? (message + guid + "").getBytes("UTF-8") : (message + guid + msg).getBytes("UTF-8");
    DatagramPacket dp = new DatagramPacket(data, data.length); DefaultTableModel dtm = (DefaultTableModel) tabUser.getModel();
    for (int i : tabUser.getSelectedRows()) {
    Object key = dtm.getValueAt(i, 2);
    if (key != null) {
    User user = userTable.get(key);
    if (user != null) {
    dp.setAddress(user.getInetAddress());
    dp.setPort(5413); ds.send(dp);
    }
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    } /**
     * 彈出消息盒子
     */
    public void showMessage(final String uid, final String msg) {
    new Thread() {
    public void run() {
    MessageBox mb = new MessageBox(userTable.get(uid), msg);
    mb.setVisible(true);
    };
    }.start();
    } /**
     * 回复消息
     * 
     * @param uid
     */
    public void reply(String uid) {
    DefaultTableModel dtm = (DefaultTableModel) tabUser.getModel();
    for (int i = 0; i < tabUser.getRowCount(); i++) {
    if (uid.equals(dtm.getValueAt(i, 2))) {
    tabUser.setRowSelectionInterval(i, i);
    }
    }
    taEdit.setFocusable(true);
    } /**
     * 刷新用戶列表
     */
    public void refresh() {
    // 清空用戶列表
    userTable.clear();
    // 清空表格
    DefaultTableModel dtm = (DefaultTableModel) tabUser.getModel();
    for (int i = tabUser.getRowCount(); i > 0; i--) {
    dtm.removeRow(i - 1);
    }
    // 添加5個空行
    for (int i = 0; i < 5; i++) {
    dtm.addRow(new Object[] { null, null, null });
    }
    // 發送刷新廣播
    broadcast(refresh);
    } /**
     * 新用戶上線
     * 
     * @param user
     */
    public void addUser(User user) {
    userTable.put(user.getGuid(), user);
    DefaultTableModel dtm = (DefaultTableModel) tabUser.getModel();
    dtm.insertRow(0, new Object[] { user.getUserName(), user.getHostAddress(), user.getGuid() });
    lblOnlineNum.setText(userTable.size() + "");
    } /**
     * 用戶下線
     * 
     * @param uid
     */
    public void removeUser(String uid) {
    userTable.remove(uid);
    DefaultTableModel dtm = (DefaultTableModel) tabUser.getModel();
    for (int i = 0; i < tabUser.getRowCount(); i++) {
    if (uid.equals(dtm.getValueAt(i, 2))) {
    dtm.removeRow(i);
    }
    }
    lblOnlineNum.setText(userTable.size() + "");
    } /**
     * 發送廣播消息
     */
    public void broadcast(int flag) {
    try {
    if (ds != null) {
    byte[] data = (flag + guid + userName).getBytes("UTF-8");
    ds.send(new DatagramPacket(data, 0, data.length, InetAddress.getByName("255.255.255.255"), 5413));
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    } /**
     * 監聽消息
     */
    public void listen() {
    try {
    ds = new DatagramSocket(5413);// 啟動監聽器
    } catch (Exception e) {
    JOptionPane.showMessageDialog(this, "5413端口被佔用", "錯誤", JOptionPane.ERROR_MESSAGE);
    dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
    return;
    }
    // 啟動一個線程開始監聽
    new Thread() {
    public void run() {
    while (true) {
    try {
    DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
    ds.receive(dp);// 此方法會阻塞線程,直到收到消息 // 將發送過來的消息還原成字符串
    String msg = new String(dp.getData(), 0, dp.getLength(), "UTF-8"); if (msg != null && msg.length() > 0) { int msgType = Integer.parseInt(msg.substring(0, 1));// 第1個字符為消息類型
    String uid = msg.substring(1, 33);// 第2到33個字符為用戶唯一標識 switch (msgType) {
    case 0:// 上線廣播
    if (!userTable.containsKey(uid)) {
    User user = new User();
    user.setGuid(uid);
    user.setUserName(msg.substring(33));// 如果是上線廣播則第33位以後就是用戶名
    user.setInetAddress(dp.getAddress()); addUser(user);// 添加到用戶表中 // 發送響應
    byte[] data = (online + guid + userName).getBytes("UTF-8");
    DatagramPacket p = new DatagramPacket(data, data.length, dp.getAddress(), 5413);
    ds.send(p);
    }
    break;
    case 1:// 下線廣播
    removeUser(uid);
    break;
    case 2:// 用戶消息
    showMessage(uid, msg.substring(33));// 如果是用戶消息則第33位開始為用戶消息
    break;
    case 3:// 刷新廣播
    if (!guid.equals(uid) || !userTable.containsKey(uid)) {
    // 發送響應
    byte[] data = (online + guid + userName).getBytes("UTF-8");
    DatagramPacket p = new DatagramPacket(data, data.length, dp.getAddress(), 5413);
    ds.send(p);
    }
    break;
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    }.start();
    } /**
     * 生成窗體
     */
    private void generateWindow() {
    setSize(415, 315);
    setResizable(false);
    setLocationRelativeTo(null);
    setTitle("局域網聊天");
    getContentPane().setLayout(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 窗體關閉事件,發送下線廣播
    addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
    broadcast(offline);
    if (ds != null) {
    ds.close();
    }
    }
    }); // 用戶列表滾動條
    spUser = new JScrollPane();
    spUser.setBounds(12, 12, 292, 102);
    getContentPane().add(spUser); // 用戶列表
    tabUser = new JTable(new DefaultTableModel(new Object[][] { { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, { null, null, null }, }, new String[] { "\u7528\u6236\u540D", "IP\u5730\u5740", "\u552F\u4E00\u6A19\u8B58" }) {
    private static final long serialVersionUID = 8891200084509298048L;
    private boolean[] columnEditables = new boolean[] { false, false, false }; public boolean isCellEditable(int row, int column) {
    return columnEditables[column];
    }
    });
    spUser.setViewportView(tabUser); // 文本編輯器滾動條
    spEdit = new JScrollPane();
    spEdit.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    spEdit.setBounds(12, 126, 383, 102);
    getContentPane().add(spEdit); // 文本編輯區
    taEdit = new JTextArea();
    taEdit.addKeyListener(new KeyAdapter() {
    public void keyPressed(KeyEvent e) {
    if ((e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER) || (e.isAltDown() && e.getKeyCode() == KeyEvent.VK_S)) {
    send();
    }
    }
    });
    taEdit.setLineWrap(true);
    spEdit.setViewportView(taEdit); // 分隔條
    paSeparator = new JPanel();
    paSeparator.setBorder(new EtchedBorder(EtchedBorder.RAISED, null, null));
    paSeparator.setBounds(12, 117, 383, 5);
    getContentPane().add(paSeparator); // 刷新按鈕
    btnRefresh = new JButton("刷新");
    btnRefresh.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    refresh();
    }
    });
    btnRefresh.setBounds(316, 77, 79, 28);
    getContentPane().add(btnRefresh); // 關閉按鈕
    btnClose = new JButton("關閉");
    btnClose.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    Messenger.this.dispatchEvent(new WindowEvent(Messenger.this, WindowEvent.WINDOW_CLOSING));
    }
    });
    btnClose.setBounds(12, 240, 98, 28);
    getContentPane().add(btnClose); // 發送按鈕
    btnSend = new JButton("發送");
    btnSend.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    send();
    }
    });
    btnSend.setBounds(297, 240, 98, 28);
    getContentPane().add(btnSend); // 當前在線人數標籤
    lblOnline = new JLabel("當前在線人數");
    lblOnline.setBounds(316, 13, 79, 28);
    getContentPane().add(lblOnline); // 當前在線人數
    lblOnlineNum = new JLabel("0");
    lblOnlineNum.setHorizontalAlignment(SwingConstants.CENTER);
    lblOnlineNum.setBounds(326, 42, 55, 18);
    getContentPane().add(lblOnlineNum); lblNewLabel = new JLabel("Alt + S 或 Ctrl + Enter 發送");
    lblNewLabel.setBounds(128, 245, 158, 18);
    getContentPane().add(lblNewLabel);
    }
      

  5.   

    /**
     * 消息盒子
     * 
     * @author 小綿羊
     */
    class MessageBox extends JFrame {
    private static final long serialVersionUID = -2027863244344802324L; private JPanel panel;
    private JLabel lblInfo;
    private JLabel lblTime;
    private JScrollPane scrollPane;
    private JTextArea taMessage;
    private JButton btnClose;
    private JButton btnReply;
    private User user;
    private String msg;
    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public MessageBox(User user, String msg) {
    this.user = user;
    this.msg = msg;
    generateWindow();
    } /**
     * 生成消息窗體
     */
    private void generateWindow() {
    setSize(415, 315);
    setResizable(false);
    setLocationRelativeTo(null);
    setTitle("收到消息");
    getContentPane().setLayout(null);
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); panel = new JPanel();
    panel.setBorder(new TitledBorder(new TitledBorder(null, "\u6D88\u606F\u4F86\u81EA...", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 70, 213)), "", TitledBorder.LEADING, TitledBorder.TOP, null, Color.BLACK));
    panel.setBounds(10, 10, 389, 73);
    panel.setLayout(null);
    getContentPane().add(panel); lblInfo = new JLabel(user.toString());
    lblInfo.setHorizontalAlignment(SwingConstants.CENTER);
    lblInfo.setBounds(12, 15, 365, 18);
    panel.add(lblInfo); lblTime = new JLabel("時間:" + format.format(new Date()));
    lblTime.setHorizontalAlignment(SwingConstants.CENTER);
    lblTime.setBounds(12, 45, 365, 16);
    panel.add(lblTime); scrollPane = new JScrollPane();
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPane.setBounds(10, 94, 389, 141);
    getContentPane().add(scrollPane); taMessage = new JTextArea(msg);
    taMessage.setLineWrap(true);
    taMessage.setEditable(false);
    scrollPane.setViewportView(taMessage); btnClose = new JButton("關閉");
    btnClose.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    MessageBox.this.dispatchEvent(new WindowEvent(MessageBox.this, WindowEvent.WINDOW_CLOSING));
    }
    });
    btnClose.setBounds(65, 245, 98, 28);
    getContentPane().add(btnClose); btnReply = new JButton("回复");
    btnReply.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    MessageBox.this.dispatchEvent(new WindowEvent(MessageBox.this, WindowEvent.WINDOW_CLOSING));
    Messenger.this.reply(user.getGuid());
    }
    });
    btnReply.setBounds(253, 245, 98, 28);
    getContentPane().add(btnReply);
    }
    } class User {
    private String guid;
    private String userName;
    private String hostAddress;
    private InetAddress inetAddress; public String getGuid() {
    return guid;
    } public void setGuid(String guid) {
    this.guid = guid;
    } public String getUserName() {
    return userName;
    } public void setUserName(String userName) {
    this.userName = userName;
    } public String getHostAddress() {
    return hostAddress;
    } public InetAddress getInetAddress() {
    return inetAddress;
    } public void setInetAddress(InetAddress inetAddress) {
    this.inetAddress = inetAddress;
    this.hostAddress = inetAddress.getHostAddress();
    } public String toString() {
    return userName + "(" + hostAddress + ")";
    }
    } public static void main(String[] args) {
    new Messenger().setVisible(true);
    }
    }