zoukankan      html  css  js  c++  java
  • Java学习--网络编程

     目录

      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层。

      下面是OISTCP/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

    通信的时候,我们需要考虑下传输数据的大小,考虑应用的场景。

     

      

  • 相关阅读:
    2020年勒索软件攻击最多的四大漏洞
    物联网时代,我们还能有哪些隐私?
    区块链技术最重要价值所在
    为什么云遣返不仅仅是从公共云回到内部部署环境
    如何应对越来越多的物联网勒索软件威胁?
    如何将边缘计算与核心系统集成
    莫唱衰:5G开局很快,但原力呈现才刚刚开始
    云原生架构支撑千万级DAU游戏
    变革型AI、无代码与低代码——哪一种才是企业AI部署的理想途径?
    nginx代理的配置和文件访问权限配置
  • 原文地址:https://www.cnblogs.com/bananafish/p/9713209.html
Copyright © 2011-2022 走看看