【网络编程2】Java数据报套接字
来源:互联网 发布:如何创建域名 编辑:程序博客网 时间:2024/06/06 00:34
这篇博文是本文学习《Java网络程序设计》书中第5章数据报套接字的学习总结。初学者网友学习这篇Java数据报套接字文章,如果难于理解文章前面理论部分,可以先运行后面的程序,边看运行后面的程序边理解前面的原理,这对初学者是最好的方法。所有源代码都在文章后面我的github链接代码中。
——惠州学院13网络工程 吴成兵 20160609
目录 1
- 目录 1
- 一 数据报套接字概述
- 二 DatagramPacket
- 21 创建DatagramPacket对象
- 211 创建的DatagramPacket对象用于接收数据
- 212 创建的DatagramPacket对象用于发送数据
- 22 DatagramPacket常用方法
- 21 创建DatagramPacket对象
- 三 DatagramSocket
- 31 创建DatagramSocket对象
- 32 DatagramSocket常用方法
- 四 DatagramSocket编程示例
- 41 利用DatagramSocket查询端口占用情况
- 42 利用数据报通信的CS程序
- 421 数据接收端
- 422 数据发送端
- 43 用UDP实现的聊天程序
一 数据报套接字概述
流套接字的每个连接均要花费一定的时间,为了减少这种开销,网络API提供了第二种套接字——数据报套接字(DatagramSocket),又称自寻址套接字。
数据报套接字基于的协议是UDP协议,采用的是一种尽力而为(Best-Effort)的传送数据的方式,它只是把数据的目的地记录在数据报包(DatagramPacket)中,然后就直接放在网络上,系统不保证数据是否能安全送到,或者什么时候可以送到,也就是说它并不保证传送的质量。UDP在每一个自寻址包中包含了错误检测信息,在每个自寻址包到达目的地之后UDP进行简单的错误检查,如果检查失败,UDP将抛弃这个自寻址包,也不会从发送者那里重新请求替代者。这与通过邮局发送信件相似,发信人在发信这前不需要与收信人建立连接,同样也不能保证信件能到达发信人那里。
可见,UDP的优点是效率高,并且比较灵活,一般用于质量和实时性要求不是很高的情况,比如实时音频和视频应用中。
DatagramSocket本身只是码头,不维护状态,不能产生I/O流,它的唯一作用就是接收和发送数据报包,这个数据报包在Java中是使用DatagramPacket对象实现的。
数据报套接字编程中主要使用下面三个类:DatagramPacket 、DatagramSocket和MulticastSocket。
- DatagramPacket对象描绘了自寻址包的地址信息;
- DatagramSocket表示客户端程序与服务器程序自寻址套接字;
- MulticastSocket 描绘了能进行多点传送的自寻址套接字。
二 DatagramPacket
2.1 创建DatagramPacket对象
2.1.1 创建的DatagramPacket对象用于接收数据
以一个空数组来创建DatagramPacket对象,该对象的作用是接收DatagramSocket中的数据。
- public DatagramPacket(byte buf[], int length) :接收到的数据从buf[0]开始存放,直到整个数据包接收完毕或者将length的字节写入buf为止。
- public DatagramPacket(byte buf[], int offset, int length):接收到的数据从buf[offset]开始存放,如果数据包长度超出了length,则会触发IllegalArgument-Exception。
不过这是RuntimeException,不需要用户代码捕获。
示范代码如下:
byte[] buffer = new byte[8912];DatagramPacket datap = new DatagramPacket(buffer, buffer.length);
2.1.2 创建的DatagramPacket对象用于发送数据
以一个包含数据的数组 buf[]来创建DatagramPacket对象,该对象作为DatagramSocket发送数据的载体,并指定该DatagramPacket目的IP地址和端口号。
- public DatagramPacket(byte buf[], int length, InetAddress address, int port)
- public DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port)
示范代码是要发送一串字符串:
String string = new String("java networking");byte[] data=string.getBytes();int port=1024;InetAddress inetA=null;try { inetA = InetAddress.getByName("127.0.0.1"); DatagramPacket datap = new DatagramPacket(data,data.length,inetA,port);} catch (UnknownHostException e) {}
2.2 DatagramPacket常用方法
获取DatagramPacket对象属性的方法如下:
- public synchronized InetAddress getAddress()
- public synchronized int getPort()
- public synchronized byte[] getData()
- public synchronized int getLength()
- public synchronized int getOffset()
设置DatagramPacket对象属性的方法如下:
- public synchronized void setAddress(InetAddress iaddr)
- public synchronized void setPort(int iport)
- public synchronized void setData(byte[] buf, int offset, int length)
- public synchronized void setData(byte[] buf)
- public synchronized void setLength(int length)
- public synchronized void setSocketAddress(SocketAddress address)
部分方法说明:
- getAddress()是返回该DatagramPacket的IP地址。如果DatagramPacket是发送出来的数据报包,这个方法则返回目的主机的IP地址。如果DatagramPacket是接收到的数据报包,这个方法则返回远程主机的IP地址。
- getSocketAddress()是返回要将此包发送到的或此数据报包的远程主机的SocketAddress(通常是IP地址+端口号)。
- setAddress()是设置该DatagramPacket要发送往的目的主机的IP地址。
- setSocketAddress()是设置要将此包发送到的或此数据报包的远程主机的SocketAddress(通常是IP地址+端口号)。
三 DatagramSocket
3.1 创建DatagramSocket对象
- public DatagramSocket() throws SocketException :系统随机产生一个端口,创建一个数据报套接字。这种构造方法没有指定端口号,可以用在发送端,如果构造不成功则触发SocketException异常。
- public DatagramSocket(int port) throws SocketException :用一个指定端口号port创建一个数据报套接字。如果指定端口已被占用或者是试图连接低于1024的端口但又没具备权限。
- public DatagramSocket(int port, InetAddress laddr) throws SocketException :创建一个数据报套接字,并将该对象绑定到指定的IP地址和端口。
通常用指定端口的方式创建发送端数据报套接字。一旦得到了DatagramSocket对象之后,就可以通过如下两个方法来接收和发送数据:
- public void send(DatagramPacket p) throws IOException :从该DatagramSocket中接收数据报包。
- public synchronized void receive(DatagramPacket p) throws IOException :使用该DatagramSocket对象向外发送数据报包。
从上面两个方法可以看出,使用DatagramSocket发送数据报包时,DatagramSocket并不知道将该数据报包发送到哪里,而是由DatagramPacket自身决定数据报包的目的地,所有的端口、目的地址和数据,需要由DatagramPacket来指定。就像码头并不知道每个集装箱发送到哪里,码头只是将这些集装箱发送出去,而集装箱本身包含了该集装箱的目的地。
DatagramSocket在接收数据之前,应该采用public DatagramPacket(byte buf[], int length)或public DatagramPacket(byte buf[], int offset, int length)构造方法创建一个DatagramPakcet对象,给出接收数据的字节及其长度。然后调用DatagramSocket的方法receive()等待数据报包的到来,receive()将一直等待(也就是说会阻塞调用该方法的线程),直到收到一个数据报包为止,如下代码所示:
//创建要接收数据的DatagramPacket对象DatagramPacket packet =new DatagramPacket(buf,buf.length);//接收数据receiveSocket.receive(packet);
发送数据之前,调用public DatagramPacket(byte buf[], int length, InetAddress address, int port)或public DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port)构造方法创建DatagramPacket对象,此时的字节数组存放了要发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的方法send()实现的,send()根据数据报包的目的地址来寻径以传递数据报包,如下代码所示:
//创建一个要发送数据的DatagramPacket对象DatagramPacket packet = new DatagramPacket(buf,length,address, port);//发送数据sendSocket.send(packet);
3.2 DatagramSocket常用方法
- public InetAddress getInetAddress()
- public int getPort()
- public InetAddress getLocalAddress()
- public int getLocalPort()
- public SocketAddress getRemoteSocketAddress()
- public SocketAddress getLocalSocketAddress()
- public void send(DatagramPacket p) throws IOException
- public synchronized void receive(DatagramPacket p) throws IOException
四 DatagramSocket编程示例
4.1 利用DatagramSocket查询端口占用情况
package _5_2DatagramSocket编程示例._5_2_1利用DatagramSocket查询端口占用情况;import java.net.DatagramSocket;import java.net.SocketException;/** * * Copyright ? 2016 Authors. All rights reserved. * * FileName: .java * @author : Wu_Being <1040003585@qq.com> * Date/Time: 2016-6-10/上午12:36:45 * Description: 查询端口的占用情 ? */public class UDPScan { /** * @param args */ public static void main(String[] args) { //2014~65535 for (int port = 1024; port < 65536; port++) { try { DatagramSocket server = new DatagramSocket(port); server.close(); } catch (SocketException e) { System.out.println("there is a server in port:" + port + "."); } } }}
4.2 利用数据报通信的C/S程序
4.2.1 数据接收端
package _5_2DatagramSocket编程示例._5_2_2利用数据报通信的CS程序;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketException;/** * * Copyright ? 2016 Authors. All rights reserved. * * FileName: .java * @author : Wu_Being <1040003585@qq.com> * Date/Time: 2016-6-10/下午10:36:26 * Description: */public class UDPReceiver { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { DatagramSocket receiveSocket =new DatagramSocket(5000); byte buf[]=new byte[1000]; DatagramPacket receivepPacket=new DatagramPacket(buf,buf.length); System.out.println("starting to receive packet..."); while(true){ receiveSocket.receive(receivepPacket); String receiveData=new String(receivepPacket.getData(),0,receivepPacket.getLength()); String name=receivepPacket.getAddress().getHostName(); int port=receivepPacket.getPort(); System.out.print("来自主机:"+name); System.out.print(",的端口:"+port); System.out.println("的数据:"+receiveData); } } catch (SocketException e) { System.out.println("不能打开数据报Socket,或数据报Socket无法与指定端口连接"); System.exit(1); } catch (IOException e) { System.out.println("网络通信出现问题,问题在于:"+e.toString()); } }}
4.2.2 数据发送端
package _5_2DatagramSocket编程示例._5_2_2利用数据报通信的CS程序;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;import java.util.Scanner;/** * * Copyright ? 2016 Authors. All rights reserved. * * FileName: .java * * @author : Wu_Being <1040003585@qq.com> Date/Time: 2016-6-10/下午10:36:20 * Description: */public class UDPSender { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub while (true) { Scanner scanner = new Scanner(System.in); try { System.out.print("请输入要发送的数据:"); String string = scanner.nextLine(); DatagramSocket sendSocket = new DatagramSocket();// 端口号随机 // byte[] databyte=new byte[100] byte[] databyte = string.getBytes(); DatagramPacket sentPacket = new DatagramPacket(databyte, databyte.length, InetAddress.getByName("127.0.0.1"), 5000); sendSocket.send(sentPacket); System.out.println("send the data:" + string); } catch (SocketException e) { System.out.println("不能打开数据报Socket,或数据报Socket无法与指定端口连接"); } catch (IOException e) { System.out.println("网络通信出现问题,问题在于:" + e.toString()); } } }}
4.3 用UDP实现的聊天程序
package _5_2DatagramSocket编程示例._5_2_3用UDP实现的聊天程序;import java.awt.BorderLayout;import java.awt.Container;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.SocketException;import java.net.UnknownHostException;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;public class UDPChat implements ActionListener, Runnable { JTextArea showArea; JLabel lbl1, lbl2, lbl3; JTextField msgTextField, sendPortTextField, receivePorttTextField, IPAddressTextField; JFrame mainFrame; JButton sendButton, startButton;//,resetbButton; JScrollPane JSPane; JPanel panel1, panel2; Container container; Thread thread = null; DatagramSocket sendSocket, receiveSocket; DatagramPacket sendPacket, receivePacket; private InetAddress sendIP; private int sendPort, receivePort;// 存储发送端口和接收端口 private byte inbuf[], outbuf[]; public static final int BUFSIZE = 1024; public UDPChat() { mainFrame = new JFrame("聊天——UDP协议"); container = mainFrame.getContentPane(); showArea = new JTextArea(); showArea.setEditable(false); showArea.setLineWrap(true); lbl1 = new JLabel("接收端口号:"); lbl2 = new JLabel("发送端口号:"); lbl3 = new JLabel("对方的地址:"); sendPortTextField = new JTextField(); sendPortTextField.setColumns(4); receivePorttTextField = new JTextField(); receivePorttTextField.setColumns(4); IPAddressTextField = new JTextField(); IPAddressTextField.setColumns(8); startButton = new JButton("开始"); startButton.addActionListener(this);/**/// resetbButton=new JButton("重置");// resetbButton.addActionListener(this);/**/ panel1 = new JPanel(); panel1.setLayout(new FlowLayout()); panel1.add(lbl1); panel1.add(receivePorttTextField); panel1.add(lbl2); panel1.add(sendPortTextField); panel1.add(lbl3); panel1.add(IPAddressTextField); panel1.add(startButton);// panel1.add(resetbButton); JSPane = new JScrollPane(showArea); msgTextField = new JTextField(); msgTextField.setColumns(40); msgTextField.setEditable(false); msgTextField.addActionListener(this);/**/ sendButton = new JButton("发送"); sendButton.setEnabled(false); sendButton.addActionListener(this);/**/ panel2 = new JPanel(); panel2.setLayout(new FlowLayout()); panel2.add(msgTextField); panel2.add(sendButton); container.add(panel1, BorderLayout.NORTH); container.add(JSPane, BorderLayout.CENTER); container.add(panel2, BorderLayout.SOUTH); mainFrame.setSize(600, 400); mainFrame.setVisible(true); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void actionPerformed(ActionEvent e) { try { if (e.getSource() == startButton) {/* 按下了开始按键 */ inbuf = new byte[BUFSIZE]; receivePort = Integer.parseInt(receivePorttTextField.getText()); sendPort = Integer.parseInt(sendPortTextField.getText()); sendIP = InetAddress.getByName(IPAddressTextField.getText()); //创建发送和接收DatagramSocket和DatagramPacket sendSocket = new DatagramSocket(); receiveSocket = new DatagramSocket(receivePort); receivePacket = new DatagramPacket(inbuf, BUFSIZE); thread = new Thread(this); thread.setPriority(Thread.MIN_PRIORITY); thread.start(); startButton.setEnabled(false); sendButton.setEnabled(true); msgTextField.setEditable(true);// } else if (e.getSource() == resetbButton) {// // sendPortTextField.setText(null);// receivePorttTextField.setText(null);// IPAddressTextField.setText(null);// msgTextField.setText(null);// showArea.setText(null);// // startButton.setEnabled(true);// sendButton.setEnabled(false);// msgTextField.setEditable(false);// // thread.interrupt();// if(receivePacket!=null) {// receiveSocket.close();// } } else {/* 按下了发送按键或回车键 */ outbuf = msgTextField.getText().getBytes(); // 组装要发送的的数据包 sendPacket = new DatagramPacket(outbuf, outbuf.length, sendIP, sendPort); // 发送数据 sendSocket.send(sendPacket); showArea.append("我说(" + msgTextField.getText() + ")" + getDateTime() + "\n"); msgTextField.setText(null); } } catch (UnknownHostException e1) { showArea.append("getByName无法连接到指定地址!!!" + getDateTime() + "\n"); } catch (SocketException e1) { showArea.append("DatagramSocket无法打开指定端口!!!" + getDateTime() + "\n"); } catch (IOException e1) { showArea.append("send数据数据失败!!!" + getDateTime() + "\n"); } catch (NumberFormatException e1) { showArea.append("设置端口数据格式不对!!!" + getDateTime() + "\n"); } } @Override public void run() { String msgstr; while (true) { try {// 注意try的位置 receiveSocket.receive(receivePacket); msgstr = new String(receivePacket.getData(), 0, receivePacket.getLength()); showArea.append("对方说(" + msgstr + ")" + getDateTime() + "\n"); } catch (Exception e) { showArea.append("receive接收数据出错!!!" + getDateTime() + "\n"); } } } public static void main(String[] args) { new UDPChat(); } /** * Java代码中获得当前时间 * * @return 当前时期时间 */ private String getDateTime() { Date date = new Date(); DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = format.format(date); return time; }}
文中所有源代码链接
Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!
《Java数据报套接字》:
http://blog.csdn.net/u014134180/article/details/51636009
如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
- 返回到目录 ↩
- 【网络编程2】Java数据报套接字
- Java套接字实现网络编程之基础篇2
- JAVA网络编程 Datagram套接字
- JAVA网络编程 Datagram套接字
- java基础之网络套接字编程
- 【网络编程1】Java套接字Socket
- JAVA021 -- java网络编程之套接字
- Java网络编程-(1)套接字
- java网络编程--socket套接字
- 网络套接字编程
- 数据报(UDP)套接字客户端/服务器编程
- UDP(用户数据报协议)和套接字编程
- [java]网络编程(Socket编程、套接字编程)
- java编程_socket_套接字_网络编程
- java编程_socket_套接字_网络编程
- java编程_socket_套接字_网络编程
- Java编程思想之网络编程(二)套接字Socket
- Java网络编程之套接字(Socket编程)
- QtQuick 全局缩放和放大<DPI>
- Jump to Section Overview Usage Floating Action Icons Design Support Library Animating the Floating A
- Delete files or directories in bash shell
- ViewPager简单实现分析
- 为什么基于DNS的全局负载均衡(GSLB)不起作用?
- 【网络编程2】Java数据报套接字
- R语言︱线性混合模型理论与案例探究(固定效应&随机效应)
- leetcode-Ugly Number(丑数)
- 【Windows】教你一步一步在Windows 7 系统上开启Telnet服务
- Xcode各版本官方下载及百度云盘下载, Mac和IOS及Xcode版本历史.
- UVa 1347 Tour
- Android学习笔记之SimpleAdapter
- orcale 忘记密码
- 在ubuntu14.04.1中将qt4.8.6移植到基于hi3520d的nvr上