欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java网络基础

程序员文章站 2022-04-27 18:50:24
...

计算机网络

将分布在不同地理区域的计算机,通过一些外部网络设备以及内部的网络协议,连接成一个网络系统;通俗的理解为2台或以上的计算机协同工作,例如:文件传输,数据传输。计算机网络的核心目的是实现:信息共享

网络分类

根据网络规模以及用途分为:

  • 局域网(0-10km,通过网络设备有线连接)
  • 城域网(0-100km,交通信号,视频监控)
  • 广域网(因特网:互联网)

根据网络的工作模式分为:

  • 专有服务器(只提供专一某一种服务器,如:云主机,数据库专有服务器,静态资源文件的专有服务)
  • 客户机服务器模式(c/s架构)
  • 对等式网络(peer to peer)

网络模型与协议

计算机网络之间实现通信需要两种设备支持:

  1. 硬件设备:(网卡,网关:交换机,路由器)
  2. 软件设备:(网络通信协议:TCP/IP、UDP)

网络协议

网络协议就是计算器网络设备相互之间通信的标准(暗号),在互联网标准组织的推动下,将网络协议分为两种:

  • TCP/IP : 传输控制协议/ip协议
    传输控制协议,是一个安全可靠的互联网协议,需要通信的主机之间需要先建立正确的链接,才能够进行通信
  • UDP:用户数据报协议
    是一个不安全的网络协议,不需要双方之间建立联系,也不保证信息传输的有序性(有可能后发消息先到),传输效率比TCP/IP更高.没有专门服务器和客户端,只有发送端和接收端。

IP

Internet Protocol(因特网协议),主机之间通信的唯一标识,每台计算机都已个唯一的ip地址;ip又划分为IPv4和IPv6

  • IPv4由4个字节构成的一段地址(每个字节最大不能超过255,范围0~255,最大取值只能到40+亿个)
  • IPv6由16个字节构成

1字节=8个二进制位

4字节=32位

16字节=128位

ip地址需要确保在同一个网络中不可重复,一旦重复则会出现:ip冲突

ip地址通常分为5类:

A. (1.0.0.0 到127.0.0.0)

B. (128.1.0.0–191.254.0.0)

C. (192.0.1.0–223.255.254.0) 民用**

D. (224.0.0.0到239.255.255.255) 广播

E.(240.0.0.0到255.255.255.254,255.255.255.255)

端口(门牌号)

端口(port)是主机中应用程序对外的沟通的唯一标识;ip是主机的标识,端是应用的标识;因此如果需要准确的寻找到主机中的应用,则需要同时提供ip和端口。

端口分为TCP/IP、UDP

取值范围从 0 ~ 65535之间;但是由于0~1023之间的端口密集绑定了一些已有的服务,所以应该避免在创建自定义服务时使用这些端口;自定义的服务建议选择范围:

  • 1024~49151之间

InetAddress类

IndetAddress是位于java.net包中提供的用于表示ip地址和主机的类,常用方法:

  • getLocalhost() 获取本地主机
  • getByName() 根据提供的主机名或者ip获取InetAddress对象
  • getHostAddress() 获取主机地址
  • getHostName() 获取主机名称

基于TCP/IP的Socket通信

TCP/IP协议是一种面向流的全双工通信协议,有着服务器客户端的概念,必须保证通信双方建立稳定安全的连接才能够进行数据传输;

​ Socket(套接字),实际上就是由IP地址跟端口号的结合,通过Socket对象可以实现两台主机之间的通信;Socket分为服务端Socket(java.net.ServerSocket),以及客户端Socket(java.net.Socket)

示例代码:

/**
 * 服务器
 * @author mrchai
 *
 */
public class Server {

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

        //创建服务
        //		ServerSocket server = new ServerSocket();
        //		//将服务绑定到指定的主机以及指定端口
        //		server.bind(new InetSocketAddress(8888));

        //占据指定的端口创建一个服务(创办一家银行:还未开业)
        ServerSocket server = new ServerSocket(8888);
        System.out.println("服务已开启,等待连接...");
        while(true) {
            //开启监听
            Socket s = server.accept();
            InetAddress ip = s.getInetAddress();
            System.out.println(ip.getHostName()+"==="+ip.getHostAddress());


            //获取基于Socket的输出流
            OutputStream os = s.getOutputStream();
            //将节点流包装打印流
            PrintWriter out = new PrintWriter(os);
            out.println("欢迎使用SOFTEEM服务器!!!");
            out.flush();
            s.close();
        }
    }

}
/**
 * 客户端
 * @author mrchai
 *
 */
public class Client {

    public static void main(String[] args) throws UnknownHostException, IOException {
        //连接到指定地址,指定端口的服务
        Socket s = new Socket("192.168.7.101",8888);

        //从socket中获取输入流
        InputStream is = s.getInputStream();
        //将字节流转换为字符流
        InputStreamReader isr = new InputStreamReader(is);
        //将字符节点流包装为缓冲字符输入流
        BufferedReader br = new BufferedReader(isr);
        //读取一行文本
        String msg = br.readLine();
        System.out.println("服务端:"+msg);
    }
}

基于UDP的Socket通信

UDP协议不是一种基于稳定连接的协议,是一种面向数据报包的通信协议,不需要通信双方建立稳定的连接,也没有所谓服务端和客户的概念,数据报包在传输的时候不保证一定及时到达,也不能保证数据报包的到达顺序,但是UDP协议传输效率要远高于TCP/IP,比如直播,视频会议。

DatagramSocket&DatagramPacket

DatagramSocket类是一个基于UDP通信协议的套接字,使用该类可以实现一个无连接的通信通道;需要实现在该通道通信,我们还需要另一个类的辅助:DatagramPacket(数据报包),该类用于将数据打包成数据报包,然后通过DatagramSocket完成数据报包的发送(send)与接收(receive)
示例代码:

/**
 * 发送方
 * @author mrchai
 *
 */
public class Sender {

    public static void main(String[] args) throws IOException {
        //创建一个数据报的网络通道(创建物流公司)
        DatagramSocket ds = new DatagramSocket();

        //准备需要传输的数据(货物)
        String msg = "天王盖地虎,小鸡炖蘑菇!!!";
        //将需要发送的数据打包成数据报包(打包货物)
        DatagramPacket packet = new DatagramPacket(
            msg.getBytes(), 		//需要被发送的数据的字节数组
            msg.getBytes().length, 	//发送的数据长度(字节数组长度)
            InetAddress.getByName("localhost"),  //接收方的ip
            1025	//接收方的端口				
        );
        //发送数据报包(投递包裹)
        ds.send(packet);
        //关闭通道
        ds.close();
    }
}
/**
 * 接收方
 * @author mrchai
 *
 */
public class Receiver {

    public static void main(String[] args) throws IOException {
        //创建一个数据报的网络通道,绑定到指定端口
        DatagramSocket ds = new DatagramSocket(1025);

        //声明字节数组,用于存储接收的数据
        byte[] b = new byte[1024];
        //准备数据报包(空包)
        DatagramPacket packet = new DatagramPacket(b, b.length);

        //通过循环可以不断接收发送到当前地址和端口的数据报包
        while(true) {
            //接收数据到数据报包中
            ds.receive(packet);
            //接受到的数据(字节数组)实际长度
            int len = packet.getLength();
            //将字节数组转换为字符串
            String s = new String(b, 0, len);
            //获取发送方的ip地址
            String ip = packet.getAddress().getHostAddress();
            System.out.println("收到来自【"+ip+"】消息:"+s);
        }
    }
}

UDP数据广播

java.net包中提供了用于实现UDP数据广播的Socket类:java.net.MulticastSocket,该类从DatagramSocket继承而来,可以实现广播消息的发送:

/**
 * 广播发送方
 * @author mrchai
 *
 */
public class BoradcastSender {

    public static void main(String[] args) throws IOException {
        //创建广播通道
        MulticastSocket ms = new MulticastSocket();
        //获取广播地址(D类地址)
        InetAddress addr = InetAddress.getByName("228.5.6.7");
        //将通道加入组播地址
        ms.joinGroup(addr);

        String msg = "*************";
        //将消息打包成数据报包
        DatagramPacket dp = new DatagramPacket(
            msg.getBytes(), 
            msg.getBytes().length, 
            addr, 
            5555);
        //发送
        ms.send(dp);
        ms.close();
    }
}

/**
 *广播接收方
 * @author mrchai
 *
 */
public class BroadcastReceiver {

	public static void main(String[] args) throws IOException {
		//创建广播通道,并绑定端口5555
		MulticastSocket ms = new MulticastSocket(5555);
		//获取广播地址(D类地址)
		InetAddress addr = InetAddress.getByName("228.5.6.7");
		//将通道加入组播地址
		ms.joinGroup(addr);
		
		//声明字节缓冲区
		byte[] b = new byte[1024];
		//基于字节缓冲区构建数据报包(空包)
		DatagramPacket dp = new DatagramPacket(b, b.length);
		System.out.println("准备接收通知...");
		while(true) {
			//接收数据到数据报包中
			ms.receive(dp);
			//获取读取到的数据报长度
			int len = dp.getLength();
			String ip = dp.getAddress().getHostAddress();
			String s = new String(b,0,len);
			System.out.println("接收到来自"+ip+"的通知消息:"+s);
		}
	}
}

Http协议

URL 类

URL(统一资源定位器),一般用于表示一个网络地址(本地网,外部网络),通过该地址可以定位到网络中的资源。

URL的案例:

  • http://www.softeem.com:80/sales/home.html?page=1
  • ftp://119.231.8.19:23
  • jdbc:mysql://192.168.0.1:3306/test?user=root&password=123456

一个URL地址通常由以下几个部分构成:

  • 协议(双方约定的通信标准: http:// ftp:// jdbc:mysql://)
  • 主机地址或域名(资源所在服务器地址:softeem.com 119.231.8.9 192.168.0.1)
  • 端口(服务器中指定服务对外数据交换接口,唯一:80 3306)
  • 请求资源(服务器根地址中资源所在的相对位置:/sales/home.html test)
  • 查询路径(?之后的内容:page=1 user=root&password=123456)

URL类中提供的部分方法:


        //根据提供的url地址创建一个URL对象
        URL url = new URL("http://www.softeem.com:80/doc/index.html?offset=5&limit=10");
        //获取当前地址所表示的协议
        String protocol = url.getProtocol();
        System.out.println(protocol);
        //获取主机地址
        String host = url.getHost();
        System.out.println(host);

        //获取端口号
        int port = url.getPort();
        System.out.println(port);

        //获取该URL请求的所有内容包括查询路径
        String file = url.getFile();
        System.out.println(file);

        //获取URL的请求路径部分(不含查询路径)
        String path = url.getPath();
        System.out.println(path);

        //获取查询部分
        String query = url.getQuery();
        System.out.println(query);

Http概述

Http(Hyper Text Transfer Protocol)超文本传输协议(not only text);是一个基于TCP/IP的应用层协议,一般用于WWW服务器进行数据传输的一种协议,http是一种请求响应协议,即由客户端通过http协议发起请求,由http服务器提供响应;http是一种无状态的短链接协议。
由于HTTP协议是基于TCP/IP的,因此客户端和服务端之间通信都是面向字节流通信机制

Http请求的构成

一个http请求过程通常由两个部分组成:

  1. 请求头(客户端请求到服务器时传输一些配置信息以及书资源)
  2. 响应头(服务端响应客户端时传递到客户端的状态信息)

请求头

请求体 是否必选
GET/POST [请求资源的URL路径] HTTP/[HTTP版本]
Host: [URL主机]
User-Agent: [请求类型唯一标识]
Accept: [设置服务器返回的数据类型]
Accept-Language:[设置服务器返回的语言]
Accept-Encoding: [设置服务器返回的压缩编码]
Accept-Charset: [设置服务器返回的文字编码]
\r\n
Post内容

请求头中常见的请求方式有

  • POST
  • GET
  • DELETE
  • PUT
  • HEAD

响应头

回复体 是否必须返回
HTTP/[HTTP版本] [HTTP状态码]
Date: [服务器时间]
Server: [服务器类型]
Content-Type: [返回的数据流内容类型]
Content-Length:[返回的数据流内容长度]
Content-Encoding:[返回的数据流压缩编码]
Accept-Charset: [设置服务器返回的文字编码]
\r\n
回复体内容

http响应头中比较值得关注的是响应的状态码。

  • 1XX 消息
  • 2XX 响应成功
  • 200 服务端响应成功
  • 3XX 重定向,请求被重新定向到其他目标
  • 4XX 来自客户端的请求错误
  • 404 Not Found 请求的资源不存在
  • 405 请求和响应的方式不一致(客户端发送get请求,但是服务端使用post接收)
  • 5XX 服务器错误
  • 500 服务器内部错误(程序异常)

JSON数据格式

HttpURLConnection

​ HttpURLConnection用于获取一个http连接,是一个http客户端工具类,HttpURLConnection从URLConnection继承而来,通过该类可以读取服务端响应的数据(文本,视频,音频,图片等资源)。

public class HttpConnDemo {

    public String loadData(String url) {
        //Callable&FutureTask
        return null;
    }

    //练习:将以下地址表示的音乐文件下载到本地
    //http://music.softeem.top/musics/1592383934192.mp3
    public static void main(String[] args) {
        //		new Thread() {	
        //			public void run() {			
        //			};
        //		}.start();
        //使用线程启动网络请求
        new Thread(()->{

            try {
                //				String path = "http://192.168.7.141:9090/easyblog/index.html";
                String path = "http://music.softeem.top/list";
                //根据提供的url地址创建一个url对象
                URL url = new URL(path);
                //打开连接(强转为HttpURLConnection)
                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                //打开连接
                //			conn.connect();
                //设置请求方式(不设置默认使用GET)
                conn.setRequestMethod("GET");
                //获取服务端的响应码
                int code = conn.getResponseCode();
                //避免魔法值
                if(code == HttpURLConnection.HTTP_OK) {
                    //从连接中获取输入流
                    InputStream is = conn.getInputStream();
                    InputStreamReader isr = new InputStreamReader(is,"utf-8");
                    BufferedReader br = new BufferedReader(isr);

                    String str = "";
                    while((str = br.readLine()) != null) {
                        System.out.println(str);
                    }
                    br.close();
                }
                //断开连接
                conn.disconnect();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (ProtocolException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }) .start();
    }
}

基于Http协议下载远程文件

/**
 * 文件下载器
 * @author mrchai
 */
public class FileDownloader {

    public void download(String url,File dir) throws MalformedURLException, FileNotFoundException {

        URL urlObj = new URL(url);

        //获取文件名称
        String path = urlObj.getPath();	//	musics/1592383934192.mp3
        int index = path.lastIndexOf("/");// 6
        String fname = path.substring(index+1); // 1592383934192.mp3
        //根据文件名组合目录获取本地文件的输出流
        OutputStream os = new FileOutputStream(new File(dir,fname));
        System.out.println("开始下载..."); 
        //启动线程读写
        new Thread(()-> {
            HttpURLConnection conn = null;
            InputStream is = null;
            try {
                //打开连接
                conn = (HttpURLConnection)urlObj.openConnection();
                conn.setRequestMethod("GET");
                //获取响应状态码
                int stateCode = conn.getResponseCode();
                if(stateCode == HttpURLConnection.HTTP_OK) {
                    //获取连接中输入流
                    is = conn.getInputStream();
                    byte[] b = new byte[1024];
                    int len = 0;
                    while((len = is.read(b)) != -1) {
                        os.write(b, 0, len);
                    }
                    System.out.println("下载完成!!!");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if(os != null)os.close();
                    if(is != null)is.close();
                    if(conn != null)conn.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }).start();

    }

    public static void main(String[] args) throws MalformedURLException, FileNotFoundException {
        //		String url = "http://music.softeem.top/musics/1592383934192.mp3";
        //		String url = "http://192.168.7.141:9090/easyblog/mp3/WeAreYoung.mp3";
        String url="https://vdept.bdstatic.com/366e32794a7965496b53655453614276/4b5a314d42746252/dff065116b75d4ef9129d7746e9ec38095b1d32cfaae43e648f2d7f1c3ee084e52394855eb32d106c6775955cf6abb2def3c701150f1ed387791e632bf442002.mp4?auth_key=1595566524-0-0-8e9d876380f34a9366e5b88aea39c832";
        new FileDownloader().download(url,new File("d:/tempfile"));
    }

}

JSON数据格式

​ JSON(JavaScript Object Notation)是一种与语言平台无关的数据交换格式,有着比XML更为轻量级的数据表现形式,是目前大多数互联网应用程序之间的数据交换格式的首选。

JSON数据格式从结构上分为三种类型:

  1. 标量
  2. 数组
  3. 对象

标量

标量即一个具体的值:数值,字符串,布尔等;如:10、softeem、true 都是标量

数组

也称之为序列,序列即一系列数据(类型一致)的集合,数组使用“[]”包裹,内部元素之间使用“,”隔开,比如:数值数组,字符串数组,复杂的对象数组

[2,4,6,8,0]
["kobe","curry","wade"]
[
    {
        "name":"黑龙江",
        "citys":["哈尔滨","大庆"]
    }, 
    {
        "name":"*",
        "citys":["台北","*"]
    }
]

对象

也称之为映射(Map),所谓映射即一个对象,包含在一对”{}“之间,内部的元素以键值对为结构组织,键和值之间使用“:”分隔,元素之间以“,”隔开

{
    "id":10,
    "name":"softeem",
    "type":"normal""flag":true,
    "langs":["java","c++","php"],
    "group":{
        id:1,
        gname:"vip1"
    }
}

JSON支持的数据类型

JSON数据格式支持的值类型:

  1. String 字符串
  2. Number 数值
  3. Array 数组
  4. Object 对象
  5. true/false 布尔值
  6. null 空值

JSON与Java对象相互转换

json作为一种数据交换格式,就避免不了与Java之间的相互转换,因此对于Json字符串和Java之间的转换,目前有一些开源的可选方案:

  • FastJSON:阿里巴巴提供
  • Gson:Google提供
  • Jackson
  • json-lib

FastJSON使用

fastJSON是由阿里巴巴开源的JSON库,号称全世界最快的json插件,常用方法:

  • toJSONString(Object) 将一个Java对象转换为Json字符串
  • parseObject(String json,Class<T> clazz) 将一个json字符串转换为Java对象
  • parseArray(String json,Class<T> clazz) 将一个json字符串转换为Java集合