网络编程基础

1.概述

邮件:

在这里插入图片描述

  • 计算机网络: 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统网络管理软件网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
  • 网络编程的目的:无线电台…传播交流信息,数据交换,通信。
  • 想要达到这个效果需要什么:
    1. 如何让准确的定位网络上的一台主机 192.168.16.124:端口, 定位上这个计算机上的某个资源。
    2. 找到了这个主机,如何传输数据呢?
  • Javaweb:网页编程 、 B/S架构
  • 网络编程:TCP/IP 、 C/S

2.网络通信要素

如何实现网络的通信?

  • 通信双方的地址:
    • ip:192.168.16.124
    • 端口:5900
  • 规则:网络通信的协议:TCP/IP

在这里插入图片描述

网络模型是描述计算机网络结构和通信方式的抽象概念,通常分为七层。这个模型被称为 OSI(Open Systems Interconnection)模型,它是国际标准化组织(ISO)制定的一个通信系统的标准框架。另一个常用的网络模型是 TCP/IP 模型,它是因特网所采用的网络模型,相对于 OSI 模型而言更加简洁。

  1. OSI 模型
  • 物理层(Physical Layer):负责定义物理介质的传输方式,如电缆、光纤等,以及规定了数据传输的基本单位比特。

  • 数据链路层(Data Link Layer):负责在物理介质上传输数据帧,提供了数据的可靠传输和错误检测功能。包括了MAC子层和LLC子层。

  • 网络层(Network Layer):负责进行数据的路由选择和分组转发,提供了网络互连的功能,以及实现了逻辑地址的分配与转换,如IP地址。

  • 传输层(Transport Layer):负责为应用程序提供端到端的可靠数据传输服务,包括了面向连接的TCP协议和无连接的UDP协议。

  • 会话层(Session Layer):负责建立、管理和终止会话连接,提供了数据交换的全双工或者半双工通信功能。

  • 表示层(Presentation Layer):负责数据的格式转换、加密解密、数据压缩等功能,以便不同系统之间的数据交换。

  • 应用层(Application Layer):负责提供特定的网络应用服务,如HTTP、FTP、SMTP等,为用户提供了网络通信的接口。

  1. TCP/IP 模型
  • 应用层:包含了 OSI 模型中的应用层、表示层和会话层的功能,提供了各种应用服务。

  • 传输层:对应 OSI 模型的传输层,提供了端到端的数据传输服务,包括 TCP 和 UDP。

  • 网络层:对应 OSI 模型的网络层,负责进行数据的路由选择和分组转发,实现了 IP 协议。

  • 链路层:对应 OSI 模型的数据链路层和物理层,负责将数据帧发送到物理介质上,包括了 MAC 和物理层的功能。

小结:

  1. 网络编程中有两个主要的问题:
  • 如何让准确的定位到网络上的一台或多台主机;
  • 找到主机之后如何通信;
  1. 网络编程中的要素:
  • IP和端口号:IP
  • 网络通信协议:UDP、TCP
  1. 万物皆对象

3.IP

IP 地址:InetAddress

  • 唯一定位一台网络上的计算机

  • 127.0.0.1: 本机localhost

  • ip地址的父类

    • IPV4: 127.0.0.1 ,4个字节组成。,0~255, 42亿~;30亿都在北美,亚洲4亿。2011年就用尽;
    • IPV6: fe80::f0e0:7383:ad8e:f32f%3 ,128位。8个无符号整数

    "IP"通常指的是Internet Protocol(互联网协议),它是因特网中最为重要的协议之一。IPv4(Internet Protocol version 4)和IPv6(Internet Protocol version 6)是两个主要的IP协议版本。

    1. IPv4
    • IPv4是因特网广泛采用的第四版Internet协议,它使用32位地址来标识网络上的每个设备。
    • IPv4地址通常以点分十进制表示,如192.168.0.1。
    • 由于IPv4地址空间有限(约42亿个地址),导致IPv4地址短缺,这促使了IPv6的发展和部署。
    1. IPv6
    • IPv6是IPv4的后继者,它采用128位地址空间,提供了远远超过IPv4的地址数量。
    • IPv6地址通常以冒号分隔的八个16进制块表示,例如2001:0db8:85a3:0000:0000:8a2e:0370:7334。
    • IPv6不仅解决了IPv4地址短缺的问题,还提供了更好的安全性、自动配置、移动性支持等特性。
    2406:da18:ddf:4000:67d5:b226:cad7:125b
    
  • 公网(互联网)–私网(局域网)

    1. 公网(互联网)
    • 公网是指连接在全球范围内的网络,即互联网。它是通过各种网络提供商(ISP)和其他服务提供商相互连接而形成的。
    • 公网是开放的,任何人都可以通过适当的访问权限访问其中的资源。这意味着公网上的资源可以被全世界的用户访问。
    • 公网IP地址是全球唯一的,并且用于标识设备在全球范围内的位置。
    1. 私网(局域网)
    • 私网是指在特定地理范围内的局域网络,如家庭、公司或组织内部的网络。它通常由路由器、交换机和其他设备连接在一起,形成一个封闭的网络环境。
    • 私网的特点是受限访问,只有局域网内的设备可以相互通信和访问资源,外部设备无法直接访问。
    • 私网通常使用专用IP地址范围(例如IPv4的192.168.x.x、172.16.x.x - 172.31.x.x、10.x.x.x等)来标识网络中的设备。

    在实际应用中,公网和私网常常是相互连接的。例如,一个公司可能拥有一个私有的局域网用于内部通信和资源共享,同时通过路由器连接到互联网,使员工可以访问外部资源和服务。这种连接可以通过网络地址转换(NAT)等技术来实现,从而在私有网络和公共网络之间进行通信。

    • ABCD地址

      IP地址的分类指的是根据地址的前几位来划分IP地址范围的一种方式,主要用于IPv4地址空间。根据这种分类,IP地址可以分为五个主要的类别,通常用字母 A、B、C、D、E 来表示,每个类别有不同的地址范围和用途:

      1. A类地址
      • A类地址范围是从1.0.0.0到126.0.0.0。
      • A类地址的第一个字节(8位)用于网络标识,剩余的三个字节(24位)用于主机标识。
      • A类地址的网络号范围从1.0.0.0到126.0.0.0,可以支持最多约1677万个主机,适用于大型网络。
      1. B类地址
      • B类地址范围是从128.0.0.0到191.255.0.0。
      • B类地址的前两个字节(16位)用于网络标识,剩余的两个字节(16位)用于主机标识。
      • B类地址的网络号范围从128.0.0.0到191.255.0.0,可以支持最多约6.5万个主机,适用于中型网络。
      1. C类地址
      • C类地址范围是从192.0.0.0到223.255.255.0。
      • C类地址的前三个字节(24位)用于网络标识,剩余的一个字节(8位)用于主机标识。
      • C类地址的网络号范围从192.0.0.0到223.255.255.0,可以支持最多约254个主机,适用于小型网络。
      1. D类地址
      • D类地址范围是从224.0.0.0到239.255.255.255。
      • D类地址用于多播(Multicast)通信,它们被用于一次性传送数据到多个目的地。
      1. E类地址
      • E类地址范围是从240.0.0.0到255.255.255.255。
      • E类地址是保留地址,用于将来的实验和发展。

      这些地址分类的划分方式是为了更有效地管理和分配IP地址,但随着IPv4地址空间的枯竭,CIDR(Classless Inter-Domain Routing,无类域间路由)和NAT(Network Address Translation,网络地址转换)等技术的广泛应用,IP地址分类的重要性已经大大降低

    • 192.168.xx.xx,专门给组织内部使用。

  • 域名:记忆IP问题!

    • IP:www.vip.com
Code (non-static method)Feature
byte[] getAddress()返回ip地址对应的字节数组
String getHostAddress()字符串形式返回主机ip地址
String getHostName()返回主机的主机名,或者如果该 IP 地址没有关联的主机名,则返回 IP 地址的字符串表示形式
String getCanonicalHostName()返回规范化的主机名,即通过 DNS 解析获得的完全限定域名(FQDN)
Code (static method)FeatureExample
getLocalHost()返回本地主机的 InetAddress 对象InetAddress localHost = InetAddress.getLocalHost();
getByName(String host)根据主机名或 IP 地址字符串获取对应的 InetAddress 对象InetAddress address = InetAddress.getByName(“www.example.com”);
getAllByName(String host)返回与指定主机名关联的所有 InetAddress 对象的数组InetAddress[] addresses = InetAddress.getAllByName(“www.example.com”);
getByAddress(byte[] addr)根据原始的 IP 地址字节数组获取对应的 InetAddress 对象byte[] ipAddress = {127, 0, 0, 1};

InetAddress localhost = InetAddress.getByAddress(ipAddress);
getByAddress(String host, byte[] addr)根据主机名和原始的 IP 地址字节数组获取对应的 InetAddress 对象。这个方法可以用于解析 IPv4 和 IPv6 地址。byte[] ipAddress = {127, 0, 0, 1};

InetAddress localhost = InetAddress.getByAddress(“localhost”, ipAddress);
package com.fatfish;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

/**
 * @author fatfish
 * @version 1.0
 * @date 2024/6/6 20:15
 */
public class InetAddressDemo {
    public static void main(String[] args) throws UnknownHostException {
        System.out.println("====================静态方法====================");
        // getLocalHost()
        InetAddress inetAddress = InetAddress.getLocalHost();
        System.out.println("InetAddress.getLocalHost(): " + inetAddress);

        // getByName(String host)
        inetAddress = InetAddress.getByName("127.0.0.1");
        System.out.println("InetAddress.getByName(\"127.0.0.1\"): " + inetAddress);

        inetAddress = InetAddress.getByName("localhost");
        System.out.println("InetAddress.getByName(\"localhost\"): " + inetAddress);

        // getAllByName(String host)
        InetAddress[] inetAddresses = InetAddress.getAllByName("www.baidu.com");
        System.out.println("InetAddress.getAllByName(\"www.baidu.com\"): \n" + Arrays.toString(inetAddresses));

        // getByAddress(byte[] addr)
        inetAddress = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
        System.out.println("InetAddress.getByAddress(new byte[]{127, 0, 0, 1}): " + inetAddress);

        // getByAddress(String host, byte[] addr)
        inetAddress = InetAddress.getByAddress("localhost", new byte[]{127, 0, 0, 1});
        System.out.println("InetAddress.getByAddress(\"localhost\", new byte[]{127, 0, 0, 1}): " + inetAddress);

        System.out.println("====================非静态方法====================");
        // getAddress()
        byte[] address = inetAddress.getAddress();
        System.out.println("inetAddress.getAddress(): \n" + Arrays.toString(address));

        // getCanonicalHostName()
        String canonicalHostName = inetAddress.getCanonicalHostName();
        System.out.println("inetAddress.getCanonicalHostName(): " + canonicalHostName);

        // inetAddress.getHostName()
        String hostName = inetAddress.getHostName();
        System.out.println("inetAddress.getHostName(): " + hostName);

        // inetAddress.getHostAddress()
        String hostAddress = inetAddress.getHostAddress();
        System.out.println("inetAddress.getHostAddress(): " + hostAddress);
    }
}
====================静态方法====================
InetAddress.getLocalHost(): fatfish/100.80.xxx.xxx
InetAddress.getByName("127.0.0.1"): /127.0.0.1
InetAddress.getByName("localhost"): localhost/127.0.0.1
InetAddress.getAllByName("www.baidu.com"): 
[www.baidu.com/182.61.200.6, www.baidu.com/182.61.200.7]
InetAddress.getByAddress(new byte[]{127, 0, 0, 1}): /127.0.0.1
InetAddress.getByAddress("localhost", new byte[]{127, 0, 0, 1}): localhost/127.0.0.1
====================非静态方法====================
inetAddress.getAddress(): 
[127, 0, 0, 1]
inetAddress.getCanonicalHostName(): eureka7001.com
inetAddress.getHostName(): localhost
inetAddress.getHostAddress(): 127.0.0.1

进程已结束,退出代码 0

4. 端口

在计算机网络中,端口是用于标识应用程序或服务的通信终点。它们是网络通信中的逻辑构造,允许多个应用程序在同一设备上共享网络连接。每个端口都与一个特定的数字关联,称为端口号,范围从0到65535。

以下是端口的一些重要特点和用途:

  1. 端口分类
  • 系统端口(Well-known ports):范围从0到1023,这些端口通常被标准化协议或常用服务所使用,例如:HTTP(端口80)、HTTPS(端口443)、FTP(端口21)、SSH(端口22)等。

  • 注册端口(Registered ports):范围从1024到49151,这些端口用于自定义服务或应用程序。

    • Tomcat:8080

    • MySql:3306

    • Oracle:1521

  • 动态/私有端口(Dynamic/private ports):范围从49152到65535,通常由客户端应用程序动态分配,用于临时通信。

    在这里插入图片描述

  1. 端口与IP地址结合使用
  • 在TCP/IP协议中,通信的两端由IP地址和端口号组合确定。这样,可以通过IP地址和端口号将数据准确地传送到正确的应用程序或服务。
  • 一个网络连接由源IP地址、源端口、目标IP地址和目标端口组成。
  1. 端口的用途
  • 应用标识:端口号用于唯一标识运行在设备上的应用程序或服务。
  • 多路复用:允许多个应用程序在同一设备上共享网络连接。
  • 通信目标:确定数据包应该传递到哪个应用程序或服务。
  1. 通信协议
  • 在TCP/IP协议中,TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种常见的传输协议。TCP提供可靠的、面向连接的通信,而UDP提供无连接的通信。
  1. 安全性
  • 端口的安全性是网络安全的一个重要方面。开放不必要的端口可能会增加系统受攻击的风险。因此,管理员通常会关闭不需要的端口,并对公开服务的端口进行安全配置。
netstat -ano #查看所有的端口
netstat -nao|findstr "7808" #查看指定的端口
tasklist|findstr "8696"

在这里插入图片描述

package com.fatfish;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

/**
 * @author fatfish
 * @version 1.0
 * @date 2024/6/6 20:45
 */
public class InetSocketAddressDemo {
    public static void main(String[] args) throws UnknownHostException {
        // 基于主机名来创建 InetSocketAddress,可能需要进行 DNS 解析
        InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1", 8080);
        InetSocketAddress inetSocketAddress3 = new InetSocketAddress("localhost", 8080);
        // 直接使用本地主机的 IP 地址创建 InetSocketAddress,省略了主机名解析的过程
        InetSocketAddress inetSocketAddress2 = new InetSocketAddress(InetAddress.getLocalHost(), 8080);
        System.out.println("new InetSocketAddress(\"127.0.0.1\", 8080): " + inetSocketAddress1);
        System.out.println("new InetSocketAddress(\"localhost\", 8080): " + inetSocketAddress3);
        System.out.println("new InetSocketAddress(InetAddress.getLocalHost(), 8080): " + inetSocketAddress2);

        System.out.println("inetSocketAddress1.getAddress(): " + inetSocketAddress1.getAddress());
        System.out.println("inetSocketAddress1.getHostName(): " + inetSocketAddress1.getHostName());
        System.out.println("inetSocketAddress1.getPort(): " + inetSocketAddress1.getPort());
    }
}
new InetSocketAddress("127.0.0.1", 8080): /127.0.0.1:8080
new InetSocketAddress("localhost", 8080): localhost/127.0.0.1:8080
new InetSocketAddress(InetAddress.getLocalHost(), 8080): fatfish/100.80.xxx.xxx:8080
inetSocketAddress1.getAddress(): /127.0.0.1
inetSocketAddress1.getHostName(): eureka7001.com
inetSocketAddress1.getPort(): 8080

在这里插入图片描述

5.通信协议

协议:约定,就好比中国人交流说的是普通话

网络通信协议: 速率,传输码率,代码结构,传输控制…

问题:非常的复杂

大事化小:分层

TCP/IP协议簇:实际上是一组协议

重要:

  • TCP:用户传输协议
  • UDP:用户数据报协议

出名的协议:

  • TCP:
  • IP:网络互联协议

在这里插入图片描述

TCP UDP 对比

  • TCP:打电话

    • 连接,稳定

    • 三次握手,四次挥手

      最少需要三次,保证稳定连接!
      A:你瞅啥?
      B:瞅你咋地?
      A:干一场
      
      A:我要分手了
      B:我知道你要分手了
      B:你真的要分手吗?
      A:我真的要分手了
      
    • 客户端、服务器

    • 传输完成,释放连接,效率低

  • UDP;发短信

    • 不连接,不稳定
    • 客户端、服务端:没有明确的解现
    • 不管有没有准备好,都可以发给你
    • DDOS:洪水攻击! 发垃圾包 堵塞线路 (饱和攻击)
  • HTTPS

    HTTPS(Hypertext Transfer Protocol Secure)是一种基于HTTP的通信协议,通过SSL/TLS加密协议在HTTP的基础上进行了加密和认证,用于安全地传输数据。HTTPS的主要目的是确保网络通信的安全性和隐私保护,防止数据在传输过程中被窃听、篡改或伪造。

    以下是HTTPS的一些关键特点和工作原理:

    1. 加密传输:HTTPS使用SSL/TLS协议对传输的数据进行加密,使得第三方无法窃听或窥视通信内容。这种加密保证了敏感信息(如登录凭据、信用卡信息等)在传输过程中的安全性。

    2. 身份验证:HTTPS使用SSL/TLS证书对服务器和客户端进行身份验证,确保通信双方的真实性和合法性。服务器必须通过数字证书来证明其身份,客户端可以验证服务器证书的合法性。

    3. 数据完整性:HTTPS使用加密哈希算法(如SHA)来确保传输的数据在传输过程中未被篡改或损坏。接收方可以通过验证数据的哈希值来确认数据的完整性。

    4. HTTPS连接的建立过程

    5. 客户端发送请求:客户端(如浏览器)向服务器发送一个连接请求,请求建立安全连接。

    6. 服务器返回证书:服务器收到客户端的连接请求后,会将自己的SSL/TLS数字证书发送给客户端。该证书包含了服务器的公钥、服务器的域名(或IP地址)、证书的颁发者(CA,Certificate Authority)等信息。

    7. 客户端验证证书:客户端接收到服务器发送的证书后,会进行证书验证,以确保其合法性和有效性。验证包括:

    - 验证证书的有效性:检查证书的签名是否有效、证书是否在有效期内等。
    - 验证证书的颁发者:客户端检查证书颁发者的信任链,确保证书颁发者是一个受信任的CA机构。
    - 验证证书中的域名(或IP地址):确保证书中包含的域名(或IP地址)与客户端正在访问的域名(或IP地址)匹配,防止中间人攻击(Man-in-the-Middle)。
    
    1. 客户端生成密钥:如果服务器的证书验证通过,客户端会生成一个随机的对称密钥(Session Key),用于加密通信内容。

    2. 客户端使用服务器的公钥加密密钥:客户端使用服务器证书中包含的公钥对生成的对称密钥进行加密,然后将加密后的密钥发送给服务器。

    3. 服务器解密密钥:服务器收到客户端发送的加密密钥后,使用自己的私钥(在服务器证书对应的密钥对中)解密该密钥。

    4. 建立加密通道:客户端和服务器使用双方共同生成的对称密钥作为加密算法的密钥,建立一个安全的通信通道,用于后续的数据传输。

    5. 安全通道建立完成:至此,客户端和服务器建立了一个安全的HTTPS连接,可以开始进行加密的数据传输。

    6. HTTPS性能影响:由于加密和解密过程需要消耗计算资源,HTTPS通信相对于HTTP会稍微增加一些延迟和性能开销。但随着计算能力的提升和SSL/TLS协议的优化,HTTPS的性能影响已经大大降低。

HTTPS 连接过程

1. http通信存在的问题

  • 容易被监听
    http通信都是明文,数据在客户端与服务器通信过程中,任何一点都可能被劫持。比如,发送了银行卡号和密码,hacker劫取到数据,就能看到卡号和密码,这是很危险的

  • 被伪装
    http通信时,无法保证通行双方是合法的,通信方可能是伪装的。比如你请求www.taobao.com,你怎么知道返回的数据就是来自淘宝,中间人可能返回数据伪装成淘宝。

  • 被篡改
    hacker中间篡改数据后,接收方并不知道数据已经被更改

2. 共享密钥加密(对称加密)和公开密钥加密(非对称加密)

  • 共享密钥加密(对称加密)
    共享密钥的加密密钥和解密密钥是相同的,所以又称为对称密钥

  • 公开密钥加密(非对称加密)
    加密算法是公开的,密钥是保密的。公开密钥分为私有密钥和公有密钥,公有密钥是公开的,任何人(客户端)都可以获取,客户端使用公有密钥加密数据,服务端用私有密钥解密数据。

  • 异同
    共享密钥加密与公开密钥加密相比,加解密处理速度快,但公开密钥更适应互联网下使用

3. https解决的问题

https很好的解决了http的三个缺点(被监听、被篡改、被伪装),https不是一种新的协议,它是http+SSL(TLS)的结合体,SSL是一种独立协议,所以其它协议比如smtp等也可以跟ssl结合。https改变了通信方式,它由以前的http----->tcp,改为http------>SSL----->tcp;https采用了共享密钥加密+公开密钥加密的方式

  • 防监听
    数据是加密的,所以监听得到的数据是密文,hacker看不懂。

  • 防伪装
    伪装分为客户端伪装和服务器伪装,通信双方携带证书,证书相当于身份证,有证书就认为合法,没有证书就认为非法,证书由第三方颁布,很难伪造

  • 防篡改
    https对数据做了摘要,篡改数据会被感知到。hacker即使从中改了数据也白搭。

4. https连接过程

这里写图片描述

  • 客户端发送请求到服务器端

  • 服务器端返回证书和公开密钥,公开密钥作为证书的一部分而存在

  • 客户端验证证书和公开密钥的有效性,如果有效,则生成共享密钥并使用公开密钥加密发送到服务器端

  • 服务器端使用私有密钥解密数据,并使用收到的共享密钥加密数据,发送到客户端

  • 客户端使用共享密钥解密数据

  • SSL加密建立…

5. 客户端认证的通信的过程

  • 客户端需要认证的过程跟服务器端需要认证的过程基本相同,并且少了最开始的两步。这种情况都是证书存储在客户端,并且应用场景比较少,一般金融才使用,比如支付宝、银行客户端都需要安装证书

6. 连接过程结合了对称加密和非对称加密

HTTPS(Hypertext Transfer Protocol Secure)连接过程结合了对称加密和非对称加密,以确保通信的安全性和隐私保护。

  1. 非对称加密
  • 在HTTPS连接的初始阶段,服务器使用非对称加密来验证自己的身份,并协商一个用于后续通信的对称密钥。
  • 服务器会将自己的公钥发送给客户端,客户端使用这个公钥来加密一个随机生成的对称密钥,并发送给服务器。
  • 这个对称密钥只能由服务器的私钥来解密,因此只有服务器能够获取到这个对称密钥。
  1. 对称加密
  • 一旦服务器收到客户端发来的加密的对称密钥,服务器和客户端之间的通信将使用这个对称密钥来进行加密和解密。
  • 对称加密在这里被用于实际的数据传输过程中,因为对称加密速度快,适合加密大量的数据。

通过这种结合使用对称加密和非对称加密的方式,HTTPS既能确保通信的安全性,又能保持较高的性能。非对称加密用于安全地协商对称密钥,而对称加密用于实际的数据传输,结合了两者的优势。这种组合提供了一种安全可靠的方式来进行加密通信,保护了用户的隐私和数据安全。

6.TCP

先启动服务端,再启动客户端!!!!

在 Java 网络编程中,SocketServerSocket 是两个不同的类,分别用于实现客户端和服务器端的套接字通信。

  1. Socket(客户端)
  • Socket 类用于在客户端创建一个套接字,并通过该套接字与服务器进行通信。
  • 客户端使用 Socket 来连接服务器,并发送和接收数据。
  • 适用场景:用于客户端应用程序,例如浏览器、聊天客户端等。
  1. ServerSocket(服务器端)
  • ServerSocket 类用于在服务器端创建一个服务器套接字,用于监听客户端的连接请求。
  • 服务器端使用 ServerSocket 来监听指定端口,接受客户端连接,并创建相应的 Socket 与客户端进行通信。
  • 适用场景:用于服务器端应用程序,例如 Web 服务器、聊天服务器等。

Socket 类是 Java 中用于实现客户端和服务器之间通信的基础类之一。它提供了对网络上另一个套接字的连接,并进行数据传输的能力。以下是一些 Socket 类的常用方法和一般用法:

  1. 构造函数
  • Socket(String host, int port):使用指定的主机名和端口号创建一个套接字。

  • Socket(InetAddress address, int port):使用指定的 IP 地址和端口号创建一个套接字。

  • 示例:

    java

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

  1. 连接和关闭
  • connect(SocketAddress endpoint):连接到指定的端点(服务器)。

  • close():关闭套接字连接。

  • 示例:

    java

    socket.connect(new InetSocketAddress("localhost", 8080)); socket.close();

  1. 数据传输
  • getInputStream():获取套接字的输入流,用于从套接字读取数据。

  • getOutputStream():获取套接字的输出流,用于将数据写入套接字。

  • 示例:

    java

    InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream();

  1. 发送和接收数据
  • write(byte[] b):将字节数组写入套接字的输出流。

  • read(byte[] b):从套接字的输入流读取数据到字节数组。

  • 示例:

    java

    outputStream.write("Hello, Server!".getBytes()); byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer);

  1. 其他方法
  • isConnected():检查套接字是否连接到远程主机。
  • isClosed():检查套接字是否已关闭。
  • getLocalSocketAddress():获取本地套接字地址。
  • getRemoteSocketAddress():获取远程套接字地址。
  • setSoTimeout(int timeout):设置套接字的读取超时时间。
  • setKeepAlive(boolean on):设置套接字的 keep-alive 属性。
  • 等等…

ServerSocket 类是 Java 中用于创建服务器端套接字的类,它用于监听客户端连接请求并创建对应的 Socket 实例以进行通信。以下是一些 ServerSocket 类的常用方法和一般用法:

  1. 构造函数
  • ServerSocket(int port):创建一个绑定到指定端口的服务器套接字。

  • ServerSocket(int port, int backlog):创建一个绑定到指定端口的服务器套接字,并指定连接请求的队列长度。

  • ServerSocket(int port, int backlog, InetAddress bindAddr):创建一个绑定到指定端口和 IP 地址的服务器套接字,并指定连接请求的队列长度。

  • 示例:

    java

    ServerSocket serverSocket = new ServerSocket(8080);

  1. 接受客户端连接
  • accept():监听并接受客户端的连接请求。当有客户端连接请求到达时,此方法会返回一个新的 Socket 实例,用于与客户端进行通信。

  • 示例:

    java

    Socket clientSocket = serverSocket.accept();

  1. 关闭服务器套接字
  • close():关闭服务器套接字。调用此方法后,将不再接受新的客户端连接请求。

  • 示例:

    java

    serverSocket.close();

  1. 其他方法
  • getLocalPort():获取服务器套接字绑定的端口号。
  • getInetAddress():获取服务器套接字绑定的 IP 地址。
  • setSoTimeout(int timeout):设置服务器套接字的 accept() 方法的超时时间。
  • getSoTimeout():获取服务器套接字的 accept() 方法的超时时间。
  • 等等…

客户端

  • 连接服务器 Socket
  • 发送消息
package github.Web.Demo02;

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

/** * @author subeiLY * @create 2021-06-06 11:08 */
// 客户端
public class TCPClientDemo01 {
    public static void main(String[] args) {
        Socket accept = null;
        OutputStream os = null;

        try {
            // 1.要知道服务器的地址
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            int port = 9999;
            // 2.创建一个socket链接
            accept = new Socket(inetAddress,port);
            // 3.发送信息IO流
            os = accept.getOutputStream();
            os.write("就这吧,什么鬼?".getBytes());
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            // 关闭资源
            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(accept != null){
                try {
                    accept.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务器端

  • 建立服务的端口 ServerSocket
  • 等待的用户的连接 accept
  • 接收用户的消息
package github.Web.Demo02;

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

/** * @author subeiLY * @create 2021-06-06 11:22 */
// 服务端
public class TCPServerDemo01 {
    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;

        try{
            // 1.有一个地址
            serverSocket = new ServerSocket(9999);
            // 2.等待客户端连接过来
            socket = serverSocket.accept();
            // 3.读取客户端的消息
            is = socket.getInputStream();

           /*           //弃用 会有中文乱码           byte[] buffer = new byte[1024];            int len = 0;            while ((len = is.read(bytes)) != -1){                String s = new String(buffer,0,len);                System.out.println(s);            }            */

            // 管道流
            baos = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            System.out.println(baos.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1.文件上传

  • 客户端
package github.Web.Demo02;

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

/** * @author subeiLY * @create 2021-06-06 13:13 */
// 客户端
public class TCPClientDemo02 {
    public static void main(String[] args) throws Exception {
        // 1.建立连接
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9000);
        // 2.创建输出流
        OutputStream os = socket.getOutputStream();
        // 3.读取文件
        FileInputStream stream = new FileInputStream(new File("subei.jpg"));
        // 4.输出测试文件
        byte[] buffer = new byte[1024];
        int len = 0;
        while((len = stream.read(buffer)) != -1){
            os.write(buffer,0,len);
        }
        // 5.通知服务器已发送完成
        socket.shutdownOutput();
        // 6.确定服务器已经收到,断开连接
        InputStream inputStream = socket.getInputStream();

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer2 = new byte[1024];
        int len2 = 0;
        while((len2 = stream.read(buffer2)) != -1){
            byteArrayOutputStream.write(buffer2,0,len2);
        }

        System.out.println(byteArrayOutputStream);

        // 7.关闭流
        byteArrayOutputStream.close();
        inputStream.close();
        stream.close();
        os.close();
        socket.close();

    }
}
  • 服务端
package github.Web.Demo02;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/** * @author subeiLY * @create 2021-06-06 13:13 */
// 服务器
public class TCPServerDemo02 {
    public static void main(String[] args) throws Exception{
        // 1.创建一个服务器地址
        ServerSocket socket = new ServerSocket(9000);
        // 2.监听客户连接
        Socket accept = socket.accept();    // 阻塞式监听,能等待用户连进来
        // 3.获取输入流
        InputStream is = accept.getInputStream();
        // 4.确定存放文件的位置
        FileOutputStream fileOutputStream = new FileOutputStream("resort.jpg");

        // 5.写入文件
        byte[] buffer = new byte[1024];
        int len = 0;
        while((len = is.read(buffer)) != -1){
            fileOutputStream.write(buffer,0,len);
        }

        // 6.通知客户端收集完毕
        OutputStream outputStream = accept.getOutputStream();
        outputStream.write("服务器已经收集成功,请断开连接!".getBytes());

        // 7.关闭流
        outputStream.close();
        fileOutputStream.close();
        is.close();
        accept.close();
        socket.close();

    }
}

在这里插入图片描述

2.初识Tomcat

Tomcat

Tomcat乱码: conf\logging.properties 把UTF-8改为GBK

服务端

  • 自定义 S
  • Tomcat服务器 S :Java后台开发

客户端

  • 自定义 C
  • 浏览器 B

7.UDP

发短信:不用连接,需要知道对方的地址

1.发送消息

package github.Web.Demo03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/** * @author subeiLY * @create 2021-06-06 13:25 */
// 不需要连接服务器
public class UDPClientDemo01 {
    public static void main(String[] args) throws Exception{
        // 1.建立一个Socket
        DatagramSocket socket = new DatagramSocket();
        // 2.建个包
        String msg = "服务器,你好!";
        InetAddress localhost = InetAddress.getByName("localhost");
        int port = 9090;

        // 数据,数据的长度起始,要发送给谁
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0,msg.getBytes().length,localhost,port);

        // 3.发送包
        socket.send(packet);

        // 4.关闭流
        socket.close();

    }
}
package github.Web.Demo03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/** * @author subeiLY * @create 2021-06-06 13:26 */
// 还是需要客户端的链接
public class UDPServerDemo01 {
    public static void main(String[] args) throws Exception{
        // 1.开放端口
        DatagramSocket socket = new DatagramSocket(9090);
        // 2.接收数据包
        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);

        socket.receive(packet); // 阻塞接受
        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(new String(packet.getData()));
        // 3.关闭连接
        socket.close();

    }
}

2.循环发送消息

package github.Web.Demo03;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/** * @author subeiLY * @create 2021-06-06 14:06 */
public class UDPSenderDemo01 {
    public static void main(String[] args) throws Exception{
        DatagramSocket socket = new DatagramSocket(8888);

        // 准备数据:控制台读取
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        while(true) {
            String data = reader.readLine();
            byte[] buffer = data.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length, new InetSocketAddress("localhost", 9090));

            // 发送包
            socket.send(packet);
            if (data.equals("bye")) {
                break;
            }
        }

        // 关闭socket
        socket.close();

    }
}
package github.Web.Demo03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/** * @author subeiLY * @create 2021-06-06 14:06 */
public class UDPReceiveDemo01 {
    public static void main(String[] args) throws Exception{
        // 开放端口
        DatagramSocket socket = new DatagramSocket(9090);

        while (true) {

            // 准备接收包裹
            byte[] container = new byte[1024];
            DatagramPacket packet = new DatagramPacket(container, 0, container.length);
            socket.receive(packet);


            byte[] data = packet.getData();
            String receiveData = new String(data);
            System.out.println(receiveData);


            if (receiveData.equals("bye")) {
                break;
            }
        }

        // 关闭socket
        socket.close();

    }
}

在这里插入图片描述

3. 在线咨询: 两个人都可以是发送方,也可以是接收方(配合多线程)

在这里插入图片描述

  • 发信端
package com.fatfish.udp.onlinechatting;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

/**
 * @author fatfish
 * @version 1.0
 * @date 2024/6/6 21:56
 */
public class TalkSend implements Runnable {
    DatagramSocket socket = null;
    BufferedReader reader = null;

    private int formPort;
    private String hostname;
    private int toPort;

    public TalkSend(int formPort, String hostname, int toPort) {
        this.formPort = formPort;
        this.hostname = hostname;
        this.toPort = toPort;

        try {
            socket = new DatagramSocket(formPort);
            reader = new BufferedReader(new InputStreamReader(System.in));
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {

        while (true) {
            try {
                String s = reader.readLine();
                byte[] buffer = s.getBytes();
                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length,
                        new InetSocketAddress(hostname, toPort));

                // 发送包
                socket.send(packet);
                if (s.equals("bye")) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 关闭socket
        socket.close();
    }
}
  • 接收端
package com.fatfish.udp.onlinechatting;

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

public class TalkReceive implements Runnable {
    DatagramSocket socket = null;

    private int port;

    public TalkReceive(int port) {
        this.port = port;
        try {
            socket = new DatagramSocket(port);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        //开放端口

        // 接收包
        while (true) {
            try {
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container, 0, container.length);

                // 接收
                socket.receive(packet);


                byte[] data = packet.getData();
                String receiveData = new String(data);
                System.out.println(Thread.currentThread().getName() + ":" + receiveData);


                if (receiveData.equals("bye")) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        socket.close();
    }
}
  • 教师端
package github.Web.Demo04;

/** * @author subeiLY * @create 2021-06-11 18:23 */
public class StudentClient {
    public static void main(String[] args) {
        new Thread(new TalkSend(7777,"localhost",8900)).start();
        new Thread(new TalkReceive(9999),"老师").start();

    }
}
  • 学生端
package github.Web.Demo04;

/** * @author subeiLY * @create 2021-06-11 18:23 */
public class TeacherClient {
    public static void main(String[] args) {
        new Thread(new TalkSend(5555,"localhost",9999)).start();
        new Thread(new TalkReceive(8900),"学生").start();

    }
}

在这里插入图片描述

8.URL

  • https://www.baidu.com

  • 统一资源定位符:定位互联网上的某一个资源

  • DNS域名解析 www.baidu.com —> xxx.xxx.xxxx.xxx…xxx

协议:// ip地址:端口号/项目名/资源

  • 下载网页上的文件

    • 1.启动tomcat服务器;

    .../tomcat-x.x.xx/bin/startup.bat

    • 2.在tomcat中放好文件;

在这里插入图片描述

  • 3.进行相关测试。
package com.fatfish.url;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * @author fatfish
 * @version 1.0
 * @date 2024/6/6 22:15
 */
public class DownloadByURL {
    public static void main(String[] args) throws IOException {
        // 1.下载地址
        URL url = new URL("http://localhost:8080/fatfish/a.txt");

        // 2.连接到这个资源 HTTP
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

        InputStream is = urlConnection.getInputStream();

        FileOutputStream stream = new FileOutputStream(new File("same.txt"));

        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = is.read(bytes)) != -1) {
            stream.write(bytes, 0, len);
        }

        stream.close();
        is.close();
        urlConnection.disconnect();
    }
}

在这里插入图片描述

HttpURLConnection 是 Java 中用于发送 HTTP 请求和接收 HTTP 响应的类,它继承自 URLConnection 类,提供了更多处理 HTTP 请求和响应的方法和属性。主要用于与 Web 服务器进行通信,并支持常见的 HTTP 方法(GET、POST、PUT、DELETE 等)。

以下是 HttpURLConnection 类的一些常用方法和用法:

  1. 创建连接
  • URL url = new URL("http://example.com/resource");
  • HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  1. 设置请求方法
  • connection.setRequestMethod("GET");
  • connection.setRequestMethod("POST");
  1. 设置请求头
  • connection.setRequestProperty("Content-Type", "application/json");
  • connection.setRequestProperty("Authorization", "Bearer <token>");
  1. 发送请求数据
  • 对于 POST 请求:通过 OutputStream 将请求数据写入连接。
  • 对于 GET 请求:通常不需要发送请求数据。
  1. 接收响应数据
  • 获取响应状态码:int responseCode = connection.getResponseCode();
  • 获取响应消息:String responseMessage = connection.getResponseMessage();
  • 获取响应头:Map<String, List<String>> headers = connection.getHeaderFields();
  • 获取响应体:通过 InputStream 读取响应数据。
  1. 关闭连接
  • connection.disconnect();
  1. 处理响应数据
  • InputStream 中的数据转换为字符串或其他格式进行处理。

示例代码:

URL url = new URL("http://example.com/resource");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

int responseCode = connection.getResponseCode();
String responseMessage = connection.getResponseMessage();

if (responseCode == HttpURLConnection.HTTP_OK) {
    InputStream inputStream = connection.getInputStream();
    // 读取和处理响应数据
    inputStream.close();
}

connection.disconnect();

HttpURLConnection 类提供了一种简单而灵活的方式来与 Web 服务器进行通信,用于执行常见的 HTTP 请求和处理响应。它适用于在 Java 中进行 Web 开发、HTTP API 调用等场景。

参考

狂神说笔记——网络编程04 - subeiLY - 博客园

https 建立连接过程-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值