Java网络通讯协议、UDP、TCP类加载整理

     网络通讯协议

  网络通讯协议java

网络通讯协议有不少种,目前应用最普遍的是TCP/IP协议(Transmission Control Protocal/Internet Protoal传输控制协议/英特网互联协议),它是一个包括TCP协议和IP协议,UDP(User Datagram Protocol)协议和其它一些协议的协议组,在学习具体协议以前首先了解一下TCP/IP协议组的层次结构。数组

 

 

 

1.1      InetAddress

 

 

 

package com.oracle.InetAddress;安全

 

import java.net.InetAddress;服务器

import java.net.UnknownHostException;网络

 

public class Demo01 {多线程

    public static void main(String[] args) throws UnknownHostException {oracle

        //获取本机地址dom

        InetAddress inet=InetAddress.getLocalHost();socket

        System.out.println(inet);post

        //根据主机名获取inet对象

    /*  InetAddress inet1=InetAddress.getByName("DESKOP-NR4E1C5");

        //获取主机名

        System.out.println(inet1.getHostName());*/

        //获取ip地址

        String ip=inet.getHostAddress();

        System.out.println(ip);

       

    }

}

 

运行结果:

 

 

     UDP与TCP协议

在介绍TCP/IP结构时,提到传输层的两个重要的高级协议,分别是UDP和TCP,其中UDP是User Datagram Protocol的简称,称为用户数据报协议,TCP是Transmission Control Protocol的简称,称为传输控制协议。

2.1      UDP协议

 

UDP是无链接通讯协议,即在数据传输时,数据的发送端和接收端不创建逻辑链接。

 

可是在使用UDP协议传送数据时,因为UDP的面向无链接性,不能保证数据的完整性,所以在传输重要数据时不建议使用UDP协议。UDP的交换过程以下图所示。

UDP传输数据被限制在64K之内

 

 

 

 

2.2      TCP协议

TCP协议是面向链接的通讯协议,即在传输数据前先在发送端和接收端创建逻辑链接,而后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。

 

 

因为TCP协议的面向链接特性,它能够保证传输数据的全性安,因此是一个被普遍采用的协议,例如在下载文件时,若是数据接收不完整,将会致使文件数据丢失而不能被打开,所以,下载文件时必须采用TCP协议。

 UDP通讯

3.1      DatagramPacket

UDP是一种面向无链接的协议,UDP通讯也是同样,发送和接收的数据也须要使用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就至关于一个集装箱,用于封装UDP通讯中发送或者接收的数据

接下来根据API文档的内容,对DatagramPacket的构造方法进行逐一详细地讲解。

 

 

使用该构造方法在建立DatagramPacket对象时,指定了封装数据的字节数组和数据的大小,没有指定IP地址和端口号。很明显,这样的对象只能用于接收端,不能用于发送端。由于发送端必定要明确指出数据的目的地(ip地址和端口号),而接收端不须要明确知道数据的来源,只须要接收到数据便可。

 

 

用该构造方法在建立DatagramPacket对象时,不只指定了封装数据的字节数组和数据的大小,还指定了数据包的目标IP地址(addr)和端口号(port)。该对象一般用于发送端,由于在发送数据时必须指定接收端的IP地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址同样。

 

面咱们讲解了DatagramPacket的构造方法,接下来对DatagramPacket类中的经常使用方法进行详细地讲解,

 

 

3.2      DatagramSocket

DatagramPacket数据包的做用就如同是“集装箱”,能够将发送端或者接收端的数据封装起来。在程序中须要实现通讯只有DatagramPacket数据包也一样不行,为此JDK中提供的一个DatagramSocket类。DatagramSocket类的做用就相似于码头,使用这个类的实例对象就能够发送和接收DatagramPacket数据包,发送数据的过程以下图所示。

 

 

在建立发送端和接收端的DatagramSocket对象时,使用的构造方法也有所不一样,下面对DatagramSocket类中经常使用的构造方法进行讲解。

 

 

该构造方法用于建立发送端的DatagramSocket对象,在建立DatagramSocket对象时,并无指定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。

 

 

该构造方法既可用于建立接收端的DatagramSocket对象,又能够建立发送端的DatagramSocket对象,在建立接收端的DatagramSocket对象时,必需要指定一个端口号,这样就能够监听指定的端口。

 

 

 

3.3      UDP网络程序

 

 

 

要实现UDP通讯须要建立一个发送端程序和一个接收端程序,很明显,在通讯时只有接收端程序先运行,才能避免因发送端发送的数据没法接收,而形成数据丢失。所以,首先须要来完成接收端程序的编写。

 

package com.oracle.InetAddress;

 

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.util.Scanner;

 

 

//UDPend协议发送端

public class UDPend {

    public static void main(String[] args) throws IOException {

        Scanner  sc=new Scanner(System.in);

        String str=sc.next();

        //1.建立数据包对象,封装要发送的信息、接收端的ip以及端口号

        byte[] bytes=str.getBytes();

        InetAddress inet=InetAddress.getByName("127.0.0.1");

        DatagramPacket dp=new DatagramPacket(bytes, bytes.length,inet,8888);

        //2.建立DatagramSocket对象

        DatagramSocket ds=new DatagramSocket();

        //3.发送数据包

        ds.send(dp);

        //4.释放资源

        ds.close();

    }

}

 

 

 

package com.oracle.InetAddress;

 

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.SocketException;

 

//UDPRecieve接收端

public class UDPRecieve {

    public static void main(String[] args) throws IOException {

        //建立DatagramSocket对象明确的端口号

        DatagramSocket ds=new DatagramSocket(8888);

        //建立字节数组接收数据

        byte[] bytes=new byte[1024];

        //建立数据包对象

        DatagramPacket dp=new DatagramPacket(bytes,bytes.length);

        //接收数据包

        ds.receive(dp);

        //拆包

        //获取发送端的ip地址

        String ip=dp.getAddress().getHostAddress();

        //获取发送端的端口号

        int post=dp.getPort();

        //获取实际数据的长度

        int length=dp.getLength();

        System.out.println("ip地址为:"+ip+",端口号为:"+post+",发送内容为:"+new String(bytes,0,length));

        //关闭资源

        ds.close();

    }

}

 

 

    TCP通讯

TCP通讯同UDP通讯同样,都能实现两台计算机之间的通讯,通讯的两端都须要建立socket对象。

区别

UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间能够任意地发送数据

而TCP通讯是严格区分客户端与服务器端的,在通讯时,必须先由客户端去链接服务器端才能实现通讯,服务器端不能够主动链接客户端,而且服务器端程序须要事先启动,等待客户端的链接。

 

在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。

4.1      ServerSocket

JDK的java.net包中提供了一个ServerSocket类,该类的实例对象能够实现一个服务器段的程序。经过查阅API文档可知,ServerSocket类提供了多种构造方法

 

 

使用该构造方法在建立ServerSocket对象时,就能够将其绑定到一个指定的端口号上(参数port就是端口号)。

ServerSocket的经常使用方法:

 

 

ServerSocket对象负责监听某台计算机的某个端口号,在建立ServerSocket对象后,须要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法以后,服务器端程序会发生阻塞,直到客户端发出链接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通讯,程序才能继续向下执行。

4.2      Socket

查阅API文档可知Socket类一样提供了多种构造方法

 

 

使用该构造方法在建立Socket对象时,会根据参数去链接在指定地址和端口上运行的服务器程序,其中参数host接收的是一个字符串类型的IP地址。

 

 

该方法在使用上与第二个构造方法相似,参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。

在以上Socket的构造方法中,最经常使用的是第一个构造方法。

Socket的经常使用方法:

方法声明

功能描述

int getPort()

该方法返回一个int类型对象,该对象是Socket对象与服务器端链接的端口号

InetAddress getLocalAddress()

该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回

void close()

该方法用于关闭Socket链接,结束本次通讯。在关闭socket以前,应将与socket相关的全部的输入/输出流所有关闭,这是由于一个良好的程序应该在执行完毕时释放全部的资源

InputStream getInputStream()

该方法返回一个InputStream类型的输入流对象,若是该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据

OutputStream getOutputStream()

该方法返回一个OutputStream类型的输出流对象,若是该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据

在Socket类的经常使用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端创建链接后,数据是以IO流的形式进行交互的,从而实现通讯。

 

 

4.3      简单的TCP网络程序

 

/*

 * 实现TCP 服务器程序

 * 表示服务器程序的类 java.net.ServerSocket

 * 构造方法:

 *     ServerSocket(int port)传递端口号

 *     很重要的事情:必需要得到客户端的套接字对象Socket

 *     Socket accept()

 *

 * 1,建立服务器ServerSocket对象(指定服务器端口号)

 * 2,开启服务器了,等待客户端的链接,当客户端链接后,能够获取到链接服务器的客户端Socket对象

 * 3,给客户端反馈信息

 * 4,关闭流资源

 */

    //服务器程序

package com.oracle.Tcp;

 

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

public class TCPServer {

    public static void main(String[] args) throws IOException {

        //建立ServiceScoket对象,接收客户端

        ServerSocket server=new ServerSocket(8080);

        //调用accept方法,获取链接个人客户端的Socket对象

        Socket socket=server.accept();

        //获取输入字节流

        InputStream in=socket.getInputStream();

        byte[] bytes=new byte[1024];

        int len=in.read(bytes);

        String ip=socket.getLocalAddress().getHostAddress();

        int port=socket.getPort();

        System.out.println("客户端地址为:"+ip+",端口号为:"+port+"发送内容为:"+new String(bytes,0,len));

        //回复客户端

        OutputStream out=socket.getOutputStream();

        out.write("哈哈".getBytes());

        //释放资源

        server.close();

    }

}

 

/*

 * 实现TCP 客户端,链接到服务器

 * 和服务器实现数据交换

 * 实现TCP客户端程序的类 java.net.Soket

 * 构造方法

 *    Socket(String host,int port) 传递服务器IP和端口号

 *    注意:构造方法只要运行,就会和服务器进行链接,链接失败,抛出异常

 

 *    OutputStream   getOutputStream() 返回套接字的输出流

 *    做用:将数据输出,输出到服务器

 *    InputStream   getInputStream() 返回套接字的输入流

 *    做用:从服务器端读取数据

 

 *    客户端服务器数据交换,必须使用套接字对象Socket中的获取的IO流,本身new流,不行

 

 * 1,建立客户端Socket对象,(指定要链接的服务器地址与端口号)

 * 2,获取服务器端的反馈回来的信息

 * 3,关闭流资源

 */

//客户端程序

package com.oracle.Tcp;

 

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

 

public class TCPClient {

    public static void main(String[] args) throws IOException {

        //建立Socket对象,链接服务器

        Socket scoket=new Socket("127.0.0.1",8080);

        //获取输出字节流

        OutputStream out=scoket.getOutputStream();

        //发送数据

        out.write("嘤嘤嘤".getBytes());

        //接收服务器端的回复

        InputStream in=scoket.getInputStream();

        byte[] bytes=new byte[1024];

        String ip=scoket.getLocalAddress().getHostAddress();

        int port=scoket.getPort();

        int len=in.read(bytes);

       System.out.println("服务端ip地址为:"+ip+",端口号为:"+port+",内容为:"+new String(bytes,0,len));

        scoket.close();

       

       

       

    }

}

 

4.4      文件上传案例多线程版本

目前大多数服务器都会提供文件上传的功能,因为文件上传须要数据的安全性和完整性,很明显须要使用TCP协议来实现。接下来经过一个案例来实现图片上传的功能

 

 

 

//服务器程序

package com.oracle.WenJian;

 

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.Random;

 

public class TCPServer {

    public static void main(String[] args) throws IOException {

        //建立ServerSocket对象,接收客户端

        ServerSocket server=new ServerSocket(8080);

        //调用accpt方法 建立链接并获取客户端socket对象

        Socket socket=server.accept();

        //获取字节输入流

        InputStream in=socket.getInputStream();

        //明确目的地

        File file=new File("E:\\test1");

        if(!file.exists()){

            file.mkdirs();

        }

        //文件路径

       

        //文件名:域名+毫秒值+6位随机数

        String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(999999);

        String path=file.getAbsolutePath()+File.separator+filename+".png";

        FileOutputStream fos=new FileOutputStream(path);

       

        //开始复制

        byte[] bytes=new byte[1024];

        int len=0;

        while ((len=in.read(bytes))!=-1) {

            fos.write(bytes,0,len);

        }

        //回复客户端

        OutputStream out=socket.getOutputStream();

        out.write("上传成功!!".getBytes());

        //释放资源

        fos.close();

        server.close();

       

       

       

       

    }

}  

 

 

//客户端程序

package com.oracle.WenJian;

 

 

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

public class TCPClient {

    public static void main(String[] args) throws IOException {

        //建立Socket对象,链接服务器

        Socket socket=new Socket("192.168.1.171",8080);

        //获取字节流输出

        OutputStream out=socket.getOutputStream();

        //建立字节输入流,明确数据源

        FileInputStream fis=new FileInputStream("E:\\test\\b.png");

        byte[] bytes=new byte[1024];

        //开始复制

        int len=0;

        while ((len=fis.read(bytes))!=-1) {

            out.write(bytes,0,len);

           

        }

        //告诉服务器 添加一个结束标记

        socket.shutdownOutput();

        //接收服务器的回复

        InputStream in=socket.getInputStream();

        len=in.read(bytes);

        System.out.println(new String(bytes,0,len));

        //释放资源

        fis.close();

        socket.close();

       

    }

}

    类加载器

5.1      类的加载

当程序要使用某个类时,若是该类还未被加载到内存中,则系统会经过加载,链接,初始化三步来实现对这个类进行初始化。

加载

就是指将class文件读入内存,并为之建立一个Class对象。

任何类被使用时系统都会创建一个Class对象

链接

验证 是否有正确的内部结构,并和其余类协调一致

准备 负责为类的静态成员分配内存,并设置默认初始化值

解析 将类的二进制数据中的符号引用替换为直接引用

初始化

就是咱们之前讲过的初始化步骤

5.2      类初始化时机

1. 建立类的实例

2. 类的静态变量,或者为静态变量赋值

3. 类的静态方法

4. 使用反射方式来强制建立某个类或接口对应的java.lang.Class对象

5. 初始化某个类的子类

6. 直接使用java.exe命令来运行某个主类

5.3      类加载器

负责将.class文件加载到内存中,并为之生成对应的Class对象。

虽然咱们不须要关心类加载机制,可是了解这个机制咱们就能更好的理解程序的运行

5.4      类加载器的组成

Bootstrap ClassLoader 根类加载器也被称为引导类加载器,负责Java核心类的加载

好比System,String等。在JDK中JRE的lib目录下rt.jar文件中Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

System ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

 

经过这些描述就能够知道咱们经常使用的类,都是由谁来加载完成的。

相关文章
相关标签/搜索