java 网络编程基础 UDP协议DatagramSocket,MulticastSocket 实现局域网聊天软件(Server + Client模式)
开发思路:
服务端两个Socket:
- UDP的DatagramSocket接收客户端消息。
- 广播multicastSocket 发送广播消息
客户端一个Socket:
- multicastSocket 接收服务端发来的广播 (不允许客户端直接发广播),同时发送点对点数据到UDP服务端DatagramSocket 。
- javax.swing.* 提供客户端图形化界面
生疏知识点:
图形化界面按钮监控键盘
addActionListener(AbstractAction接口实现类);监听器。
topTextField.getInputMap().put(KeyStroke.getKeyStroke('\n'),"confirm_username"); 键盘事件和名字关联;
topTextField.getActionMap().put("confirm_username",confirmListener); 事件别名和监听器关联
服务器端程序:
package tcpandudp.udpexample; import java.io.IOException; import java.net.*; /** * @ClassName MulticastServerScoket * @projectName: object1 * @author: Zhangmingda * @description: 设计思想:为避免所有人直接发广播,导致消息内容无环节把控,消息发送的时候,发送到非广播端口(作为一个服务端)再由此服务端向广播地址发送消息, * date: 2021/5/13. */ public class MulticastServerScoket { /** * 广播Socket端口 */ private static final int BROAD_PORT = 30000; /** * 广播IP地址 :224.0.0.0 到 239.255.255.255 */ private static final String BROAD_IP = "230.3.3.3"; /** * 服务端口 */ private static final int SERVER_PORT = 8888; private void start(){ try ( /** * 广播用套接字 */ MulticastSocket multicastSocket = new MulticastSocket(BROAD_PORT); /** * 服务端套接字 */ DatagramSocket datagramSocket = new DatagramSocket(SERVER_PORT) ){ /** * 广播IP地址 */ InetAddress multi_addr = InetAddress.getByName(BROAD_IP); /** * 广播套接字配置接收广播的IP地址 */ multicastSocket.joinGroup(multi_addr); /** * 构建接收UDP数据的包 */ byte[] inBuff = new byte[4096]; DatagramPacket inPacket = new DatagramPacket(inBuff,inBuff.length); /** * 接收广播,并广播出去 */ while (true){ //普通套接字收广播 datagramSocket.receive(inPacket); String content = new String(inPacket.getData(),0,inPacket.getLength()); System.out.println(content); //广播套接字发广播 DatagramPacket outPacket = new DatagramPacket(inPacket.getData(),inPacket.getLength(),multi_addr,BROAD_PORT); multicastSocket.send(outPacket); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 程序入口 */ public static void main(String[] args) { new MulticastServerScoket().start(); } }
客户端
package tcpandudp.udpexample; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.net.*; import java.util.Scanner; import java.util.concurrent.atomic.AtomicReference; /** * @ClassName MulticastClientSocket * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/5/13. */ public class MulticastClientSocket { /** * 广播Socket端口 */ private static final int BROAD_PORT = 30000; /** * 广播IP地址 :224.0.0.0 到 239.255.255.255 */ private static final String BROAD_IP = "230.3.3.3"; /** * 要发送数据包的服务端IP地址和 端口 */ private static final String SERVER_IP = "127.0.0.1"; private static final int SERVER_PORT = 8888; private void go() { JFrame jFrame = new JFrame("广播聊天客户端"); //上部 JPanel topPanel = new JPanel(); JTextField topTextField = new JTextField(30); JButton topButton = new JButton("确认用户名"); topPanel.add(topTextField); topPanel.add(topButton); jFrame.add(topPanel, BorderLayout.NORTH); //中部 JTextArea centerArea = new JTextArea(10,40); JScrollPane centerPane = new JScrollPane(centerArea); jFrame.add(centerPane); //下 JPanel bottomPanel = new JPanel(); JTextField bottomTextField = new JTextField(35); JButton sendButton = new JButton("发送"); bottomPanel.add(bottomTextField); bottomPanel.add(sendButton); jFrame.add(bottomPanel, BorderLayout.SOUTH); jFrame.setLocation(400,300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.pack(); jFrame.setVisible(true); AtomicReference<String> username = new AtomicReference<>(""); //确认用户名事件监听器 Action confirmListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { String topTextContent = topTextField.getText(); if (topTextContent != null && ! "".equals(topTextContent)){ username.set(topTextContent); System.out.println("用户名设置成功"); } } }; //绑定事件监听器 topButton.addActionListener(confirmListener); topTextField.getInputMap().put(KeyStroke.getKeyStroke('\n'),"confirm_username"); topTextField.getActionMap().put("confirm_username",confirmListener); /** * 发送&接收用socket */ try{ MulticastSocket mClinetSocket = new MulticastSocket(BROAD_PORT); InetAddress multi_addr = InetAddress.getByName(BROAD_IP); /** * 接收端 */ new Thread(){ @Override public void run() { byte[] inBuff = new byte[4096]; /** * 构建接收包 */ DatagramPacket inPacket = new DatagramPacket(inBuff,0,inBuff.length); while (true){ /** * 接收数据放包里,转为字符串打印出来 */ try { mClinetSocket.receive(inPacket); } catch (IOException e) { e.printStackTrace(); } String content = new String(inPacket.getData(),0, inPacket.getLength()); System.out.println(content); centerArea.append(content + "\n"); //向文本框加入文本 } } }.start(); /** * 套接字加入广播地址 */ mClinetSocket.joinGroup(multi_addr); /** * 服务端地址构建 */ InetAddress server_addr = InetAddress.getByName(SERVER_IP); /** * 构建发出包 */ DatagramPacket outPacket = new DatagramPacket(new byte[0],0,server_addr,SERVER_PORT); /** * 发送按钮监听器 */ Action sendListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { if (username.get().equals("")){ System.err.println("请输入用户名"); }else { String sendContent = bottomTextField.getText(); if (sendContent != null && ! "".equals(sendContent)){ sendContent = username + ":" + sendContent; //输入字节存入包, outPacket.setData(sendContent.getBytes()); try { mClinetSocket.send(outPacket); bottomTextField.setText(null); } catch (IOException ex) { ex.printStackTrace(); } } } } }; /** * 发送按钮绑定监听器 */ sendButton.addActionListener(sendListener); //内容框监听键盘 bottomTextField.getInputMap().put(KeyStroke.getKeyStroke('\n'),"send"); bottomTextField.getActionMap().put("send",sendListener); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new MulticastClientSocket().go(); } }
posted on 2021-05-14 23:06 zhangmingda 阅读(474) 评论(0) 编辑 收藏 举报