Http协议

目录

一、web开发基础

1. C/S架构

2. B/S架构

(1)什么是web开发

(2)什么是B/S架构

二、Http协议原理

1. Http基本概念

2. Http请求格式

(1)请求行:

(2)请求头:

(3)请求体:

2. Http响应格式

(1)响应行:

(2)响应头:

(3)响应体:

3. Http响应状态码

三、 socket

1. 概述

2. 网络通讯三要素

3. IP地址和端口号码

四、 InetAddress

1. InetAddress类的常用方法

2. ipconfig 获取本机的ip地址

五、 dns域名解析

六、UDP协议

1.  什么是UDP

2. 发送数据

3. 接受数据

七、TCP协议

1. 三次握手

(1)客户端

  (2) 服务器端


一、web开发基础

1. C/S架构

服务器-客户机,即Client-Server(C/S)结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。

例如我们需要下载QQ、微信、电脑版吃鸡,如果该客户端软件需要升级,用户需要重新下载最新版本的客户端下载安装。

C(客户端Client)/S(Server)架构

C(客户端Client)/S(Server)架构 桌面应用程序

java swing 、 c#

下载对应的安装包

安装成功之后

才可以使用

2. B/S架构

(1)什么是web开发

Web:全球广域网,也称为万维网(www),也就是能够通过浏览器访问的网站

例如 通过浏览器访问 www.mayikt.com 、www.baidu.com、www.taobao.com。

JavaWeb开发:是使用java技术栈开发Web项目。

(2)什么是B/S架构

B/S架构的全称为Browser/Server,即浏览器/服务器结构,Browser指的是Web浏览器

它的特点是 客户端只需要安装浏览器,应用程序的逻辑和数据都存放在服务器端共享访问。

优点:易于维护升级:服务器端升级后,客户端(浏览器端无需升级)就获取最新的版本

静态web资源(如html 页面、js、css、images):指web页面中供人们浏览的数据始终是不变。

动态web资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同。

  静态web资源开发技术:Html js、css、images,所有用户访问后,得到的结果都是一样的,称为静态资源.静态资源可以直接被浏览器解析

  常用动态web资源开发技术:JSP/Servlet、ASP、PHP等,每个用户访问相同资源后,得到的结果可能不一样。称为动态资源。动态资源被访问后,需要先转换为静态资源,在返回给浏览器

  在Java中,动态web资源开发技术统称为Javaweb。

B/S体系架构的软件 版本升级的时候 客户端是无需升级的 只需要重新刷新网页即可。

缺陷:会占用服务器端带宽资源。

二、Http协议原理

1. Http基本概念

Hyper Text Transfer Protocol 超文本传输协议,基于HTTP传输协议(超文本传输协议)客户端与服务器端之间数据传输规则。

传输协议:定义了,客户端和服务器端通信时,发送数据的格式

HTTP特点:

(1)底层基于TCP协议实现 ,面向连接方式安全,默认端口号:80;

(2)基于请求(request)与响应(response)模型,一次请求对应一次响应

(3)Http协议是无状态协议,对于事务处理是没有任何记忆功能,每次请求之间相互独立,不能交互数据

(4)Http协议多次请求无法共享,在javaweb开发中我们可以通过cookie、session解决该问题

(5)http协议数据传输过程中 属于同步的过程;如果客户端发送请求达到服务器端,服务器端已经不响应 可能会导致 客户端会一直阻塞等待 对于用户体验是不好的 所以客户端发送请求达到服务器时会设置超时时间 例如5s。

2. Http请求格式

请求数据格式:

(1)请求行 请求方法(get、post)、url (/首页) http协议版本1.1版本 请求第一行

GET /front/showcoulist HTTP/1.1

(2)请求头 (键值对的形式)

Host: www.mayikt.com Connection: keep-alive Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://www.mayikt.com/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: __yjs_duid=1_92c8557b9791d34466e53ea75410e2c01649305342102; JSESSIONID=B303350E58BA0F1230E0B66A9ADCD35F; Hm_lvt_eaa952b8610db6f155ab0febd442e89a=1649305345,1649313679; Hm_lpvt_eaa952b8610db6f155ab0febd442e89a=1649316541

(3)请求体

(1)请求行:

    请求数据第一行

   1.1 由3部分组成,分别为:请求方法、URL 以及协议版本,之间由空格分隔

   1.2 请求方法包括GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE以及扩展方法,当然并不是所有的服务器都实现了所有的方法,部分方法即便支持,处于安全性的考虑也是不可用的

* HTTP协议有7中请求方式,常用的有2种
                * GET:
                    1. 请求参数在请求行中,在url后。
                    2. 请求的url长度有限制的
                    3. 不太安全
                * POST:
                    1. 请求参数在请求体中
                    2. 请求的url长度没有限制的
                    3. 相对安全

   1.3协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1

(2)请求头:

第二行开始,格式 key:value形式

Accept-Ranges: bytes

Access-Control-Allow-Origin: *

Access-Control-Expose-Headers: X-Log, X-Reqid

Access-Control-Max-Age: 2592000

常见http协议请求头

Host:接受请求的服务器地址,可以是IP端口号,也可以是域名

User-Agent:发送请求的应用程序名称,浏览器告诉服务器,我访问你使用的浏览器版本信息,可以在服务器端获取该头的信息,解决浏览器的兼容性问题

Referer:http://localhost/login.html
                * 告诉服务器,我(当前请求)从哪里来
                    * 作用:
                        1. 防盗链:
                        2. 统计工作:

Connection:指定与连接相关的属性,如Connection:Keep-Alive

Accept-Charset:通知服务端可以发送的编码格式

Accept-Encoding:通知服务端可以发送的数据压缩格式

Accept-Language:通知服务端可以发送的语言

(3)请求体:

post请求的最后一部分,存放发送请求的参数

userName=mayikt&age=26

测试html

<!DOCTYPE html>
<html>
<head>
<title>登录测试页面</title>
<form action="login.html" method="get">
<label>用户名: </label><input type="text" name="username" /><br>
<label>密&nbsp码&nbsp: </label><input type="password" name="password" /><br>
<input type="submit" value="登录 " />
</form>

</head>
</html>

2. Http响应格式

响应格式分为3个部分

(1)响应行:

    组成:协议/版本 响应状态码 状态码描述
               响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态, 状态码都是3位数字

(2)响应头:

第二行开始 格式 key value

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(服务端响应客户端的时间)

服务器端响应结果给客户端类型:

a.text/html;charset=UTF-8

b.image类型

(3)响应体:

存放服务器响应给客户端的内容

3. Http响应状态码

HTTP状态码说明

1xx(临时响应)

表示临时响应并需要请求者继续执行操作的状态代码。

100: (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。

101: (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。

2xx (成功)

200(成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。

201: (已创建) 请求成功并且服务器创建了新的资源。

202: (已接受) 服务器已接受请求,但尚未处理。

203: (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。

204: (无内容) 服务器成功处理了请求,但没有返回任何内容。

205: (重置内容) 服务器成功处理了请求,但没有返回任何内容。

206: (部分内容) 服务器成功处理了部分 GET 请求。

3xx (重定向)

表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。

300: (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。

301: (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。

302: (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

303: (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。

304: (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。

305: (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。

307: (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

4xx(请求错误,一般是客户端问题)

这些状态代码表示请求可能出错,妨碍了服务器的处理。

400: (错误请求) 服务器不理解请求的语法。

401: (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。

403: (禁止) 服务器拒绝请求。

404: (未找到) 服务器找不到请求的网页。(客户端发送请求达到服务器端地址填写错了)

405: (方法禁用) 禁用请求中指定的方法。

406: (不接受) 无法使用请求的内容特性响应请求的网页。

407: (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。

408: (请求超时) 服务器等候请求时发生超时。

409: (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。

410: (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。

411: (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。

412: (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。

413: (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。

414: (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。

415: (不支持的媒体类型) 请求的格式不受请求页面的支持。

416: (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。

417: (未满足期望值) 服务器未满足"期望"请求标头字段的要求。

5xx(服务器错误,一般是服务端问题)

这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

500: (服务器内部错误) 服务器遇到错误,无法完成请求。(服务器端 发生了错误)

501: (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。

502: (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。

503: (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。

504: (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。

505: (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

三、 socket

1. 概述

(1)计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程。例如我们的QQ聊天

(2)Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。

(3)Java提供的网络类库,可以实现网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。

2. 网络通讯三要素

    (1)IP:电子设备(计算机)在网络中的唯一标识。
    (2)端口:应用程序在计算机中的唯一标识。 0~65536
    (3)传输协议:规定了数据传输的规则
      基础协议:
            a. tcp:安全协议,三次握手。 速度稍慢
            b. udp:不安全协议。 速度快

(1)我们需要知道的是主机间通过网络进行通信是需要遵循网络通信协议,是通过IP地址准确定位主机,通过端口号准确定位主机上的应用,例如IP地址和端口号 192.168.110.1:80

(2)如何实现网络中的主机互相通信?

① 通信双方地址:IP和端口号

② 一定的规则协议。 tcp或者udp​

3. IP地址和端口号码

IP地址准确定位主机

(1)IP 地址:InetAddress(在Java中使用InetAddress类代表IP)

一的标识 Internet 上的计算机(通信实体)

(2)本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost

(3)IP地址分类方式1:IPV4 和 IPV6

         a. IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已 经用尽。以点分十进制表示,如192.168.0.1

         b. IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984

(4)IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168. 开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用

特点:不易记忆

端口号就是标识正在计算机上运行的进程(程序

不同的进程有不同的端口号

被规定为一个 16 位的整数 0~65535。

四、 InetAddress

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

1. InetAddress类的常用方法

方法声明

功能描述

InetAddress getByName(String host)

获取给定主机名的的IP地址,host参数表示指定主机

InetAddress getLocalHost()

获取本地主机地址

String getHostName()

获取本地IP地址的主机名

boolean isReachable(int timeout)

判断在限定时间内指定的IP地址是否可以访问

String getHostAddress()

获取字符串格式的原始IP地址

public class Test01 {
    public static void main(String[] args) throws UnknownHostException {
        // 获取给定主机名的的IP地址,host参数表示指定主机
        InetAddress hostAddress = InetAddress.getByName("DELL");//DELL/192.168.0.105
 InetAddress localhost = InetAddress.getLocalHost();
        System.out.println(localhost);//DELL/192.168.0.105
        
// 获取获取本地IP地址的主机名
        String hostName = inetAddress.getHostName();
        // 获取IP地址
        String address = inetAddress.getHostAddress();
        System.out.println("hostName:" + hostName);
        System.out.println("address:" + address);
    }
}

2. ipconfig 获取本机的ip地址

(1) 127.0.0.1 (电脑自己访问自己)

(2) localhost (电脑自己访问自己)

(3) 192.168.0.106 直接获取到局域网的ip (让别人访问电脑)​

五、 dns域名解析

hostName 主机名称 其实就是 域名

mayikt.com---域名

taobao.com---域名

localhost--域名 dns解析ip地址

为了方便记忆 我们会使用域名在通过dns解析成我们的ip地址。

C:\Windows\System32\drivers\etc 配置我们本地dns域名解析。

六、UDP协议

1.  什么是UDP

UDP协议 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法,俗称面向无连接

。通俗易懂讲解 UDP协议会把数据打包发送给目标地址, 这个数据包能不能发送给目标地址就不管了,所以我们的udp协议 它是不可靠协议、安全性低,容易丢包 但是速度非常快 无需类似于 tcp协议三次握手。

核心特点:面向无连接、不可靠的协议 、安全系数很低 容易丢包 但是传输速度是非常快 不需要类似于tcp协议三次握手。 聊天工具

2. 发送数据

(1)创建发送端socket对象;

(2)提供数据,并将数据封装到数据包中;

(3)通过socket服务的发送功能,将数据包发出去;

(4)释放资源;

在windows 操作系统中,C:\Windows\System32\drivers\etc\HOSTS 文件中 新增

127.0.0.1 test.mayikt.com

相关代码:

public class UdpClient {
    public static void main(String[] args) throws IOException {
        //1.创建发送端socket对象;
        DatagramSocket datagramSocket = new DatagramSocket();
        //2.提供数据,并将数据封装到数据包中;
        byte[] msg = "mayikt".getBytes();
        InetAddress inetAddress = InetAddress.getByName("test.mayikt.com");
        int port = 8848;
        DatagramPacket datagramPacket = new DatagramPacket(msg, msg.length, inetAddress, port);
        //3.通过socket服务的发送功能,将数据包发出去;
        datagramSocket.send(datagramPacket);
        //4.释放资源;
        datagramSocket.close();
    }
}

3. 接受数据

(1)创建接收端socket对象;

(2)接收数据;

(3)解析数据;

(4)输出数据;

(5)释放资源;

public class UdpServer {
    public static void main(String[] args) throws IOException {
        //创建接收端socket对象
        DatagramSocket datagramSocket = new DatagramSocket(8848);
        //接收数据;
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
        //解析数据;
        System.out.println("开始接受数据.");
        datagramSocket.receive(datagramPacket);
        System.out.println("接受到数据.");
        //输出数据;
        String msg = new String(datagramPacket.getData());
        System.out.println(msg);
        //释放资源;
        datagramSocket.close();

    }
}

练习题

使用udp协议 客户端可以一直发送数据给服务器端,服务器端可以一直接受到客户端发送的数据。

如果客户端输入 666 就会直接退出程序。

public class UdpClient {
    public static void main(String[] args) throws IOException {
        // 创建DatagramSocket发送者
        DatagramSocket ds =
                new DatagramSocket();
        // 创建Scanner
        while (true) {
            System.out.println("客户端:请输入发送的内容");
            Scanner sc = new Scanner(System.in);
            String context = sc.nextLine();
            if ("666".equals(context)) {
                System.out.println("退出程序...");
                break;
            }
            byte[] data = context.getBytes();
            // 封装数据包
            DatagramPacket dp =
                    new DatagramPacket(data, data.length, InetAddress.getByName("mayikt.server.com"), 8080);
            ds.send(dp);
            System.out.println("发送数据成功...");
        }
        ds.close();
    }
}
public class UdpServer {
    public static void main(String[] args) throws IOException {
        // 创建DatagramSocket接受
        DatagramSocket ds =
                new DatagramSocket(8080);
        // 创建Scanner
        while (true) {
            //2.接收数据
            byte[] bytes = new byte[1024];
            // 数据包的形式接受
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
            ds.receive(dp);
            System.out.println("服务器端接受到数据:" + new String(dp.getData()));
        }
//        ds.close();

    }
}

七、TCP协议

1. 三次握手

TCP是面向连接的可靠协议、通过三次握手建立连接,通讯完成时拆除连接

UDP是面向无连接通讯协议,udp通讯时不需要接受方确定,属于不可靠传输,可能会存在丢包的现象。

tcp协议 需要先经历三次握手成功之后 在将数据发送给服务器端 确保服务器端是在 在将数据

发送给服务器端。三次握手、四次挥手。

udp协议直接将数据发送给服务器端-----传输效率高 缺陷 没有验证服务器端

是否存在 如果不在的情况下 直接传输数据 可能丢失数据

数据连接池目的 tcp协议连接复用

jdbc

首先我们要知道在tcp建立连接中,有一些名词表示:

比如:syn就是建立连接、ack就是确认标志、fin终止标志

第一次握手:客户端会向服务器端发送码为syn=1,随机产生一个seq_number=x的数据包到服务器端 (syn)

第二次握手:服务端接受到客户端请求之后,确认ack=x+1, 于是就向客户端发送syn(服务端独立生成 随机生成数字Y)+ack

第三次握手:客户端接受syn+ack,向服务器端发送ack=y+1,此包发送完毕即可 建立tcp连接。

白话文翻译:

第一次握手:客户端向服务器端发送 问服务器你在不在?

第二次握手:服务器端回应客户端说:我在的。

第三次握手:客户端发送给服务器端:ok,那我开始建立连接的

关闭连接:

第一次挥手: 客户端向服务器端发送释放的报文,停止发送数据fin=1、生成一个序列号seq=u;

第二次挥手: 服务器端接受到释放的报文后,发送ack=u+1;随机生成的seq=v给客户端;当前状态为关闭等待状态

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

第三次挥手:服务器端最后数据发送完毕之后,就向客户端发送连接释放报文,FIN=1,ack=u+1 当前为半关闭状态,随机生成一个随机树w

第四次挥手,客户端必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

白话文翻译四次挥手:

第一次挥手 客户端向服务端发送一个释放连接通知;

第二次挥手 服务端接受到释放通知之后,告诉给客户端说等待一下,因为可能存在有其他的数据没有发送完毕,等待数据全部传输完毕之后就开始 关闭连接;

第三次挥手 服务器端所有的数据发送完毕之后,就告诉客户端说现在可以释放连接了。

第四次挥手: 客户端确认是最终释放连接通知,ok 就开始 就向服务区端发送我们可以开始关闭连接啦;

(1)客户端

a.创建发送端Socket对象(创建连接)

b.获取输出流对象;

c.发送数据;

d.释放资源;

public class TcpClient {
    public static void main(String[] args) throws IOException {
        //创建socket连接Socket
        Socket s = new Socket(InetAddress.getByName("mayikt.server.com"), 8090);
        //获取数据流对象
        OutputStream outputStream = s.getOutputStream();
        String data = "mayikt tcp";
        // 写入数据
        outputStream.write(data.getBytes());
        // 关闭资源
        outputStream.close();
        s.close();
    }
}

(2) 服务器端

a.创建接收端Socket对象;

b.监听(阻塞:如果建立连接失败,程序会一直阻塞,不往下执行;

c.获取输入流对象;

d.获取数据;

e.输出数据;

f.释放资源;

public class TcpServer {
    public static void main(String[] args) throws IOException {
        // 创建serverSocket
        ServerSocket serverSocket = new ServerSocket(8090);
        // 监听客户端数据
        Socket socket = serverSocket.accept();
        // 获取到客户端发送的数据
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        System.out.println("客户端发送的数据:" + new String(bytes, 0, len));
        // 关闭资源
        inputStream.close();
        serverSocket.close();

    }
}

Exception in thread "main" java.net.ConnectException: Connection refused: connect

at java.net.DualStackPlainSocketImpl.connect0(Native Method)

at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:75)

at java.net.AbstractPlainSocketImpl

客户端连接不上服务器端 javaweb开发 http协议 底层就是基于 tcp协议封装

tomcat 报错:Connection refused: connect

原因:

          ip 访问不同

          防火墙没有关闭

          或者 只能够在局域网访问

练习题1

使用tcp协议 客户端可以一直发送数据给服务器端,服务器端可以一直接受到客户端发送的数据。

如果客户端输入 666 就会直接退出程序。

服务器端代码:

public class TcpServer {
    public static void main(String[] args) throws IOException {
        // 创建serversocket对象
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务器端启动成功....");
        while (true) {
            // 接受客户端数据
            Socket socket = serverSocket.accept();
            //inputStream
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = inputStream.read(bytes);
            System.out.println("服务器端接受客户端:" + new String(bytes, 0, len));
            // 服务端响应数据给客户端
            OutputStream outputStream = socket.getOutputStream();
            String resp = "我收到啦" + UUID.randomUUID().toString();
            outputStream.write(resp.getBytes());
            inputStream.close();
            outputStream.close();
            socket.close();
        }
    }
}

客户端代码:

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

        while (true) {
            // 创建socket对象
            Socket socket = new Socket("127.0.0.1", 8080);
            System.out.println("客户端:请输入发送数据的内容");
            Scanner sc = new Scanner(System.in);
            String context = sc.nextLine();
            if (context.equals("666")) {
                break;// 退出循环
            }
            // 获取getOutputStream
            OutputStream outputStream = socket.getOutputStream();
            // 写入数据给服务器端
            outputStream.write(context.getBytes());
            // 接受服务器端响应的内容
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = inputStream.read(bytes);
            System.out.println("服务端响应数据给客户端:" + new String(bytes, 0, len));
            outputStream.close();
            socket.close();
        }

    }
}

改造成多线程方式:


练习题2

使用tcp协议 实现登录

tcp服务器端代码

public class TcpServer {
    public static void main(String[] args) throws IOException {
        // 服务器端可以一直接受 客户端数据
        // 创建监听端口号码 ServerSocket
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务器端启动成功...");
        while (true) {
            // 监听客户端发送过来的数据注意  我们的客户端没有发送数据给服务器端 该方法就会在这里一直阻塞
            Socket socket = serverSocket.accept();
            //不允许单独new线程 线程池来维护线程----java进阶
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 接受客户端数据
                        InputStream inputStream = socket.getInputStream();
                        byte[] bytes = new byte[1024];
                        int len = inputStream.read(bytes);
                        // userName=mayikt&userPwd=123456
                        String text = new String(bytes, 0, len);
                        String[] split = text.split("&");
                        String userName = split[0].split("=")[1];
                        String userPwd = split[1].split("=")[1];
                        // 回应数据给客户端
                        OutputStream outputStream = socket.getOutputStream();
                        if (("mayikt".equals(userName) && "123456".equals(userPwd))) {
                            outputStream.write("ok".getBytes());
                        } else {
                            outputStream.write("fails".getBytes());
                        }
                        // 关闭资源
                        inputStream.close();
                        socket.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

tcp客户端代码

public class TcpClient {
    public static void main(String[] args) throws IOException {
        // 客户端是可以一直发送数据给服务器端
        while (true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户的名称:");
            String userName = sc.nextLine();
            System.out.println("请输入用户的密码:");
            String userPwd = sc.nextLine();
            Socket socket = new Socket("127.0.0.1", 8080);
            // 获取到我们的outputStream
            OutputStream outputStream = socket.getOutputStream();
            // 发送数据
            String text = "userName=" + userName + "&userPwd=" + userPwd;
            outputStream.write(text.getBytes());
            // 接受服务器端响应数据给客户端
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = inputStream.read(bytes);
            String resp = new String(bytes, 0, len
            );
            if ("ok".equals(resp)) {
                System.out.println("登录成功");
            } else {
                System.out.println("登录失败");
            }

            // 关闭资源
            outputStream.close();
            socket.close();
        }
    }
}

练习题3

使用tcp协议 web服务器

public class HttpTcpServer {
    public static void main(String[] args) throws IOException {
        // 服务器端可以一直接受 客户端数据
        // 创建监听端口号码 ServerSocket
        ServerSocket serverSocket = new ServerSocket(80);
        System.out.println("服务器端启动成功...");
        while (true) {
            // 监听客户端发送过来的数据注意  我们的客户端没有发送数据给服务器端 该方法就会在这里一直阻塞
            Socket socket = serverSocket.accept();
            //不允许单独new线程 线程池来维护线程----java进阶
            new Thread(new Runnable() {
                @Override
                public void run() {
                    InputStream inputStream = null;
                    OutputStream outputStream = null;
                    try {
                        // 获取请求地址
                        byte[] reqByte = new byte[1024];
                        inputStream = socket.getInputStream();
                        outputStream = socket.getOutputStream();
                        int reqLen = inputStream.read(reqByte);
                        String reqUrl = new String(reqByte, 0, reqLen);
                        String url = reqUrl.split("\r\n")[0].split(" ")[1];
                        File file = new File("D:\\mayikt\\html" + url);
                        byte[] bytes = new byte[20480];
                        FileInputStream fileInputStream = new FileInputStream(file);
                        //从硬盘中读取数据到内存中
                        int len = fileInputStream.read(bytes);
                        //返回数据给浏览器
                        outputStream.write(bytes, 0, len);
                    } catch (Exception e) {
                        e.printStackTrace();
                        if (outputStream != null) {
                            try {
                                outputStream.write("404".getBytes());
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                        }
                    } finally {
                        // 关闭资源
                        try {
                            outputStream.close();
                            inputStream.close();
                            socket.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值