黑马程序员-JAVA.net-网络工具类粗解
来源:互联网 发布:手机会议录音软件 编辑:程序博客网 时间:2024/06/01 08:46
——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; //localhost ip = Inet4Address.getLocalHost(); sp(ip);//xxxx-xxxx/192.168.1.100 for example //loopback ip= Inet4Address.getLoopbackAddress(); sp(ip);//localhost/127.0.0.1 //Indicate a ip & hostname without NS ip=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 ipv4 ip=Inet4Address.getByAddress( new byte[]{(byte) 0xfe,(byte) 0xfe,(byte) 0xfe,(byte) 0xfe}); sp(ip);///254.254.254.254 //Indicate a ip for hostname using NS ip=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"); } @Override public 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; } @Override public 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"); } } @Override protected 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 Server try { new Thread(new TcpServer(serverPort)).start(); } catch (IOException e1) { e1.printStackTrace(); } //start Client Socket 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 client while(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 word public static final String ENDCONN="##$$$$##"; Socket socket; public TcpClient(Socket socket) { super(); this.socket = socket; } @Override public void run() {// sp(socket+" Client"); //client request //emulate chat Random 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>>(); } @Override public void run() { // Dispatcher thread new Thread(new Runnable() { @Override public 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 thread new Thread(new Runnable() { @Override public 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 Client while (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; } @Override public String call() throws Exception { //server Business PrintWriter 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 server new Thread(new Runnable() { @Override public void run() { new AsyncServer(servAddr.getPort(), 100).start(); // blocking server main thread to keep async alive while (true) { try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); // wait server init ts(300); Random r = new Random(); // 5000 clients for (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 channel servsc.accept(null, new AcceptCompletionHandler()); this.started = true; } private void init() { // build async group AsynchronousChannelGroup asyncGroup = null; try { // async thread pool asyncGroup = AsynchronousChannelGroup.withCachedThreadPool( Executors.newCachedThreadPool(), 10); } catch (IOException e) { e.printStackTrace(); } // open serversocket try { this.servsc = AsynchronousServerSocketChannel.open(asyncGroup); } catch (IOException e) { e.printStackTrace(); } // config addr resuse & tcp recieve buffer try { 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 everyone try { 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 cyclicly if (this.started && this.servsc.isOpen()) { servsc.accept(null, new AcceptCompletionHandler()); } else { throw new IllegalStateException("Controller has been closed"); } } // accept complete event handler class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Object> { final ByteBuffer buffer = ByteBuffer.allocate(1024); @Override public void completed(AsynchronousSocketChannel channel, Object attachment) { new ASession(channel, AsyncServer.this).start(); } @Override public 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> { @Override public void completed(Integer result, Object attachment) { if (channel.isOpen()) { buffer.clear(); channel.read(buffer, 20, TimeUnit.SECONDS, null, readh); } } @Override public void failed(Throwable exc, Object attachment) { sp("########################## WRITE FAIL IN SERVER"); exc.printStackTrace(); } } class ReadCompletionHandler implements CompletionHandler<Integer, Object> { @Override public 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 next if (AsyncClient.ENDCODE.equals(msg)) { if (channel.isOpen()) { try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } server.pendingAccept(); } else { // write response if (channel != null && channel.isOpen()) { channel.write( ByteBuffer.wrap((msg + " responsed.").getBytes()), 10, TimeUnit.SECONDS, null, writeh); } } } @Override public 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 handles private 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(); } @Override public void run() { try { client = AsynchronousSocketChannel.open(); } catch (IOException e) { e.printStackTrace(); } // launch conn if (client != null && client.isOpen()) { client.connect(serverAddr, null, connecth); } } class ConnectCompletionHandler implements CompletionHandler<Void, Object> { @Override public 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); } } } @Override public 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> { @Override public void completed(Integer result, Object attachment) { if (client.isOpen()) { buffer.clear(); client.read(buffer, 20, TimeUnit.SECONDS, null, readh); } } @Override public void failed(Throwable exc, Object attachment) { sp("########################## WRITE FAIL IN CLIENT"); exc.printStackTrace(); } } class ReadCompletionHandler implements CompletionHandler<Integer, Object> { @Override public 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); } } } @Override public void failed(Throwable exc, Object attachment) { sp("########################## READ FAIL IN CLIENT"); exc.printStackTrace(); } }}class NullCompletionHandler implements CompletionHandler<Integer, Object> { @Override public void completed(Integer result, Object attachment) { //just do nothing } @Override public 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-网络工具类粗解
- 黑马程序员--Java基础--网络编程java.net
- 黑马程序员--java笔记15--网络编程 Java.net
- 黑马程序员 Net
- 黑马程序员_ADO.NET
- 黑马程序员-net快捷键
- 黑马程序员-Ado.Net
- 黑马程序员-ADO.Net
- 黑马程序员-ADO.NET
- 黑马程序员 ADO.net
- 黑马程序员-ADO.net
- 黑马程序员-----ADO.NET
- 黑马程序员--ADO.NET
- 【黑马程序员】ADO.NET
- 黑马程序员--.net字符串
- 黑马程序员--.NET泛型类
- 【黑马程序员】ADO.net
- 黑马程序员《.NET 方法》
- php empty
- 欢迎使用CSDN-markdown编辑器
- SpringMVC学习系列(4) 之 数据绑定-1
- 一、Linux网络编程-TCP/IP基础(一)ISO/OSI参考模型、TCP/IP四层模型、基本概念
- JS 验证身份证及获取地区
- 黑马程序员-JAVA.net-网络工具类粗解
- struts2小技巧总结
- strcpy与memcpy
- 第一次大作业分析【界面篇】
- MySQL · 答疑释惑 · GTID下auto_position=0时数据不一致
- NOJ Palindromes
- apache hive 0.14 beeline 使用注意事项
- 一个小错误
- Struts1.x系列教程(13):国际化