网络编程java
网络通讯协议分层思想编程
为何要分层呢?由于整个网络协议很是复杂,要涉及到方方面面的知识,并且还有对底层硬件的操做,利用分层的思想,咱们能够将复杂的通讯协议分割成一层层的形式,上一层能够调用下一层,而与再下一层不发生关系,各层之间互不影响,便于系统的开发。咱们把用户程序做为最高层,把物理通讯线路做为最底层,高层到底层一步步封装,咱们不须要直接操做底层,而是操做最简单的最高层,这就是分层的意义。服务器
参考模型网络
物理层、数据链路层、网络层、传输层、会话层、表示层、应用层socket
应用层、传输层(TCP/UDP层)、网络层(IP层)、数据链路层、物理层.net
咱们今天要讲的主要是传输层。3d
IP协议code
IP层:给咱们作的最大贡献就是提供了独一无二的IP地址。server
IP TCP UDP 网关 内网 子网掩码对象
UDP是User Datagram Protocol的简称,是一种无链接的协议。UDP是从一台计算机向另外一台计算机发送称为数据报的独立数据包的协议,该协议并不保证数据报是否能正确地到达目的地,它是一个非面向链接的协议。每一个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,所以可否到达目的地,到达时间以及内容的正确性都是不能保证的。
端口:用于区分不一样的网络应用程序 ,占两个字节,因此共有 65535 个端口号。不过系统会随时征用 1024 如下端口。
端口又分TCP和UDP端口,各有 65535 个端口。
TCP Socket 通讯模型
示例1:最简单的Socket模型:Client写数据务器读数据
// Server import java.net.*; import java.io.*; public class Server { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(6666); // 已经开始监听6666端口了 while(true) { Socket s = ss.accept(); // ss创建一个插座Socket,接受和客户端s的链接(阻塞式链接),链接成功,至关于服务器和客户端之间链接了两根管道。读的管道(InputStream)和写的管道(OutputStream)。 System.out.println("A Client has Connected!"); DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF());// 因此先获取管道,要说就获取写的管道,要听就获取读的管道。 dis.close(); s.close(); } } } // Client import java.net.*; import java.io.*; public class Client { public static void main(String[] args) throws Exception { Socket s = new Socket("127.0.0.1", 6666);// 申请和ss创建链接 DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeUTF("Hello TCP."); // 链接好以后开始说话,经过管道流的方式来讲话,因此先获取管道,要说就获取写的管道,要听就获取读的管道。 dos.flush(); dos.close(); s.close(); } }
Client 端的 IP 地址不能随意指定,不知为什么。
示例2:服务器向客户端发送数据,客户端接收数据
// Server import java.net.*; import java.io.*; public class Server { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(6666); while(true) { Socket s = ss.accept(); System.out.println("A Client has Connected!"); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I'm Server."); dos.close(); s.close(); } } catch (IOException e) { System.out.println("Server Error!!!"); e.printStackTrace(); } } } // Client import java.net.*; import java.io.*; public class Client { public static void main(String[] args) { try { Socket s = new Socket("127.0.0.1", 6666); DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF()); dis.close(); s.close(); } catch(IOException e) { System.out.println("Client Error!!!"); e.printStackTrace(); } } } //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15944], I'm Server. //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15953], I'm Server. //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15954], I'm Server. //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15955], I'm Server.
示例3:服务器和客户端同时读写数据(固然一个先读一个先写喽,若是两个都读或都写的话就卡死啦)
// Server // 服务器先接收客户端的数据,而后再发送数据给客户端 import java.net.*; import java.io.*; public class Server { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(6666); Socket s = ss.accept(); System.out.println("A Client has Connected!"); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); String str = null; if((str=dis.readUTF()) != null) { System.out.println("I'm reseaving message..."); Thread.sleep(3000); dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I hava reseaved: " + str); } dis.close(); dos.close(); s.close(); } catch (IOException e) { System.out.println("Server Error!!!"); e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } // Client // 客户端先发送数据给服务器,再接收服务器的回复。 import java.net.*; import java.io.*; public class Client { public static void main(String[] args) { try { Socket s = new Socket("localhost", 6666); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); System.out.println("Hi Server, I'm sending message to you..."); Thread.sleep(2000); dos.writeUTF("Hello HYJ."); System.out.println(dis.readUTF()); dis.close(); s.close(); } catch(UnknownHostException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
注意:这里面使用的是 Socket s = new Socket("localhost", 6666);
最后要 catch(UnknownHostException e),UnknownHostException 小于 IOException 因此要放前面。
UDP 通讯模型
示例:
// UDPServer 接收并打印来自客户端的数据 import java.net.*; import java.io.*; public class UDPServer { public static void main(String[] args) { try { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); DatagramSocket ds = new DatagramSocket(8888); while(true) { ds.receive(dp); //ByteArrayInputStream bais = new ByteArrayInputStream(buf); //DataInputStream dis = new DataInputStream(bais); //System.out.println("UDPClient: " + dis.readUTF()); System.out.println("UDPClient: " + new String(buf, 0, dp.getLength())); } } catch (IOException e) { System.out.println("UDPServer Error!!!"); e.printStackTrace(); } } } // UDPClient 发送数据给服务器 import java.net.*; import java.io.*; public class UDPClient { public static void main(String[] args) { try { //ByteArrayOutputStream baos = new ByteArrayOutputStream(); //DataOutputStream dos = new DataOutputStream(baos); //dos.writeUTF("Hello HYJ!"); //dos.flush(); //byte[] buf = baos.toByteArray(); byte[] buf = (new String("Hello HYJ!")).getBytes(); System.out.println("buf.length = " + buf.length); DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress("127.0.0.1", 8888)); DatagramSocket ds = new DatagramSocket(7777); ds.send(dp); ds.close(); } catch(IOException e) { e.printStackTrace(); } } }