原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。
http://52android.blog.51cto.com/2554429/482954
Java对于网络通讯有着非常强大的支持。不仅可以获取网络资源,传递参数到远程服务器,还可以通过Socket对象实现TCP协议,通过DatagramSocket对象实现UDP协议。同时,对于多点广播以及代理服务器也有着非常强大的支持。以下是本人在学习过程中的总结和归纳。
1. Java的基本网络支持
1.1 InetAddress
Java中的InetAddress是一个代表IP地址的对象。IP地址可以由字节数组和字符串来分别表示,InetAddress将IP地址以对象的形式进行封装,可以更方便的操作和获取其属性。InetAddress没有构造方法,可以通过两个静态方法获得它的对象。代码如下:
|
|
|
2.1 ServerSocket
在两个通信端没有建立虚拟链路之前,必须有一个通信实体首先主动监听来自另一端的请求。ServerSocket对象使用accept()方法用于监听来自客户端的Socket连接,如果收到一个客户端Socket的连接请求,该方法将返回一个与客户端Socket对应的Socket对象。如果没有连接,它将一直处于等待状态。通常情况下,服务器不应只接受一个客户端请求,而应该通过循环调用accept()不断接受来自客户端的所有请求。
这里需要注意的是,对于多次接收客户端数据的情况来说,一方面可以每次都在客户端建立一个新的Socket对象然后通过输入输出通讯,这样对于服务器端来说,每次循环所接收的内容也不一样,被认为是不同的客户端。另外,也可以只建立一次,然后在这个虚拟链路上通信,这样在服务器端一次循环的内容就是通信的全过程。
服务器端的示例代码:
|
2.2 Socket
使用Socket可以主动连接到服务器端,使用服务器的IP地址和端口号初始化之后,服务器端的accept便可以解除阻塞继续向下执行,这样就建立了一对互相连接的Socket。
客户端示例代码:
|
|
|
2.4 使用协议字符
协议字符用于标识一些字段的特定功能,用于说明传输内容的特性。它可以由用户自定义。一般情况下,可以定义一个存放这些协议字符的接口。如下:
|
|
|
3.1 使用DatagramSocket发送、接收数据
DatagramSocket本身并不负责维护状态和产生IO流。它仅仅负责接收和发送数据报。使用receive(DatagramPacket p)方法接收,使用send(DatagramPacket p)方法发送。
这里需要首先明确的是,DatagramPacket对象的构造。DatagramPacket的内部实际上采用了一个字节型数组来保存数据,它的初始化方法如下:
|
3.2 使用MulticastSocket实现多点广播
MulticastSocket是DatagramSocket的子类,可以将数据报以广播形式发送到数量不等的多个客户端。实现策略就是定义一个广播地址,使得每个MulticastSocket都加入到这个地址中。从而每次使用MulticastSocket发送数据报(包含的广播地址)时,所有加入了这个广播地址的MulticastSocket对象都可以收到信息。
MulticastSocket的初始化需要传递端口号作为参数,特别对于需要接受信息的端来说,它的端口号需要与发送端数据报中包含的端口号一致。具体代码如下:
|
|
5. 编码中的问题总结
a. 双方初始化套接字以后,就等于建立了链接,表示双方互相可以知晓对方的状态。服务器端可以调用接收到的客户端套接字进行输入输出流操作,客户端可以调用自身内部的套接字对象进行输入输出操作。这样可以保持输入输出的流畅性。例如,客户端向服务器端发送消息时,可以隔一段的时间输入一段信息,然后服务器端使用循环不断的读取传过来的输入流。
b. 对于可能出现阻塞的方法,例如客户端进行循环不断读取来自服务器端的响应信息时,如果此时服务器端并没有向客户端进行输出,那么读取的方法将处于阻塞状态,直到收到信息为止才向下执行代码。那么对于这样容易产生阻塞的代码,就需要将它放在一个单独的线程中处理。
c. 有一些流是顺承的。例如,服务器端在收到客户端的消息以后,就将消息再通过输出流向其他所有服务器发送。那么,这个来自客户端的输入流和发向客户端的输出流就是顺接的关系,不必对它们分在两个不同的线程。
d. println()方法对应readLine()。
e. 在JFrame类中,一般不要将自己的代码写进main方法中,可以将代码写到自定义的方法中,然后在main方法中调用。
Java中的DatagramPacket与DatagramSocket的初步
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。
http://sunspot.blog.51cto.com/372554/130313
接收方:Getter.java import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketAddress; public class Getter { public static void main(String[] args) { try { //确定接受方的IP和端口号,IP地址为本地机器地址 InetAddress ip = InetAddress.getLocalHost(); int port = 8888; //创建接收方的套接字,并制定端口号和IP地址 DatagramSocket getSocket = new DatagramSocket(port,ip); //确定数据报接受的数据的数组大小 byte[] buf = new byte[1024]; //创建接受类型的数据报,数据将存储在buf中 DatagramPacket getPacket = new DatagramPacket(buf,buf.length); //通过套接字接收数据 getSocket.receive(getPacket); //解析发送方传递的消息,并打印 String getMes = new String(buf,0,getPacket.getLength()); System.out.println("对方发送的消息:"+getMes); //通过数据报得到发送方的IP和端口号,并打印 InetAddress sendIP = getPacket.getAddress(); int sendPort = getPacket.getPort(); System.out.println("对方的IP地址是:"+sendIP.getHostAddress()); System.out.println("对方的端口号是:"+sendPort); //通过数据报得到发送方的套接字地址 SocketAddress sendAddress = getPacket.getSocketAddress(); //确定要反馈发送方的消息内容,并转换为字节数组 String feedback = "接收方说:我收到了!"; byte[] backBuf = feedback.getBytes(); //创建发送类型的数据报 DatagramPacket sendPacket = new DatagramPacket(backBuf,backBuf.length,sendAddress); //通过套接字发送数据 getSocket.send(sendPacket); //关闭套接字 getSocket.close(); } catch (Exception e) { e.printStackTrace(); } } }
发送方: Sender.java import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Sender { public static void main(String[] args) { try { //创建发送方的套接字,IP默认为本地,端口号随机 DatagramSocket sendSocket = new DatagramSocket(); //确定要发送的消息: String mes = "你好!接收方!"; //由于数据报的数据是以字符数组传的形式存储的,所以传转数据 byte[] buf = mes.getBytes(); //确定发送方的IP地址及端口号,地址为本地机器地址 int port = 8888; InetAddress ip = InetAddress.getLocalHost(); //创建发送类型的数据报: DatagramPacket sendPacket = new DatagramPacket(buf,buf.length,ip,port); //通过套接字发送数据: sendSocket.send(sendPacket); //确定接受反馈数据的缓冲存储器,即存储数据的字节数组 byte[] getBuf = new byte[1024]; //创建接受类型的数据报 DatagramPacket getPacket = new DatagramPacket(getBuf,getBuf.length); //通过套接字接受数据 sendSocket.receive(getPacket); //解析反馈的消息,并打印 String backMes = new String(getBuf,0,getPacket.getLength()); System.out.println("接受方返回的消息:"+backMes); //关闭套接字 sendSocket.close(); } catch (Exception e) { e.printStackTrace(); } } }
本文出自 “博远至静” 博客,请务必保留此出处http://sunspot.blog.51cto.com/372554/130313
用java获取本机IP地址
Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); InetAddress ip = null; while (allNetInterfaces.hasMoreElements()) { NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement(); System.out.println(netInterface.getName()); Enumeration addresses = netInterface.getInetAddresses(); while (addresses.hasMoreElements()) { ip = (InetAddress) addresses.nextElement(); if (ip != null && ip instanceof Inet4Address) { System.out.println("本机的IP = " + ip.getHostAddress()); } } }
应用场景: 一个学校,每当下课时间到了提供提示下课功能。
分析:用UDP实现广播向同网段电脑发送数据,客户端接受接受到数据后,弹出提示对话框。服务端需要一个循环来判断时间是否到下课时间,这里如果用死循环,很占系统资源,我测试CUP在100%,用java的Timer类可以很好的解决这个问题,既能保证程序始终运行,又不怎么占系统资源,具体什么原理,没有仔细研究过。下面来看代码具体实现
服务段代码:
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.SimpleDateFormat; import java.util.Date; import java.util.Timer; public class UdpSend { public void sendData()throws SocketException, UnknownHostException{ DatagramSocket ds = new DatagramSocket();// 创建用来发送数据报包的套接字 String str = "1"; DatagramPacket dp = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("255.255.255.255"), 3001); // 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号 try { ds.send(dp); } catch (IOException e) { e.printStackTrace(); } ds.close(); } public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new MyTask(), 1000, 1000); } static class MyTask extends java.util.TimerTask{ @Override public void run() { UdpSend tt = new UdpSend(); Date d = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); String strdate = sdf.format(d); String[] classTime = {"17:18:00","17:19:00","17:20:00"}; for(int i = 0;i<classTime.length;i++){ if(classTime[i].equals(strdate)){ try { tt.sendData(); } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } }
客户单简单代码示例,没有做循环
package udp; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UdpRecv { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(3001);// 创建接收数据报套接字并将其绑定到本地主机上的指定端口 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, 1024); ds.receive(dp); String strRecv = new String(dp.getData(), 0, dp.getLength()) + " from " + dp.getAddress().getHostAddress() + ":" + dp.getPort(); System.out.println(strRecv); ds.close(); } }
http://kkito.cn/index.php/blog/getArticle/183/java%E5%88%A9%E7%94%A8udp%E5%AE%9E%E7%8E%B0%E5%B9%BF%E6%92%AD
在局域网的两台机器上,一台跑server向广播地址的某端口发,一台做客户机监听某端口。
和多播一样向广播地址发实际就是给路由或者交换机发,通过这些设备在局域网里广播。
代码如下:
package cn.kk.socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class BroadCastTest { public static void main(String args[])throws Exception{ //sendBroadcast(); receiveBroadcast(); } public static void sendBroadcast()throws Exception{ DatagramSocket socket; DatagramPacket packet; byte[] data={1,2,3,4}; socket = new DatagramSocket(); socket.setBroadcast(true); //有没有没啥不同 //send端指定接受端的端口,自己的端口是随机的 packet = new DatagramPacket(data,data.length,InetAddress.getByName("255.255.255.255"),8300); for(int i = 0 ; i < 50 ; i++){ Thread.sleep(1000); socket.send(packet); } } public static void receiveBroadcast()throws Exception{ byte[] buffer = new byte[65507]; DatagramSocket server = new DatagramSocket(8300); DatagramPacket packet = new DatagramPacket(buffer , buffer.length); for(;;){ server.receive(packet); String s = new String(packet.getData( ), 0, packet.getLength( )); System.out.println(packet.getAddress( ) + " at port " + packet.getPort( ) + " says " + s); } } }
Java发送广播
package socket; import java.net.*; //导入java.net包 import java.util.Scanner; public class Weather extends Thread { // 创建类。该类为多线程执行程序 int port = 9898; // 定义端口 InetAddress iaddress = null; // 创建InetAddress对象 MulticastSocket socket = null; // 声明多点广播套接字 Weather() { // 构造方法 try { iaddress = InetAddress.getByName("225.225.225.255"); // 实例化InetAddress,指定地址 socket = new MulticastSocket(port); // 实例化多点广播套接字 socket.setTimeToLive(1); // 指定发送范围是本地网络 socket.setBroadcast(true); socket.joinGroup(iaddress); // 加入广播组 } catch (Exception e) { e.printStackTrace(); // 输出异常信息 } } public void run() { // run()方法 Scanner canScanner=new Scanner(System.in); while (true) { DatagramPacket packet = null; // 声明DatagramPacket对象 byte data[] = canScanner.next().getBytes(); // 声明字节数组 packet = new DatagramPacket(data, data.length, iaddress, port); // 将数据打包 try { socket.send(packet); // 发送数据 } catch (Exception e) { e.printStackTrace(); // 输出异常信息 } } } public static void main(String[] args) { // 主方法 Weather w = new Weather(); // 创建本类对象 w.start(); // 启动线程 } }
JAVA实现广播消息DEMO
http://www.oschina.net/code/snippet_147955_4878
package test; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class MulticastSender { private int port; private String host; private String data; public MulticastSender(String data, String host, int port) { this.data = data; this.host = host; this.port = port; } public void send() { try { InetAddress ip = InetAddress.getByName(this.host); DatagramPacket packet = new DatagramPacket(this.data.getBytes(), this.data.length(), ip, this.port); MulticastSocket ms = new MulticastSocket(); ms.send(packet); ms.close(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { int port = 1234; String host = "224.0.0.1"; String data = "hello world."; MulticastSender ms = new MulticastSender(data, host, port); ms.send(); } }
package test; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class MulticastListener { private int port; private String host; public MulticastListener(String host, int port) { this.host = host; this.port = port; } public void listen() { byte[] data = new byte[256]; try { InetAddress ip = InetAddress.getByName(this.host); MulticastSocket ms = new MulticastSocket(this.port); ms.joinGroup(ip); DatagramPacket packet = new DatagramPacket(data, data.length); ms.receive(packet); String message = new String(packet.getData(), 0, packet.getLength()); System.out.println(message); ms.close(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { int port = 1234; String host = "224.0.0.1"; MulticastListener ml = new MulticastListener(host, port); while(true) { ml.listen(); } } }
MulticastSocket类的使用