本文主要是介绍黑马程序员-JAVA.net-网络工具类粗解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
Java自1.0就已集成网络操作的工具,提供了从基于流的Java.net包以实现网络访问和操作,而Java1.4又假如了nio包,利用异步和面向缓冲的新方式实现了更高效的网络操作工具类,并以此重写了部分io包中的内容。
Java.net
java.net 包可以大致分为两个部分:
- 低级 API,用于处理以下抽象:
- 地址,也就是网络标识符,如 IP 地址。
- 套接字,也就是基本双向数据通信机制。
- 接口,用于描述网络接口。
- 高级 API,用于处理以下抽象:
- URI,表示统一资源标识符。
- URL,表示统一资源定位符。
- 连接,表示到 URL 所指向资源的连接。
地址
InetAddress 类是表示 IP(Internet 协议)地址的抽象。它拥有两个子类:
- 用于 IPv4 地址的 Inet4Address。
- 用于 IPv6 地址的 Inet6Address。
IP 地址是 IP 使用的4个byte(IPv4)或者16个byte(IPv6);对于Hostname,将通过主机名解析服务(通常是DNS)将他解析为IP地址。
ipv6
并非所有系统和网络环境都支持 IPv6 协议,在 IPv6 不可用或被显式禁用的情况下,在此情况下,大多数方法在使用 Inet6Address 调用时都将抛出异常。
简单的创建InetAddress 的例子
try {InetAddress ip = null;//localhostip = Inet4Address.getLocalHost();sp(ip);//xxxx-xxxx/192.168.1.100 for example//loopbackip= Inet4Address.getLoopbackAddress();sp(ip);//localhost/127.0.0.1 //Indicate a ip & hostname without NSip=Inet4Address.getByAddress("Its.A.Fake.Domian", new byte[]{(byte) 0xfe,(byte) 0xfe,(byte) 0xfe,(byte) 0xfe});sp(ip);//Its.A.Fake.Domian/254.254.254.254//Indicate a ip with 4bytes for ipv4ip=Inet4Address.getByAddress(new byte[]{(byte) 0xfe,(byte) 0xfe,(byte) 0xfe,(byte) 0xfe});sp(ip);///254.254.254.254//Indicate a ip for hostname using NSip=Inet4Address.getByName("www.oracle.com");sp(ip);//www.oracle.com/184.50.90.127} catch (UnknownHostException e) {e.printStackTrace();}
套接字
套接字是实际操作传输层的Java工具对象,基于UDP和TCP的传输都可以通过构建套接字来完成。
端口
端口是TCP和UDP协议中对同一IP地址不同应用对象的区分手段,TCP与UDP的端口是互不影响的。
UDP与DatagramSocket
UDP:User Datagram Protocol是一种面向无连接,基于数据包的传输层协议,一个UDP数据包最大为65535bytes。但是UDP不含任何传输保证,数据的有效性必须由应用自行处理,但相对于TCP,它的连接开销小,相对速度快,很多协议也是基于UDP的,比如很重要的DNS(UDP53)协议,DHCP(UDP67/68)协议;另外很多协议同时支持TCP以及UDP以实现更好的数据交换。
DatagramSocket是Java中处理UDP点对点传输的网络端点对象。通过传输DatagramPacket网络包实现UDP协议的传输。将DatagramPacket目标指定为广播地址可以实现域内网络多播。
DatagramSocket的构造方法允许指定端口,当绑定端口失败时会抛出SocketException;若不指定,将由JVM随机安排一个可用的端口。
由于端口属于系统资源,必须保证端口在使用完后通过close()方法释放。
MulticastSocket
UDP的组播,多播组通过 D 类 IP 地址和标准 UDP 端口号指定,通过joinGroup(group)加入组,将消息发送到多播组时,该主机和端口的所有预定接收者都将接收到消息,多个 MulticastSocket 可以同时预定多播组和端口,并且都会接收到组数据报。
UDP的简单例子
一个简单的控制台通过本地环回的UDP信息收发
final int port = 36314;try {UdpReciver serv = new UdpReciver(port);StringUdpSender cli=new StringUdpSender(port);new Thread(serv).start();new Thread(cli).start();ts(10000);serv.stop();} catch (IOException e) {e.printStackTrace();}
class StringUdpSender implements Runnable {private DatagramSocket soc;private final String exitFlag;private final int port;public StringUdpSender(int port,String exitFlag) throws SocketException {super();this.exitFlag = exitFlag;soc=new DatagramSocket();this.port=port;}public StringUdpSender(int port) throws SocketException {this(port,"exit");}@Overridepublic void run() {String msg=null;BufferedReader br= new BufferedReader(new InputStreamReader(System.in));DatagramPacket dp=null;while(true){try {msg=br.readLine();if(!exitFlag.equals(msg)){dp=new DatagramPacket(msg.getBytes(), msg.getBytes().length, InetAddress.getByName("localhost"), port);soc.send(dp);}else{break;}} catch (IOException e) {e.printStackTrace();}}if (soc != null && !soc.isClosed()) {soc.close();}}}class UdpReciver implements Runnable {private DatagramSocket soc;private volatile boolean runFlag = false;public UdpReciver(int port) throws SocketException {super();this.soc = new DatagramSocket(port);}public void stop() {this.setRunFlag(false);}public boolean isRunning() {return runFlag;}private synchronized void setRunFlag(boolean runFlag) {this.runFlag = runFlag;}@Overridepublic void run() {this.setRunFlag(true);DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);while (runFlag) {try {this.soc.receive(dp);} catch (IOException e) {e.printStackTrace();}sp(dp.getAddress());sp(new String(dp.getData(),0,dp.getLength()));}if (soc != null && !soc.isClosed()) {soc.close();sp("Server stop");}}@Overrideprotected void finalize() throws Throwable {super.finalize();if (soc != null && !soc.isClosed()) {soc.close();}}
}
TCP
TCP(Transfer Control Protocol)是面向连接的,相对可靠的数据传输协议,TCP的双方必须经过3次握手来达成一个连接,有了连接之后才能开始传输数据,TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和,一旦有问题将请求重发,包丢失也将请求重发,而重复的包将丢弃。这样TCP就达成了一个可靠的数据传送。
TCP的连接时有状态的,双方通过协议信号更新彼此的状态,常见的服务端LISTEN表示监听中,任一方ESTABLISHED 表示连接已建立等。
Socket
Socket是Java中TCP端点的抽象,套接字的实际工作由 SocketImpl 类的实例执行。
客户端可以通过构造一个包含服务器IP和端口的Socket尝试打开TCP连接。
打开连接之后,可以通过getInputStream和getOutputStream与对端通信。
ServerSocket
ServerSocket是Java中TCP服务端的抽象,绑定一个端口即可开始服务。服务器套接字的实际工作由 SocketImpl 类的实例执行。
ServerSocket通过accept() 阻塞方法获得客户端的连接,然后可以操作这个连接来处理交互。
TCP服务器和客户端的简单例子
这个例子实现了简单的TCP服务器和客户端,服务器对客户端送来的String简单的+上”response”返回客户端,服务端实现了简单的异步消息和连接统计。
public class TcpDemo {public static void main(String[] args) {final int serverPort = 23333;InetAddress serverAddr = null;try {serverAddr = InetAddress.getLocalHost();} catch (UnknownHostException e1) {e1.printStackTrace();}//start Servertry {new Thread(new TcpServer(serverPort)).start();} catch (IOException e1) {e1.printStackTrace();}//start ClientSocket s = null;//5 thread client
// for (int i = 0; i < 5; i++) {
// try {
// s = new Socket(serverAddr, serverPort);
// } catch (IOException e) {
// e.printStackTrace();
// }
// new Thread(new TcpClient(s)).start();
// }//about 400 thread clientwhile(true){ts(10);try {s = new Socket(serverAddr, serverPort);} catch (IOException e) {e.printStackTrace();}new Thread(new TcpClient(s)).start();}}}class TcpClient implements Runnable {//end connection key wordpublic static final String ENDCONN="##$$$$##";Socket socket;public TcpClient(Socket socket) {super();this.socket = socket;}@Overridepublic void run() {
// sp(socket+" Client");//client request//emulate chatRandom r=new Random();int times=r.nextInt(20)+5;PrintWriter pw=null;BufferedReader bfr=null;try {pw = new PrintWriter(socket.getOutputStream());bfr=new BufferedReader(new InputStreamReader(socket.getInputStream()));} catch (IOException e1) {e1.printStackTrace();}for (int i = 0; i < times; i++) {String msg = "hello from"+socket.getLocalPort()+"##"+i;pw.println(msg);pw.flush();try {msg=bfr.readLine();} catch (IOException e) {e.printStackTrace();}
// sp(msg);ts(300);}pw.println(TcpClient.ENDCONN);pw.flush();
// if(socket!=null && !socket.isClosed()){
// try {
// socket.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }}}class TcpServer implements Runnable {private ServerSocket s;private ExecutorService exes;private final BlockingQueue<Socket> connects;private volatile ConcurrentHashMap<String, Future<String>> results;public TcpServer(int port) throws IOException {super();this.s = new ServerSocket(port);this.exes = Executors.newCachedThreadPool();this.connects = new SynchronousQueue<Socket>();this.results = new ConcurrentHashMap<String, Future<String>>();}@Overridepublic void run() {// Dispatcher threadnew Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Socket s = connects.take();String stamp = s.toString() + Instant.now().toString();Future<String> result = exes.submit(new RequestHandler(s));results.put(stamp, result);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();// Result collector threadnew Thread(new Runnable() {@Overridepublic void run() {while (true) {ts(1000);List<String> remove=new ArrayList<String>();results.forEach((String stamp,Future<String> result) -> {if(result.isDone()){try {
// sp(result.get());remove.add(stamp);} catch (Exception e) {e.printStackTrace();}}else if(result.isCancelled()){
// sp(stamp+" is Cancelled");remove.add(stamp);}});for (String string : remove) {results.remove(string);}sp("Missions : "+results.size());}}}).start();//Serv to Clientwhile (true) {try {final Socket socket = s.accept();try {this.connects.put(socket);} catch (InterruptedException e) {e.printStackTrace();}} catch (IOException e) {e.printStackTrace();}}}}class RequestHandler implements Callable<String> {private Socket socket;public RequestHandler(Socket conn) {super();this.socket = conn;}@Overridepublic String call() throws Exception {//server BusinessPrintWriter pw=null;BufferedReader bfr=null;String msg=null;try {pw = new PrintWriter(socket.getOutputStream());bfr=new BufferedReader(new InputStreamReader(socket.getInputStream()));} catch (IOException e1) {e1.printStackTrace();}while(true){msg=bfr.readLine();if(TcpClient.ENDCONN.equals(msg)){
// sp(this+" recieved ENDCONN");break;}
// sp(msg);pw.println(msg+" : responsed");pw.flush();}socket.close();return "done :"+socket;}}
网络接口
NetworkInterface 实际指的是网络设备,包括硬件和软件模拟的,比如本地网络环回(lo)就是一个操作系统虚拟的网络设备。
NetworkInterface类提供Java访问本地NetworkInterface的工具,通过它,可以查询比如MAC地址,接口是否物理/虚拟,当前传输MTU值等等有价值的硬件信息,它还有一个很便捷的方法NetworkInterface getByInetAddress(InetAddress addr):可以查询绑定了指定IP地址的网络接口。
高级 API
URI
Uniform Resource Identifier 统一资源标识符,是表示一个网络中资源的标识字符串,这种标识指定了某种协议以便使用者通过合适的方式使用。
URI由URL(地址)和URN(名称)组成,常见的URI有不透明URI和分层URI
比如mailto:java-net@java.sun.com urn:isbn:096139210x
就是不透明URI,其特点是方案定义部分不以’/’开始,其结构可以表示为:[scheme:]scheme-specific-part[#fragment]
而更常见的是分层URI,http://java.sun.com/j2se/1.3/ docs/guide/collections/designfaq.html#28 ../../../demo/jfc/SwingSet2/src/SwingSet2.java
等都是分层URI,分层 URI 还要按照下面的语法进行进一步的解析:[scheme:][//authority][path][?query][#fragment]
Java.net中的URI类提供了构造和解析URI的方便工具,可以通过字符串解析URI的各个部分,也可以通过已有URI构建新的URI。最后,可以把从URI提取URL来使用,这也是最常用的。
URL
Uniform Resource Location 统一资源定位符 ,它是指向互联网“资源”的指针。URL是URI的定位部分,他们之间可以用toURI() 和toURL() 方法相互转换 。
URL 可选择指定一个“端口”,它是用于建立到远程主机 TCP 连接的端口号。如果未指定该端口号,则使用协议默认的端口。例如,http 协议的默认端口为 80。还可以指定一个备用端口,用.au:端口号
Java.net中的URL类除了像URI一样可以解析和构造(解析和构造也可以使用URLDecoder和URLEncoder)以外,特别的,它提供了一个极其方便的方法 openConnection()返回一个URLConnection对象,这个方法通过反射查询当前jre支持的协议,如果支持就打开一个协议连接,然后就可以直接操作了。
URLConnection
这里是一个打开HttpURLConnection的例子:
URL url=new URL("http://www.java.com");URLConnection conn=url.openConnection();BufferedReader bfr=new BufferedReader(new InputStreamReader(conn.getInputStream()));String str;while((str=bfr.readLine())!=null){sp(str);}
协议处理程序
Java中不仅可以直接使用系统的协议处理程序打开连接,也可以自定义协议处理程序,只需要继承URLStreamHandler抽象类即可。
Java.nio 中的网络相关
@Since Java 1.4
Java1.4中加入了新的IO体系(JSR 51),包括面向缓冲区的各种Buffer对象,双向连接的Channel,Selector模式的多路复用。
在Java1.7中,nio又得到了补充(JSR 203),包括更多的文件系统操作API(包括可插拔的自定义的文件系统), 还提供了对socket和文件的异步(Async) I/O操作。
用Async方法实现异步网络服务
下面是一个基于异步非阻塞模式的服务器简单例子,双方仅仅是简单的进行几十次字符串传递即关闭连接。
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.*;import static cc.sisel.util.Quic.*;/*** @author lz**/
public class AsyncTcpDemo {public static void main(String[] args) throws IOException,InterruptedException, ExecutionException {timeMark();InetSocketAddress servAddr = new InetSocketAddress("localhost", 22333);// start servernew Thread(new Runnable() {@Overridepublic void run() {new AsyncServer(servAddr.getPort(), 100).start();// blocking server main thread to keep async alivewhile (true) {try {Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();// wait server initts(300);Random r = new Random();// 5000 clientsfor (int i = 0; i < 5000; i++) {ts(10);new Thread(new AsyncClient(servAddr, r.nextInt(50) + 10)).start();}sp("ALL DONE");}}class AsyncServer {private AsynchronousServerSocketChannel servsc;private final int port, backlog;private boolean started;public AsyncServer(int port, int backlog) {super();this.port = port;this.backlog = backlog;init();}public void start() {// start by accept a connection channelservsc.accept(null, new AcceptCompletionHandler());this.started = true;}private void init() {// build async groupAsynchronousChannelGroup asyncGroup = null;try {// async thread poolasyncGroup = AsynchronousChannelGroup.withCachedThreadPool(Executors.newCachedThreadPool(), 10);} catch (IOException e) {e.printStackTrace();}// open serversockettry {this.servsc = AsynchronousServerSocketChannel.open(asyncGroup);} catch (IOException e) {e.printStackTrace();}// config addr resuse & tcp recieve buffertry {this.servsc.setOption(StandardSocketOptions.SO_REUSEADDR, true);this.servsc.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);} catch (IOException e) {e.printStackTrace();}// bind to port ;ip= 0.0.0.0 for everyonetry {this.servsc.bind(new InetSocketAddress("0.0.0.0", this.port),this.backlog);} catch (IOException e) {e.printStackTrace();}}public void pendingAccept() {// after accepted channel reaccept cycliclyif (this.started && this.servsc.isOpen()) {servsc.accept(null, new AcceptCompletionHandler());} else {throw new IllegalStateException("Controller has been closed");}}// accept complete event handlerclass AcceptCompletionHandler implementsCompletionHandler<AsynchronousSocketChannel, Object> {final ByteBuffer buffer = ByteBuffer.allocate(1024);@Overridepublic void completed(AsynchronousSocketChannel channel,Object attachment) {new ASession(channel, AsyncServer.this).start();}@Overridepublic void failed(Throwable exc, Object attachment) {System.out.println("failed: " + exc);pendingAccept();}}}/*** server session handle it's read & write* * @author lz**/
class ASession {private AsynchronousSocketChannel channel;private AsyncServer server;private final ByteBuffer buffer = ByteBuffer.allocate(1024);private WriteCompletionHandler writeh;private ReadCompletionHandler readh;public ASession(AsynchronousSocketChannel channel, AsyncServer server) {this.channel = channel;this.writeh = new WriteCompletionHandler();this.readh = new ReadCompletionHandler();this.server = server;}public void start() {channel.read(buffer, null, readh);}class WriteCompletionHandler implements CompletionHandler<Integer, Object> {@Overridepublic void completed(Integer result, Object attachment) {if (channel.isOpen()) {buffer.clear();channel.read(buffer, 20, TimeUnit.SECONDS, null, readh);}}@Overridepublic void failed(Throwable exc, Object attachment) {sp("########################## WRITE FAIL IN SERVER");exc.printStackTrace();}}class ReadCompletionHandler implements CompletionHandler<Integer, Object> {@Overridepublic void completed(Integer result, Object attachment) {buffer.flip();String msg = readBuffer(buffer);// sp("server recieved:" + msg);buffer.clear();// if ENDCODE then close session and pending server nextif (AsyncClient.ENDCODE.equals(msg)) {if (channel.isOpen()) {try {channel.close();} catch (IOException e) {e.printStackTrace();}}server.pendingAccept();} else {// write responseif (channel != null && channel.isOpen()) {channel.write(ByteBuffer.wrap((msg + " responsed.").getBytes()),10, TimeUnit.SECONDS, null, writeh);}}}@Overridepublic void failed(Throwable exc, Object attachment) {sp("########################## READ FAIL IN SERVER");exc.printStackTrace();}}
}/*** client emualtor send simple message & recieve* * @author lz**/
class AsyncClient implements Runnable {public static final String ENDCODE = "&#$$#&$$";private final InetSocketAddress serverAddr;private int chatCount;private AsynchronousSocketChannel client = null;private final ByteBuffer buffer = ByteBuffer.allocate(1024);// event handlesprivate ConnectCompletionHandler connecth;private WriteCompletionHandler writeh;private ReadCompletionHandler readh;private NullCompletionHandler endh;public AsyncClient(InetSocketAddress serverAddr, int chatCount) {super();this.serverAddr = serverAddr;this.chatCount = chatCount < 1 ? 1 : chatCount;this.connecth = new ConnectCompletionHandler();this.writeh = new WriteCompletionHandler();this.readh = new ReadCompletionHandler();this.endh = new NullCompletionHandler();}@Overridepublic void run() {try {client = AsynchronousSocketChannel.open();} catch (IOException e) {e.printStackTrace();}// launch connif (client != null && client.isOpen()) {client.connect(serverAddr, null, connecth);}}class ConnectCompletionHandler implements CompletionHandler<Void, Object> {@Overridepublic void completed(Void result, Object attachment) {buffer.clear();if (chatCount > 0) {ts(300);if (client.isOpen()) {client.write(ByteBuffer.wrap(("message:" + chatCount).getBytes()), 10, TimeUnit.SECONDS, null, writeh);chatCount--;}} else {if (client.isOpen()) {client.write(ByteBuffer.wrap(ENDCODE.getBytes()), 10,TimeUnit.SECONDS, null, endh);}}}@Overridepublic void failed(Throwable exc, Object attachment) {sp("########################## CONNECT FAIL IN CLIENT");ts(300);client.connect(serverAddr, null, connecth);exc.printStackTrace();}}class WriteCompletionHandler implements CompletionHandler<Integer, Object> {@Overridepublic void completed(Integer result, Object attachment) {if (client.isOpen()) {buffer.clear();client.read(buffer, 20, TimeUnit.SECONDS, null, readh);}}@Overridepublic void failed(Throwable exc, Object attachment) {sp("########################## WRITE FAIL IN CLIENT");exc.printStackTrace();}}class ReadCompletionHandler implements CompletionHandler<Integer, Object> {@Overridepublic void completed(Integer result, Object attachment) {if (client.isOpen()) {buffer.flip();String msg = readBuffer(buffer);// sp("client recieved :" + msg);buffer.clear();if (chatCount > 0) {// ts(300);client.write(ByteBuffer.wrap(("message:" + chatCount).getBytes()), 10, TimeUnit.SECONDS, null, writeh);chatCount--;} else {client.write(ByteBuffer.wrap(ENDCODE.getBytes()), 10,TimeUnit.SECONDS, null, endh);}}}@Overridepublic void failed(Throwable exc, Object attachment) {sp("########################## READ FAIL IN CLIENT");exc.printStackTrace();}}
}class NullCompletionHandler implements CompletionHandler<Integer, Object> {@Overridepublic void completed(Integer result, Object attachment) {//just do nothing}@Overridepublic void failed(Throwable exc, Object attachment) {//just do nothing}}
附:
- sp和ts方法,偷懒用:
/*** 简单的在控制台输出 对于非数组类型,输出.toString() 对于数组类型,输出:类型[内容] 不递归* * @param o* 被打印的对象*/public static void sp(Object o) {if (o == null) {System.out.println("null");return;}if (o.getClass().isArray()) {StringBuilder sb = new StringBuilder();int len = Array.getLength(o);sb.append(o.getClass().getComponentType().getSimpleName());if (len == 0) {sb.append("[]");System.out.println(sb.toString());return;}sb.append('[');for (int i = 0; i < len; i++) {if (i != 0) {sb.append(':');}sb.append(Array.get(o, i));}sb.append(']');System.out.println(sb.toString());} else {System.out.println(o);}}/*** 简单的换行 调用sp("");*/public static void sp() {sp("");}/*** !!仅用于test 或者 demo 简单的包装了Thread.sleep(millis); 并catch* (InterruptedException e)不作任何处理* * @param millis 毫秒数* @see java.lang.Thread#sleep(long millis)*/public static void ts(long millis) {if(millis<0){return;}try {Thread.sleep(millis);} catch (InterruptedException e) {e.printStackTrace();}}
这篇关于黑马程序员-JAVA.net-网络工具类粗解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!