Java之网络编程

2023-10-29

1.B/S和C/S架构

1.1B/S架构

B/S架构是Browser/Server的简称,即浏览器/服务器结构,它的特点是客户端只需要安装浏览器即可访问资源,应用程序逻辑和数据均放在服务端共享访问。

  • 优点:易于维护,服务端升级版本后,客户端(浏览器)不用升级,网页刷新后就可以获取就可以获取最新的版本
  • 缺点:会占用服务端的带宽资源

1.2C/S架构

C/S架构是Client/Serverd的简称,即客户机/服务器结构,C/S通常采用两层结构,服务端负责数据管理,客户端负责界面交互,例如微信、QQ等等

  • 优点:静态资源下载到本地安装,不用大量请求资源,占用服务端带宽资源相对B/S架构的小
  • 缺点:版本升级需要重新安装才可以使用

2.http协议

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上

2.1http协议的特点

  1. 底层基于TCP协议实现,面向连接方式安全
  2. 基于请求(request)和响应(response)模型
  3. http协议是无状态协议,对于事务处理没有任何记忆功能
  4. http多次请求数据无法共享(通常使用cookie和session解决)
  5. http协议传输数据过程属于同步的过程,如果客户端发送请求到达服务端,服务端一直没有响应,客户端会一直阻塞等待,对于用户体验不是那么友好

2.2http请求格式

http请求格式有三部分组成:请求行,请求头以及请求体

  1. 请求行:由三部分组成:请求方法(请求方法包括GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE以及扩展方法) URL以及协议的版本,之间由空格分隔,例如:POST /v1/api/check/userstatus HTTP/1.1
    在这里插入图片描述
  2. 请求头:键值对的形式,传递服务器可能会用到的参数,比如cookie,应用程序名等等
    在这里插入图片描述
  3. 请求体:客户端传送给服务端的数据,如:username=zhxd&&age=18
    在这里插入图片描述
  • post和get请求的区别:
  1. get请求参数放在请求行中,没有请求体
  2. post请求参数在请求体中
  3. get请求参数有大小限制,post请求没有

2.3http响应格式

http响应格式也分为三个部分:响应行,响应头,响应体

  1. 响应行:响应数据第一行,包括http协议版本号 状态码 状态信息
HTTP/1.1 200 OK
  1. 响应头:键值对的形式,返回客户端解析资源时可能要用到的参数
Location: http://www.baidu.com(服务端需要客户端访问的页面路径)
Server:apache tomcat(服务端的Web服务端名)
Content-Encoding: gzip(服务端能够发送压缩编码类型)
Content-Length: 80(服务端发送的压缩数据的长度)
Content-Language: zh-cn(服务端发送的语言类型)
Content-Type: text/html; charset=GB2312(服务端发送的类型及采用的编码方式)
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务端对该资源最后修改的时间)
Refresh: 1;url=http://www.mayikt.com(服务端要求客户端1秒钟后,刷新,然后访问指定的页面路径)
Content-Disposition: attachment; filename=aaa.zip(服务端要求客户端以下载文件的方式打开该文件)
Transfer-Encoding: chunked(分块传递数据到客户端)
Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务端发送到客户端的暂存数据)
Expires: date(Cache-Control过期时间)
Cache-Control: no-cache(服务端禁止客户端缓存页面数据) max-age=xx(通知浏览器:xx秒之内别来烦我,自己从缓冲区中刷新)
Pragma: no-***(服务端禁止客户端缓存页面数据)
Connection: close(1.0)/(1.1)Keep-Alive(维护客户端和服务端的连接关系)
Date: Tue, 11 Jul 2000 18:23:51 GMT(服务端响应客户端的时间)
  1. 响应体:响应给客户端的数据(内容)
{
    "username": "m0_63836635",
    "biz": "blog",
    "subBiz": "article"
}
  • http响应状态码说明
  1. 1xx:临时响应
  2. 2xx:成功响应
    • 200:成功,服务器成功处理请求
    • 201:已创建,请求成功并且服务器创建新的资源
    • 202:已接收,服务器已接受请求,但尚未处理
    • 203:非授权信息,服务器成功处理请求,但消息可能来自其他来源
    • 204:无内容,服务器成功处理请求,但没有返回任何内容
    • 205:重置内容,服务器成功处理请求,但没有返回任何内容
    • 206: 服务器成功处理了部分 GET 请求
  3. 3xx:重定向
    • 301:永久移动, 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置
    • 302:临时移动,服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求
  4. 4xx(客户端错误)
    • 404:找不到资源
  5. 5xx:服务端错误
    • 500:服务端遇到错误,无法请求

3.UDP协议

UDP协议 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法,俗称面向无连接。通俗易懂讲解 UDP协议会把数据打包发送给目标地址, 这个数据包能不能发送给目标地址就不管了,所以我们的udp协议 它是不可靠协议、安全性低,容易丢包 但是速度非常快 无需类似于 tcp协议三次握手。
UDP的特点:

  1. 面向无连接,不可靠协议
  2. 安全系数低,容易丢包
  3. 传输速度非常快

4.TCP协议

TCP面向的连接是有效可靠的,通过三次握手建立连接和四次挥手拆除连接,TCP建立和拆除连接中有一些专业表示名词,SYN建立连接,ACK确认标志,FIN终止标志。

  • tcp三次握手建立连接:
  1. 第一次握手:客户端向服务端发送建立连接标志syn=1,并生成随机的数字seq_number=x发送到服务端(SYN=syn+x)
  2. 第二次握手:服务端接收到客户端发送的数据之后,确认ack=x+1(ACK),向客户端发送连接标志并生成随机数字seq_number=y(SYN)
  3. 第三次握手:客户端接收到SYN+ACK,向服务端发送确认ack=y+1,TCP连接建立
    在这里插入图片描述
  • tcp四次挥手关闭连接
  1. 第一次挥手:客户端向服务器发送fin=1,并生成随机数seq_number=u
  2. 第二次挥手:服务端接受到释放报文后,发送ack=u+1,并生成随机数seq_number=v给客户端,当前状态为关闭等待状态

客户端收到了服务器确认通知之后,此时客户端就会进入到终止状态,等待服务器端发送释放报文

  1. 第三次挥手:服务端确认数据发送完毕之后,就向客户端发送fin=1,ack=u+1,并生成随机数seq_number=w给客户端
  2. 第四次挥手:客户端必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时客户端就入了TIME-WAIT(时间等待)状态。此时的TCP连接还没有释放,必须经过2**MSL(最长报文寿命),当客户端撤销相应的TCB后,客户端进入CLOSED状态(服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些)

5.DNS域名解析

域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网(通俗讲就是为了方便记忆 我们会使用域名在通过dns解析成我们的ip地址)

域名解析会先走本地配置的域名解析器,如果没有找到再往上级域名解析器去找,如果都没有,就会到公网ip电信运行商去找。windows系统域名解析配置在C:\Windows\System32\drivers\etc
在这里插入图片描述
在这里插入图片描述

6.socket

  1. 计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程。例如我们的QQ聊天
  2. Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序。
  3. Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。

在这里插入图片描述
网络通信三要素:ip 端口号 协议

6.1InetAddress

在jdk中提供了一个与IP相关的InterAddress类,该类用于封装一个IP地址,并提供了一系列与IP相关的方法。
InterAddress常用方法

  • static InetAddress getByName(String host):获取给定主机名的IP地址,host参数表示指定主机
  • InetAddress getLocalhost():获取本机的IP地址
  • String getHostName():获取本地的IP地址的主机名
  • String getHostAddress():获取字符串格式的原始IP地址
  • static boolean isReachable(int timeout):判断在限定时间内指定的IP地址是否可以访问
package com.zhxd.test;
/*
 * author zhxd
 * ClassName interAddressTest
 */

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class inetAddressTest {
    public static void main(String[] args) throws IOException {
        //获取指定主机的IP
        InetAddress inetAddress = InetAddress.getByName("www.zhxd.com");//主机名可在hosts中配置
        //获取字符串IP地址
        String ip = inetAddress.getHostAddress();
        System.out.println(ip);
        //获取本地IP
        InetAddress inetAddress2 = InetAddress.getLocalHost();
        System.out.println(inetAddress2.getHostAddress());
        //获取本地IP的主机名
        String hostName = inetAddress2.getHostName();
        System.out.println(hostName);
        //判断指定IP地址在限定时间内是否可以连通
        boolean reachable = InetAddress.getByName("www.baidu.com").isReachable(1000);
        System.out.println(reachable);
    }
}

6.2UDP发送端

  1. 创建发送端Socket对象:new DatagramSocket()
  2. 提供数据,把数据封装到数据包中:new DatagramPacket(byte[] msg, int msglength,InetAddress inetAddress,int port)
    • msg:字节形式的消息
    • msglength:消息的长度
    • inetAddress:接收端IP
    • port:接收端端口号
  3. 通过Socket服务的发送功能,把数据包发送出去:datagramSocket.send(DatagramPacket datagramPacket )
    • datagramPacket :数据包
  4. 释放资源:datagramSocket.close()
package com.zhxd.test;

import java.io.IOException;
import java.net.*;

public class UDPClient{
    public static void main(String[] args) throws IOException {
        //1.创建UDP发送端
        DatagramSocket datagramSocket = new DatagramSocket();
        //2.封装数据包
        byte[] msg = "你好".getBytes();
        InetAddress inetAddress = InetAddress.getByName("www.zhxd.com");
        int port = 8081;
        DatagramPacket datagramPacket = new DatagramPacket(msg, msg.length, inetAddress, port);
        //发送消息
        datagramSocket.send(datagramPacket);
        //释放资源
        datagramSocket.close();
    }
}

6.3UDP接收端

  1. 创建接收端socket对象:new DatagramSocket(int port)
    • port:端口号
  2. 接收数据:new DatagramPacket(byte[] msg,int msgLength)
    • msg:接收发送端的消息
    • msgLength:消息的长度
  3. 解析数据:datagramSocket.receive(DatagramPacket datagramPacket)
    • datagramPacket:数据包,把接受到的数据往datagramPacket存放
  4. 输出数据:datagramPacket.getData()
  5. 释放资源:datagramSocket.close()
package com.zhxd.test;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPServer{
    public static void main(String[] args) throws IOException {
        //1. 创建接收端的socket对象
        DatagramSocket datagramSocket = new DatagramSocket(8081);
        //2. 接收数据
        byte[] msg = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(msg, msg.length);
        //3.解析数据
        datagramSocket.receive(datagramPacket);
        //4.输出数据
        System.out.println(new String(datagramPacket.getData()));
        //5.释放资源
        datagramSocket.close();
    }
}

6.4TCP发送端

  1. 创建发送端Socket对象(创建连接):new Socket(InetAddress inetAddress,int port)
    • inetAddress:接收端IP地址
    • port:接收端端口号
  2. 获取输出流对象:socket.getOutputStream()
  3. 发送数据:outputStream.write(byte[] msg)
    • msg:字节形式的数据
  4. 释放资源:socket.close()
package com.zhxd.test;
/*
 * author zhxd
 * ClassName TCPClient
 */

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class TCPClient {
    public static void main(String[] args) throws IOException {
        //1. 创建发送端Socket对象
        InetAddress localHost = InetAddress.getLocalHost();
        Socket socket = new Socket(localHost, 8081);
        //2. 获取输出流
        OutputStream outputStream = socket.getOutputStream();
        //3. 写入数据
        outputStream.write("tcp Client msg".getBytes());
        //4. 释放资源
        outputStream.close();
        socket.close();
    }
}

6.5TCP接收端

  1. 创建接收端Socket对象:new ServerSocket(int port)
    • port:接收端端口号
  2. 监听(阻塞:如果建立连接失败,程序会一直阻塞,不往下执行):Soket soket = ServerSocket.accept()
  3. 获取输入流对象:socket.getInputStream()
  4. 获取数据:inputStream.read(bytes)
  5. 输出数据:new String(bytes, 0, len))
  6. 释放资源:ServerSocket.close()
package com.zhxd.test;
/*
 * author zhxd
 * ClassName TCPServer
 */

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {
    public static void main(String[] args) throws IOException {
        //1. 创建接收端socket对象
        ServerSocket serverSocket = new ServerSocket(8081);
        //2. 监听
        Socket socket = serverSocket.accept();
        //3. 获取输入流
        InputStream inputStream = socket.getInputStream();
        //4. 获取数据
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        //5. 输出数据
        System.out.println(new String(bytes,0 ,len));
        //6. 释放资源
        serverSocket.close();
        socket.close();
        inputStream.close();
    }
}

7.练习题:手写web服务器

package com.zhxd.test;
/*
 * author zhxd
 * ClassName HttpServer
 */

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        Socket socket = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        FileInputStream fileInputStream = null;
        // 创建服务ServerSocket
        serverSocket = new ServerSocket(80);
        while (true) {
            try {
                // 监听80端口
                socket = serverSocket.accept();
                // 获取请求的输入流
                inputStream = socket.getInputStream();
                // 获取响应输出流
                outputStream = socket.getOutputStream();

                //获取请求的地址
                byte[] reqbytes = new byte[1024];
                int reqLen = inputStream.read(reqbytes);
                String reqContent = new String(reqbytes, 0, reqLen);
                String url = reqContent.split("\r\n")[0].split(" ")[1];

                //读取文件
                File file = new File("./"+url);
                fileInputStream = new FileInputStream(file);
                byte[] bytes = new byte[20480];
                //从硬盘读取到内存中
                int respLen = fileInputStream.read(bytes);
                fileInputStream.close();
                //返回数据给客户端
                outputStream.write(bytes, 0, respLen);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                socket.close();
                inputStream.close();
                outputStream.close();
            }
        }
    }
}

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java之网络编程 的相关文章