目录
1.认识网络基本模型
2.基于TCP协议的网络通信
3.基于UDP协议的网络通信
4.基于TCP/IP建立的协议
5.总结
一、网络的基本模型
OSI七层网络模型
应用层:面向用户的个各种协议
表示层:信息语法及之间的关联
会话层:不同机器之间建立
传输层:TCP、IP协议
网络层:路由器
数据链路层:网桥,交换机
物理层:网卡,网线,集线器,中继器,调制解调器
需要详细了解OIS网络模型的请往这走: https://blog.csdn.net/yaopeng_2005/article/details/7064869
TCP/IP模型则是将OIS的模型合并成4层。
下面是OIS与TCP/IP模型的对比图
二、基于TCP协议的网络编程
首先我们要了解一下TCP协议。
TCP协议是一种可靠的网络协议,它需要在通信双方建立socket从而形成网络连接。
在TCP建立连接中经典的三次握手建立连接阶段可以用如下图表示:
有新兴趣的可以往这边走https://blog.csdn.net/whuslei/article/details/6667471
在计算机网络通信中,我们需要找到具体的程序,通常使用ip+端口来寻找的。
ip可以找到我们的计算机,而端口则可以定位到这台计算机的某个程序,端口与进程是没有关联的,端口是用16位表示的
端口号范围 0-65535
接下来我们看一下TCP通信的模型图吧:
套接字:用于主机的IP地址+主机的端口号作为TCP连接的端点,
着这种端点成为套接字。
服务器端:ServerSocket类
客户端:Socket类
废话不多说,我们先来搭建一个服务器端和客户端
package com.demo.tcp; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 服务器端 * @author Administrator * */ public class ServerDemo { private ServerSocket server; private Socket socket; private int port = 8888; //构造函数中初始化服务器 public ServerDemo() { // TODO Auto-generated constructor stub try { //这里利用构造方法初始化服务器,我这里只传了一个参数,所以本机相当于服务器 server = new ServerSocket(port); System.out.println("服务器初始化完成..."); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("服务器初始化失败"); } } //服务器需要做的事 public void server(){ //因为服务器不能关,所以需要写个死循环来监听客户端的链接 while(true){ try { //监听客户端的链接,客户端链接进来程序才会继续执行 socket = server.accept(); System.out.println("客户端:"+socket); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { //启动服务器 new ServerDemo().server(); } }
package com.demo.tcp; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; /** * 客户端 */ public class ClickDemo { private Socket socket; private String host = "localhost"; private int port = 8888; //客户端构造方法里连接服务器 public ClickDemo() { // TODO Auto-generated constructor stub try { //客户端初始化需要设定服务器的ip(由于我这里是在同一台机器上,所以host指定的是本地),port端口需要与服务器的端口一致才能连接上 socket = new Socket(InetAddress.getByName(host), port); System.out.println("链接成功"); } catch (IOException e) { // TODO Auto-generated catch block System.err.println("链接超时"); } } public static void main(String[] args) { //启动客户端 new ClickDemo(); } }
服务器和客户端链接之后都会有一个Socket对象,我们看看官方是怎样解释socket对象的
在我看来,套接字相当于通信的工具,我们可以通过这个通信工具来收发信息
继续查看API可以看到有一个getInputStream和一个getOutputStream方法,这两个方法
则是我们用来收发信息的方法。
接下来我们写一个简单的信息传输实例吧
package com.demo.tcp; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; /** * 客户端 */ public class ClickDemo { private Socket socket; private String host = "localhost"; private int port = 8888; //客户端构造方法里连接服务器 public ClickDemo() { // TODO Auto-generated constructor stub try { //客户端初始化需要设定服务器的ip(由于我这里是在同一台机器上,所以host指定的是本地),port端口需要与服务器的端口一致才能连接上 socket = new Socket(InetAddress.getByName(host), port); System.out.println("链接成功"); } catch (IOException e) { // TODO Auto-generated catch block System.err.println("链接超时"); } } public void send(String context){ try { OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.println(context); pw.flush(); System.out.println("发送成功"); } catch (IOException e) { e.printStackTrace(); System.out.println("发送失败"); } } public static void main(String[] args) { //启动客户端 new ClickDemo().send("HelloWord"); } }
package com.demo.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; /** * 服务器端 * @author Administrator * */ public class ServerDemo { private ServerSocket server; private Socket socket; private int port = 8888; //构造函数中初始化服务器 public ServerDemo() { // TODO Auto-generated constructor stub try { //这里利用构造方法初始化服务器,我这里只传了一个参数,所以本机相当于服务器 server = new ServerSocket(port); System.out.println("服务器初始化完成..."); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("服务器初始化失败"); } } //服务器需要做的事 public void server(){ //因为服务器不能关,所以需要写个死循环来监听客户端的链接 while(true){ try { //监听客户端的链接,客户端链接进来程序才会继续执行 socket = server.accept(); System.out.println("客户端:"+socket); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String re = br.readLine(); System.out.println(re); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { //启动服务器 new ServerDemo().server(); } }
三、基于UDP协议的网络通信
同样,我们先了解一下什么是UDP通信吧UDP的英文全名是User Datagram Protocol--用户数据报协议
它是一个简单的面向数据报的传输层协议
既然UDP是用户数据报协议,那么它传输的时候肯定是以报文的形式传输的,同时UDP是一种不需要建立连接的传输
所以UDP的数据传输速率快,然后UDP会发生数据丢失的情况。并且UDP一次数据传输不能超过64k。
UDP通信可以用以下图来表示一下。
大致的传输过程如上。
具体的传输流程请看下图
如图所示,我们可以得到一个结果,那就是客户端和服务都是公用的。简单来说就是一个程序既可以成为客户端,
也可以成为服务器端,所以没有TCP那样分开写客户端与服务器端,API主要用到的java类是DatagramSocket类与DatagramPacket类。
我们来看一下API对这两个类的描述:
------------------------------我是分隔符-------------------------------
接下来看看这两个类的用法吧。
查看DatagramSocket的构造方法我们可以看到DatagramSocket可以绑定套接字地址和绑定端口。
查看DatagramPacket的构造方法我们可以看到DatagramPacket是能将数据发出和接收的类,在这个类上可以指定发送到指定主机的指定端口号上。
综上所述,端口和ip可以在DatagramPacket上绑定也可以在DatagramSocket上绑定。
废话不多说,先写一个Demo来实现一个简单的文件收发
package com.demo.udp; 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.util.Date; /** * UDP客户端 * @author Administrator * */ public class UDPClient { private DatagramPacket packet = null; private DatagramSocket socket = null; //客户端程序端口 private int port = 8888; //客户端需发送的数据 private byte [] b = null; //服务器ip private InetAddress address = null; public UDPClient(){ try { socket = new DatagramSocket(); //将字符串装换成InetAddress类型 address = InetAddress.getByName("localhost"); System.out.println("客户端初始化成功"); } catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 发送数据的方法 */ public void send (){ String date = new Date()+""; b = date.getBytes(); System.out.println(date); //将数据打包成一个DatagramPacket报文的格式 packet=new DatagramPacket(b, b.length, address, port); try { //以报文的方式发送数据包 socket.send(packet); } catch (IOException e) { e.printStackTrace(); } } /** * 单报文内的文件发送完了关闭这个Socket通信 */ public void close(){ if(packet!=null){ socket.close(); } } public static void main(String[] args) { UDPClient udpClient = new UDPClient(); for(int i =0;i<10;i++){ udpClient.send(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } udpClient.close(); } }
package com.demo.udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /** * 服务端 * @author Administrator * */ public class UDPServer { private DatagramSocket socket = null; private DatagramPacket packet = null; private int port = 8888; private byte [] b = null; public UDPServer(){ try { socket = new DatagramSocket(port); //每次接收的文件大小 b = new byte[4096]; System.out.println("服务器初始化成功"); //创建一个DatagramPacket对象接收的长度为4096字节,接收到b数组中。 packet = new DatagramPacket(b, b.length); } catch (SocketException e) { e.printStackTrace(); } } /** * 接收方法 */ public void resive(){ try { if(!socket.isClosed()){ socket.receive(packet); } } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } byte[] data = packet.getData(); String s = new String(data); for(int i =0;i<10;i++){ System.out.println(s); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { new UDPServer().resive(); } }
通过观察代码我们可以知道UDP通信主要用了这两个方法中的send方法与receive方法。
顾名思义一个是发信息,一个是收信息。而且发送与接收都是以报文的方式进行的。
PS:由于UDP不是建立连接的通信,我们不能保证不会丢包,所以不建议使用UDP传输大文件。
四、基于TCP/IP建立的协议
如果计算机网络按TCP/IP协议4层结构划分的话可以分为:应用层、传输层、Internet层、网络接口层
我们知道TCP、UDP是传输层的协议,在传输层上是应用层。由于TCP通信是基于socket套接字进行通信的,但是由于socket套接字是没有唯一标识的。
所以我们需要有一套规范(协议)。这套协议可以我们自己定义,也可以使用现有的协议。UDP通信是通过发送报文的形式来传输信息的。如果一个
客户端要同时向另一个客户端发送多个报文,并且不同的报文需要对方的客户端做不同的事情,那么我们就需要在报文的头部添加一个唯一识别的信息。
也就是我们所说的协议。同样这套协议也可以是我们自定义的,也可以使用现有的协议。
目前TCP/IP应用层的协议有:
TCP:FTP 文件传输协议
HTTP 超文本传输协议
TELNET 远程连接协议
SMTP 邮件发送协议
UDP:DNS 域名解析协议
TFTP 简单文件传送协议
还有许多协议这里就不列举了。
五、总结
在java网络通信这一块,由于能力有限,只能聊到这里了,其实网络通信是非常重要的知识点,如果要细分的话,那绝对不是这么一点点
在网络这一块,所有的计算机都需要遵循这些协议,若不遵循这些网络信息传输协议,那网络将会发生错乱。作为一名开发人员,如果不嫌麻烦
的话,可以自定义一套自己用的通信协议。但是,在实际开发中,为了保证效率,我们一般会使用相对比较成熟的协议来通信。在选择TCP/UDP
通信的时候,我们需要考虑下传输数据的大小,考虑应用的场景。