JAVA基础学习之UDP网络编程
来源:互联网 发布:mac用破解版软件风险 编辑:程序博客网 时间:2024/05/16 07:45
UDP(UserDatagramProtocol)用户数据报包协议
UDP和TCP位于同一层-传输层,但它对于数据包的顺序错误或重发没有TCP来的可靠。因此,UDP不被应用于那些使用虚电路的面向直接服务.
UDP是一种面向无连接的通信协议。UDP向应用程序提供了一种发送封装的原始IP数据包的方法,并且发送时无需建立连接,不保证可靠数据的传输
特点:面向无连接的数据传输,不可靠的,但效率高。
UDP一次发送的数据不能超过64KB.
UDP编程所需要的类:
DatagramSocket 此类表示用来发送和接收数据报包的套接字
DatagramPacket 此类表示数据报包
DatagramPacket(byte[]buf, intlength, InetAddressaddress, intport)
参数:buf -包数据
length -包长度
address -目的地址
port -目的端口号
写法步骤:
服务器端:创建监听套接字,接受数据包,发送数据包,关闭套接字
客户端: 创建套接字,发送数据包,接受数据包,关闭套接字
DatagramSocket类
DatagramSocket(int port)
创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port, InetAddress laddr)
创建数据报套接字,将其绑定到指定的本地地址。
DatagramPacket类
构造方法摘要
DatagramPacket(byte[] buf, int length)
构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length)
构造 DatagramPacket,用来接收长度为 length 的包,在缓冲区中指定了偏移量。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)
构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int length, SocketAddress address)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
一般方法
InetAddress getAddress()
返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
byte[] getData()
返回数据缓冲区。
int getLength()
返回将要发送或接收到的数据的长度。
int getOffset()
返回将要发送或接收到的数据的偏移量。
int getPort()
返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
SocketAddress getSocketAddress()
获取要将此包发送到的或发出此数据报的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。
void setAddress(InetAddress iaddr)
设置要将此数据报发往的那台机器的 IP 地址。
void setData(byte[] buf)
为此包设置数据缓冲区。
void setData(byte[] buf, int offset, int length)
为此包设置数据缓冲区。
void setLength(int length)
为此包设置长度。
void setPort(int iport)
设置要将此数据报发往的远程主机上的端口号。
void setSocketAddress(SocketAddress address)
设置要将此数据报发往的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。
示例1:
本例子使用WindowBuilder图形界面进行编写。实现简单的一对一聊天
界面效果:
java代码
package com.ql.Receivers;import java.awt.EventQueue;import javax.swing.JFrame;import javax.swing.JPanel;import java.awt.BorderLayout;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.SocketAddress;import java.net.SocketException;import java.net.UnknownHostException;import javax.swing.JLabel;import javax.swing.JTextField;import javax.swing.JButton;import javax.swing.JScrollPane;import javax.swing.JTextArea;public class Receiver implements ActionListener { private JFrame frame; private JTextField txtStr; private JTextArea txtArea; private JButton btnSend, btnEnter; private JTextField txtYouAddress; private DatagramSocket receiverSocket, sendSocket;//发送和接收套接字 private JTextField txtMyAddress; private String youAddress = "127.0.0.2", myAddress = "127.0.0.1";//己方地址和对方地址 /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Receiver window = new Receiver(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public Receiver() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 530, 370); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(new BorderLayout(0, 0)); JPanel panel = new JPanel(); frame.getContentPane().add(panel); panel.setLayout(null); JPanel panel_1 = new JPanel(); panel_1.setBounds(0, 33, 514, 256); panel.add(panel_1); panel_1.setLayout(new BorderLayout(0, 0)); JScrollPane scrollPane = new JScrollPane(); panel_1.add(scrollPane); txtArea = new JTextArea(); scrollPane.setViewportView(txtArea); JPanel panel_2 = new JPanel(); panel_2.setBounds(0, 288, 514, 44); panel.add(panel_2); panel_2.setLayout(null); JLabel lblNewLabel = new JLabel("\u8BF7\u8F93\u5165\uFF1A"); lblNewLabel.setBounds(10, 18, 54, 15); panel_2.add(lblNewLabel); txtStr = new JTextField(); txtStr.setBounds(74, 15, 329, 21); panel_2.add(txtStr); txtStr.setColumns(10); btnSend = new JButton("\u53D1\u9001"); btnSend.setBounds(413, 12, 93, 27); btnSend.addActionListener(this); panel_2.add(btnSend); JPanel panel_3 = new JPanel(); panel_3.setBounds(0, 0, 514, 31); panel.add(panel_3); panel_3.setLayout(null); JLabel lblNewLabel_1 = new JLabel("\u5BF9\u65B9IP\uFF1A"); lblNewLabel_1.setBounds(10, 10, 54, 15); panel_3.add(lblNewLabel_1); txtYouAddress = new JTextField(); txtYouAddress.setText("127.0.0.1"); txtYouAddress.setBounds(65, 7, 152, 21); panel_3.add(txtYouAddress); txtYouAddress.setColumns(10); JLabel lblNewLabel_2 = new JLabel("\u60A8\u7684IP\uFF1A"); lblNewLabel_2.setBounds(234, 10, 54, 15); panel_3.add(lblNewLabel_2); txtMyAddress = new JTextField(); txtMyAddress.setText("127.0.0.1"); txtMyAddress.setBounds(282, 7, 152, 21); panel_3.add(txtMyAddress); txtMyAddress.setColumns(10); btnEnter = new JButton("\u786E\u5B9A"); btnEnter.setBounds(440, 6, 64, 23); btnEnter.addActionListener(this); panel_3.add(btnEnter); } @Override public void actionPerformed(ActionEvent e) { // 按钮处理 if (e.getSource() == btnSend) { //发送 String string = txtStr.getText().trim(); send(string); } if(e.getSource() == btnEnter){ //连接 if(!"".equals(txtMyAddress.getText().trim()) && !"".equals(txtYouAddress.getText().trim())){ myAddress = txtMyAddress.getText().trim(); youAddress = txtYouAddress.getText().trim(); connect(myAddress); //封装的连接方法 }else{ txtArea.setText(txtArea.getText() + "发送目的地址或自己地址不能为空!"); } } } /** * 封装的连接方法 * @param address 己方地址,用于接收数据包 */ public void connect(String address) { SocketAddress mAddress = new InetSocketAddress(address, 8888); try { receiverSocket = new DatagramSocket(mAddress);//实例化接收套接字 sendSocket = new DatagramSocket();//实例化发送套接字 } catch (SocketException e) { e.printStackTrace(); } new ReceiverThread(receiverSocket).start();//将接收放入线程中,不断接收数据 } /** * 用于接收消息的线程 * @author qinlang * */ class ReceiverThread extends Thread { DatagramSocket socket; public ReceiverThread(DatagramSocket socket){ this.socket = socket; } @Override public void run() { while(true){ DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//定义并实例化接收对象 try { socket.receive(packet);//接收数据包 } catch (IOException e) { e.printStackTrace(); } txtArea.setText(txtArea.getText() + "\n" + new String(packet.getData(), 0, packet.getLength()));//显示数据包内容 } } } /** * 用于发送数据包的方法 * @param str */ public void send(String str){ InetAddress address = null;//定义发送至的地址 try { address = InetAddress.getByName(youAddress);//实例化地址 } catch (UnknownHostException e1) { e1.printStackTrace(); } DatagramPacket packet = new DatagramPacket(str.getBytes(), str.getBytes().length, address, 8888);//定义并实例化数据包 try { sendSocket.send(packet);//发送数据包 txtArea.setText(txtArea.getText() + "\n已发送..."); } catch (IOException e) { e.printStackTrace(); } }}
示例2:
本例子使用WindowBuilder图形界面进行编写。实现简单的多对多聊天
界面效果:
java代码:
客户端
package com.ql.talkM2M;import java.awt.EventQueue;import javax.swing.JFrame;import javax.swing.JPanel;import java.awt.BorderLayout;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.InetSocketAddress;import java.net.SocketException;import javax.swing.JLabel;import javax.swing.JTextField;import javax.swing.JButton;import javax.swing.JScrollPane;import javax.swing.JTextArea;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class Sender implements ActionListener{ private JFrame frame; private JTextField txtName; private JTextField txtServerAddress; private JTextField txtStr; private JButton btnConnect, btnSend; private JTextArea textArea; private DatagramSocket socket;//套接字 private DatagramPacket packet;//数据包 private String name; //昵称 private Thread thread;//用于接收的线程 /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Sender window = new Sender(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public Sender() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.addWindowListener(new WindowAdapter() {//程序关闭通知所有在线的用户 @Override public void windowClosing(WindowEvent e) { if(thread != null){ send("退出了..."); } } }); frame.setBounds(100, 100, 536, 354); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); frame.getContentPane().add(panel, BorderLayout.CENTER); panel.setLayout(null); JPanel panel_1 = new JPanel(); panel_1.setBounds(0, 0, 520, 37); panel.add(panel_1); panel_1.setLayout(null); JLabel lblNewLabel = new JLabel("\u6635\u79F0\uFF1A"); lblNewLabel.setBounds(263, 10, 44, 15); panel_1.add(lblNewLabel); txtName = new JTextField(); txtName.setBounds(305, 7, 131, 21); panel_1.add(txtName); txtName.setColumns(10); btnConnect = new JButton("连接"); btnConnect.setBounds(446, 6, 64, 23); btnConnect.addActionListener(this); panel_1.add(btnConnect); JLabel lblNewLabel_1 = new JLabel("\u670D\u52A1\u5668IP\uFF1A"); lblNewLabel_1.setBounds(10, 10, 64, 15); panel_1.add(lblNewLabel_1); txtServerAddress = new JTextField(); txtServerAddress.setText("127.0.0.1"); txtServerAddress.setBounds(74, 7, 179, 21); panel_1.add(txtServerAddress); txtServerAddress.setColumns(10); JPanel panel_2 = new JPanel(); panel_2.setBounds(0, 279, 520, 37); panel.add(panel_2); panel_2.setLayout(null); JLabel lblNewLabel_2 = new JLabel("\u8BF7\u8F93\u5165\uFF1A"); lblNewLabel_2.setBounds(10, 12, 54, 15); panel_2.add(lblNewLabel_2); txtStr = new JTextField(); txtStr.setBounds(57, 9, 362, 21); panel_2.add(txtStr); txtStr.setColumns(10); btnSend = new JButton("\u53D1\u9001"); btnSend.setEnabled(false); btnSend.setBounds(427, 8, 83, 23); btnSend.addActionListener(this); panel_2.add(btnSend); JPanel panel_3 = new JPanel(); panel_3.setBounds(0, 37, 520, 242); panel.add(panel_3); panel_3.setLayout(new BorderLayout(0, 0)); JScrollPane scrollPane = new JScrollPane(); panel_3.add(scrollPane); textArea = new JTextArea(); scrollPane.setViewportView(textArea); } @Override public void actionPerformed(ActionEvent e) { //按钮按键处理 if(e.getSource() == btnConnect){ //连接 if("连接".equals(btnConnect.getText())){//按钮上的文字显示“连接”,表示没有连接,点击连接 if("".equals(txtServerAddress.getText()) || "".equals(txtName.getText().trim())){ textArea.setText(textArea.getText() + "请输入服务器IP或昵称!\n"); }else{ connect();//封装的连接方法 btnConnect.setText("断开");//连接按钮改变文字 thread = new Thread(new IN(socket));//将接收放入线程中,不断接收数据包 thread.start(); btnSend.setEnabled(true);//发送按钮使能 } }else if("断开".equals(btnConnect.getText())){//按钮上的文字显示“断开”,表示正在连接,点击断开 if(e.getSource() == btnConnect){ send("退出了...");//断开了连接,表明已下线 if(thread != null){ thread.stop();//销毁线程 btnSend.setEnabled(false);//发送使否 } btnConnect.setText("连接");//连接按钮改变文字 } } } if(e.getSource() == btnSend){ //发送 String string = txtStr.getText().trim(); send(string);//封装的发送方法 } } /** * 连接方法 */ public void connect(){ try { socket = new DatagramSocket();//实例化套接字 name = txtName.getText().trim(); String str = name + ":上线了..."; String address = ""; address = txtServerAddress.getText().trim();//得到服务器ip //连接上服务器,发送一次数据,通知服务器上的所有用户 packet = new DatagramPacket(str.getBytes(),str.getBytes().length, new InetSocketAddress(address, 8888)); socket.send(packet); textArea.setText(textArea.getText() + "\n已连接..."); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 为接收开启单独的线程,不断接收数据 * @author qinlang * */ class IN implements Runnable { private DatagramSocket socket; public IN(DatagramSocket socket) { this.socket = socket; } @Override public void run() { byte[] b = new byte[1024];//一次读取数据大小 DatagramPacket packet2 = new DatagramPacket(b, b.length);// 用来接收的包裹 String value = ""; while (true) { try { socket.receive(packet2);//接收数据 value = new String(b, 0, packet2.getLength());//将数据分割读取 textArea.setText(textArea.getText() + "\n" + value); } catch (IOException e) { break; } } } } /** * 发送数据的方法 * @param data */ public void send(String data){ try { packet.setData((name + ":" + data).getBytes());//设置数据(发送的数据和昵称),转换成字节流 socket.send(packet);//发送数据 textArea.setText(textArea.getText() + "\n您:" + data); } catch (IOException e) { e.printStackTrace(); } }}
服务器
package com.ql.talkM2M;import java.io.BufferedReader;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketAddress;import java.net.SocketException;import java.util.ArrayList;import java.util.List;/** * 服务器端,可看做只转发数据的服务器,也可以当客户端发送数据 * @author qinlang * */public class Server { /** * @param args */ public static void main(String[] args) { DatagramSocket socket = null; DatagramPacket packet = null; List<SocketAddress> addresses;//存放所有用户地址的集合 try { socket = new DatagramSocket(8888); packet = new DatagramPacket(new byte[1024], 1024); socket.receive(packet);//接收一次自己的数据 } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } addresses = new ArrayList<SocketAddress>(); addresses.add(packet.getSocketAddress()); //将自己的地址加入集合 new Thread(new INReceiver(socket, addresses)).start();//启动接收线程 //发送线程没有启动,因为只做转发功能,服务器不需要发送自己的数据 }}/** * 发送数据线程,此方法用于服务器对连接在服务器上的用户发数据 * @author qinlang * */class OUTReceiver implements Runnable { BufferedReader br; DatagramPacket packet;// 数据 地址 DatagramSocket socket; List<SocketAddress> addresses; public OUTReceiver(BufferedReader br, DatagramPacket packet, DatagramSocket socket, List<SocketAddress> addresses) { this.br = br; this.packet = packet; this.socket = socket; this.addresses = addresses; } @Override public void run() { while (true) {//死循环,不断发送数据 try { String data = br.readLine();//按行读取数据 packet.setData((Thread.currentThread().getName() + data).getBytes()); // 同一个数据,把所有在线的人都发一遍 for (SocketAddress socketAddress : addresses) { packet.setSocketAddress(socketAddress); socket.send(packet); } // 建议你不要把服务器关掉 } catch (IOException e) { e.printStackTrace(); } } }}/** * 接收数据线程 * @author qinlang * */class INReceiver implements Runnable { private DatagramSocket socket; private List<SocketAddress> addresses; public INReceiver(DatagramSocket socket, List<SocketAddress> addresses) { this.socket = socket; this.addresses = addresses; } @Override public void run() { byte[] b = new byte[1024]; DatagramPacket packet = new DatagramPacket(b, b.length);// 用来接收的包裹 String value = ""; while (true) { try { socket.receive(packet);//接收数据 SocketAddress myadd = packet.getSocketAddress();// 得到发数据过来的地址 // 同一个数据,把所有在线的人都发一遍 for (SocketAddress socketAddress : addresses) { if (socketAddress.equals(myadd))//如果是自身,则跳过 continue; packet.setSocketAddress(socketAddress); socket.send(packet); } // 第一次来的时候,把这个地址添加到地址集合里面去 if (!addresses.contains(myadd)) addresses.add(myadd); if (value.equalsIgnoreCase("esc"))//如果退出了,把地址从集合中移除 addresses.remove(myadd); } catch (IOException e) { e.printStackTrace(); } } }}
- JAVA基础学习之UDP网络编程
- Java基础学习记录之网络编程(TCP/UDP)
- Java基础-网络编程之UDP编程
- java基础--网络编程之UDP
- Java基础--网络编程之UDP
- java基础学习网络编程之UDP和TCP协议 十四 -3
- Java基础——网络编程(上)之UDP
- java网络编程之UDP
- java网络编程之UDP
- java网络编程之UDP
- Java网络编程之UDP
- JAVA网络编程之UDP
- java 网络编程之UDP
- Java网络编程之UDP
- java网络编程之UDP
- [学习笔记]Java网络编程之UDP通讯
- [学习笔记]Java网络编程之UDP通讯
- Java学习笔记之网络编程(一):UDP
- java连接mysql(2)
- Android TabLayout定制CustomView与ViewPager交互双向联动
- linux之cut用法
- UI 动画之UIView动画的 四种 使用含有block的类方法 实现动画
- 【bzoj1856】【Scoi2010】【字符串】
- JAVA基础学习之UDP网络编程
- WIFI营销读书笔记之一:Wifi营销基础知识
- UIView与CALayer
- FZU2203--比赛--10.1训练赛
- JSP include
- ios:数据持久化的几种方法浅谈
- MP之插件开发-事务
- info.plist
- I/O多路复用