网络编程、UDP、TCP、三次握手、四次挥手

一、初识网络编程

网络编程的概念:在网络通信协议下,不同计算机上运行的程序,进行的数据传输。

应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等。

不管是什么场景,都是计算机和计算机之间通过网络进行数据传输。

Java中可以使用java.net包下的技术开发出常见的网络应用程序。

二、常见的软件架构

(一)B/S架构

概念:只需要一个浏览器,用户通过不同的网址,可以访问不同的服务器。例如京东和淘宝。

优缺点:

  1. 不需要开发客户端,只需要开发服务端
  2. 用户不需要下载,打开浏览器就能使用
  3. 如果应用过大,用户体验受到影响

(二)C/S架构

概念:在用户本地需要下载并安装客户端程序,在远程有一个服务端程序。例如QQ、Steam。

优缺点:

  1. 画面可以做的非常精美,用户体验好
  2. 需要开发客户端,也需要开发服务端
  3. 用户需要下载和更新的时候太麻烦

有些软件,例如京东和淘宝,既又C/S架构,也有B/S架构。

三、网络编程三要素

(一)IP

IP:(Internet Protocol)是互联网协议地址,也称IP地址,是设备在网络中的地址,是唯一的标识。常见的IP分为:IPv4、IPv6

1.IPv4

IPv4:(Internet Protocol version4)是互联网通信协议第四版。 采用32为地址长度,分成4组,每组取值范围是0~255,一共有42亿多,为了方便记忆,最后采用点分十进制表示法,例如:192.168.1.66。但是ipv4已经分配完毕了,所以需要ipv6进行补充。

IPv4的地址分类形式:

  • 公网地址(万维网使用)和私有地址(局域网使用)。
  • 192.168.开头的就是私有地址,范围是192.168.0.0--192.168.255.255,专门为组织机构内部使用,以此节省IP。

特殊IP地址:127.0.0.1,也可以是localhost:是回送地址,也称本地回环地址,又称本机IP,永远只会寻找当前所在本机。

检查网络常用的CMD命令:

  • ipconfig:查看本机IP地址
  • ping:检查网络是否连通

2.IPv6

IPv6:(Internet Protocol version6)是互联网通信协议第六版。采用128位地址长度,分成8组。IPv6一共有2^128次方个IP,采用冒分十六进制表示法:

目前也有很多APP支持IPv6。

3.InetAddress的使用

java 复制代码
public class MyInetAddressDemo1 {
    public static void main(String[] args) throws UnknownHostException {
    /*
       static InetAddress getByName(String host)   确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
       String getHostName()                        获取此IP地址的主机名
       String getHostAddress()                     返回文本显示中的IP地址字符串
    */
        // 1.获取InetAddress的对象
        // IP的对象 一台电脑的对象
        InetAddress address = InetAddress.getByName("PC-20240723RWZC");
        System.out.println(address); // PC-20240723RWZC/192.168.0.4

        String hostName = address.getHostName();
        System.out.println(hostName); // PC-20240723RWZC

        String hostAddress = address.getHostAddress();
        System.out.println(hostAddress); // 192.168.0.4
    }
}

(二)端口号

端口号:是应用程序在设备中唯一的标识。一个端口号只能被一个应用程序使用。

由两个字节表示的整数,取值范围:0~65535。其中0~1023的端口号用于一些知名的网络服务或者应用,我们使用1024以上的端口号即可。

以下是一些常见服务使用的端口号列表:这些端口号被IANA(Internet Assigned Numbers Authority)分配给特定的服务,并且广为人知。它们在网络通信中扮演着重要的角色,确保数据能够准确地发送到正确的服务。

  • 21端口:FTP 文件传输服务。
  • 22端口:SSH 远程连接服务。
  • 23端口:TELNET 终端仿真服务。
  • 25端口:SMTP 简单邮件传输服务。
  • 53端口:DNS 域名解析服务。
  • 80端口:HTTP 超文本传输服务。
  • 110端口:POP3(E-mail)。
  • 123端口:NTP(网络时间协议)。
  • 135、137、138、139端口:局域网相关默认端口。
  • 161端口:SNMP(简单网络管理协议)。
  • 389端口:LDAP(轻量级目录访问协议)。
  • 443端口:HTTPS服务器。
  • 465端口:SMTP(简单邮件传输协议)。
  • 873端口:rsync。
  • 989端口:FTPS。
  • 993端口:IMAPS。
  • 995端口:POP3S。
  • 1080端口:SOCKS代理协议服务器常用端口号。
  • 1433端口:MS SQL*SERVER数据库server。
  • 1521端口:Oracle 数据库。
  • 3306端口:MYSQL数据库端口。
  • 3389端口:WIN2003远程登录。
  • 5432端口:postgresql数据库端口。
  • 6379端口:Redis数据库端口。
  • 8080端口:TCP服务端默认端口、JBOSS、TOMCAT。

(三)协议

1.协议概述

协议:是指数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。

2.UDP协议

2.1UDP协议介绍

UDP协议又叫用户数据报协议(User Datagram Protocol),是面向无连接通信协议,不管是否已经连接成功,都会直接发送数据。

特点是:速度块,有大小限制,一次最多发送64K,数据不安全,易丢失数据。

UDP协议适用场景:网络会议、语音通话、在线视频,丢失数据没有太大的影响。

2.2使用UDP协议发送数据

步骤:

  1. 创建发送端的DatagramSocket对象
  2. 数据打包(DatagramPacket)
  3. 发送数据
  4. 释放资源

代码实现UDP协议发送数据:

java 复制代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        // UDP协议发送数据
        // 1.创建DatagramSocket对象
        // 细节:绑定端口,以后就是通过这个端口往外发送
        // 空参:所有可用的端口中随机一个进行使用
        // 有参:指定端口号进行绑定
        DatagramSocket datagramSocket = new DatagramSocket();

        // 2.打包数据
        String str = "hello world";
        byte[] bytes = str.getBytes();
        InetAddress address = InetAddress.getByName("127.0.0.1");
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, 10086);
        // 3.发送数据
        datagramSocket.send(datagramPacket);
        // 4.释放资源
        datagramSocket.close();
    }
}
2.3使用UDP协议接收数据

步骤:

  1. 创建接收端的DatagramSocket对象

  2. 接收打包好的数据

  3. 解析数据包

  4. 释放资源

java 复制代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;

public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        // UDP协议接收数据
        // 1.创建DatagramSocket对象
        // 细节:在接收的时候,一定要绑定端口,而且绑定的端口一定要跟发送的端口保持一致
        DatagramSocket datagramSocket = new DatagramSocket(10086);

        // 2.接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);

        // 该方法是阻塞的,程序执行到这一步的时候,会在这里等待发送端发送消息
        datagramSocket.receive(datagramPacket);

        // 3.解析数据包
        byte[] data = datagramPacket.getData();
        InetAddress address = datagramPacket.getAddress();
        int length = datagramPacket.getLength();
        int port = datagramPacket.getPort();
        SocketAddress socketAddress = datagramPacket.getSocketAddress();
        int offset = datagramPacket.getOffset();

        System.out.println("接收到的数据:" + new String(data, 0, length));
        System.out.println("该数据是从:" + address + "这台电脑中的" + port + "端口发出的");
        System.out.println(socketAddress);
        System.out.println("数据偏移量:" + offset);

        // 4.释放资源
        datagramSocket.close();
    }
}

实现过程:

先启动接收程序,再启动发送程序,运行结果:

2.4使用UDP协议实现聊天室
  • 案例需求

    UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束

    UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

java 复制代码
public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建对象DatagramSocket的对象
        DatagramSocket datagramSocket = new DatagramSocket();

        // 2.打包数据
        Scanner scanner = new Scanner(System.in);
        InetAddress address = InetAddress.getByName("127.0.0.1");
        while (true) {
            System.out.println("请输入消息:");
            String str = scanner.nextLine();
            if ("886".equals(str)) {
                System.out.println("程序终止!");
                break;
            }
            byte[] bytes = str.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, 10086);
            // 3.发送数据
            datagramSocket.send(datagramPacket);
        }
        // 4.释放资源
        datagramSocket.close();
    }
}
java 复制代码
public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建对象DatagramSocket的对象
        DatagramSocket datagramSocket = new DatagramSocket(10086);

        // 2.接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);

        while (true) {
            datagramSocket.receive(datagramPacket);

            // 3.解析数据包
            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            String ip = datagramPacket.getAddress().getHostAddress();
            String hostName = datagramPacket.getAddress().getHostName();
            int port = datagramPacket.getPort();

            // 4.打印数据
            System.out.println(hostName + "电脑的" + ip + ":" + port + "发送消息:" + new String(data, 0, length));
        }
    }
}

运行结果:

这里的hostName是activate.netsarang.com的原因是:在某些情况下,如果系统或网络环境中的 hosts 文件(在Windows中位于C:\Windows\System32\drivers\etc\hosts,在Unix/Linux系统中通常位于/etc/hosts)中有相应的条目,那么系统会直接从 hosts 文件中获取主机名,而不是去查询DNS。

我本地的host文件:找到第一个主机名返回

还可以设置多窗口聊天:

2.5UDP的三种通信方式
2.5.1单播------一对一通信(One-to-One)

在这种模式下,**一个UDP套接字(客户端)向另一个UDP套接字(服务器)发送数据。**客户端知道服务器的IP地址和端口号,可以直接向服务器发送数据包。服务器监听指定的端口,接收来自客户端的数据包。这种模式是最简单的UDP通信方式,适用于客户端和服务器之间的直接通信。

2.5.2组播------一对多通信(One-to-Many)

在一对多通信中,**一个服务器向多个客户端发送数据。**服务器使用相同的数据包发送给所有已知客户端的IP地址和端口号。这种模式常用于广播服务,如网络广播、在线游戏或多媒体流服务。服务器不需要为每个客户端维护一个单独的连接,而是向所有客户端广播数据。

组播地址:224.0.0.0~239.255.255.255

其中224.0.0.0~224.0.0.255为预留的组播地址

组播发送端代码:

java 复制代码
public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        //创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket();

        // 创建DatagramPacket对象
        String s = "hello world !";
        byte[] bytes = s.getBytes();
        InetAddress address = InetAddress.getByName("224.0.0.1");
        int port = 10000;

        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, port);

        // 调用MulticastSocket发送数据方法发送数据
        ms.send(datagramPacket);

        // 释放资源
        ms.close();
    }
}

组播接收端代码:

java 复制代码
public class ReceiveMessageDemo1 {
    public static void main(String[] args) throws IOException {
        // 1. 创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket(10000);

        // 2. 将当前本机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        ms.joinGroup(address);

        // 3. 创建DatagramPacket数据包对象
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

        // 4. 接收数据
        ms.receive(dp);

        // 5. 解析数据
        byte[] data = dp.getData();
        int len = dp.getLength();
        String ip = dp.getAddress().getHostAddress();
        String name = dp.getAddress().getHostName();

        System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));
        // ip为:192.168.0.4,主机名为:PC-20240723RWZC的人,发送了数据:hello world !

        // 6. 释放资源
        ms.close();
    }
}

接收端可以创建多个,但要保证每一个接收端都要将当前本机,添加到224.0.0.1的这一组当中。这样,发送端发送数据,多个接收端就可以同时接收到了。

2.5.3广播------多对多通信(Many-to-Many)

在多对多通信中,多个客户端之间可以直接相互通信,而不需要通过一个中心服务器。每个客户端都可以发送和接收来自其他客户端的数据包。这种模式适用于需要点对点通信的应用,如即时消息、文件共享或P2P网络。在这种模式下,每个客户端都扮演着发送者和接收者的角色。

广播地址:255.255.255.255

java 复制代码
// 发送端
public class ClientDemo {
    public static void main(String[] args) throws IOException {
      	// 1. 创建发送端Socket对象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket();
		// 2. 创建存储数据的箱子,将广播地址封装进去
        String s = "广播 hello";
        byte[] bytes = s.getBytes();
        InetAddress address = InetAddress.getByName("255.255.255.255");
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
		// 3. 发送数据
        ds.send(dp);
		// 4. 释放资源
        ds.close();
    }
}

// 接收端
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建接收端的Socket对象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket(10000);
        // 2. 创建一个数据包,用于接收数据
        DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
        // 3. 调用DatagramSocket对象的方法接收数据
        ds.receive(dp);
        // 4. 解析数据包,并把数据在控制台显示
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data,0,length));
        // 5. 关闭接收端
        ds.close();
    }
}

3.TCP协议

3.1TCP协议介绍

TCP协议:又叫传输控制协议(Transmission Control Protocol),是面向连接的通信协议。是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通过Socket产生IO流来进行网络通信,通信之前要保证连接已经建立。

特点是:速度慢,没有大小限制,数据安全。

TCP协议适用场景:对于数据有非常高的要求,不能丢失任何数据,例如下载软件、文字聊天、发送邮件。

3.2使用TCP协议发送和接收数据
java 复制代码
public class Client {
    public static void main(String[] args) throws IOException {
        // TCP协议,发送数据

        // 1.创建Socket对象
        // 细节:在创建对象的同时会连接服务端;如果连接不上,代码会报错
        Socket socket = new Socket("127.0.0.1", 10001);

        // 2.可以从连接通道中获取输出流
        OutputStream os = socket.getOutputStream();
        // 写出数据
        os.write("hello world".getBytes());
        
        // 3.释放资源
        os.close();
        socket.close();
    }
}

public class Server {
    public static void main(String[] args) throws IOException {
        // TCP协议,接收数据

        // 1.创建对象ServerSocket
        ServerSocket serverSocket = new ServerSocket(10001);

        // 2.监听客户端的连接
        Socket socket = serverSocket.accept();

        // 3.从连接通道中获取输入流读取数据
        InputStream is = socket.getInputStream();
        int len;
        while ((len = is.read()) != -1) {
            System.out.print((char) len);
        }

        // 4.释放资源
        is.close();
        socket.close();
    }
}

先运行Server服务器,再运行Client客户端,运行结果:

3.3解决TCP传输过程中的中文乱码问题

上面的代码使用的是字节流传输,在传输中文时会产生乱码,我们可以使用BufferReader来接收:

java 复制代码
public class Server2 {
    public static void main(String[] args) throws IOException {
        // TCP协议,接收数据

        // 1.创建对象ServerSocket
        ServerSocket serverSocket = new ServerSocket(10001);

        // 2.监听客户端的连接
        Socket socket = serverSocket.accept();

        // 3.从连接通道中获取输入流读取数据
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len;
        while ((len = br.read()) != -1) {
            System.out.print((char) len);
        }

        // 4.释放资源
        is.close();
        socket.close();
    }
}

运行结果:

3.4三次握手
3.5四次挥手
相关推荐
群联云防护小杜4 小时前
CC攻击为什么难防御?
网络·网络协议·安全·web安全·udp
进击的程序汪8 小时前
深入理解网络监听:TCP、UDP、IPv4 和 IPv6
网络·tcp/ip·udp
前端李易安1 天前
什么是UDP和TCP?有什么区别?应用场景分别都有哪些?
网络·tcp/ip·udp
南东山人1 天前
使用pktgen进行高吞吐发包
linux·测试工具·udp·wireshark·压力测试
云计算DevOps-韩老师2 天前
华为数通HCIA系列第4次考试-小测-子网划分相关解析
华为·ip地址·子网划分·ensp·ipv4·子网掩码·ipv6
夏天匆匆2过2 天前
linux性能提升之sendmmsg和recvmmsg
linux·c++·单片机·网络协议·udp·tcp
UestcXiye2 天前
《TCP/IP网络编程》学习笔记 | Chapter 9:套接字的多种可选项
c++·计算机网络·ip·tcp
ZachOn1y2 天前
计算机网络:运输层 —— 运输层端口号
网络协议·tcp/ip·计算机网络·udp·tcp·端口号
UestcXiye2 天前
《TCP/IP网络编程》学习笔记 | Chapter 10:多进程服务器端
c++·计算机网络·网络编程·tcp