【网络编程】UDP数据报套接字编程和TCP流套接字编程

news2024/11/22 15:11:56

文章目录

  • 1. 网络编程基础
    • 1.1 为什么需要网络编程?
    • 1.2 网络编程是什么?
    • 1.3 概念
  • 2. Socket套接字
  • 3. UDP数据报套接字编程
    • 3.1 DatagramSocket API
    • 3.2 DatagramPacket API
    • 3.3 InetSocketAddress API
  • 4. UDP构建服务端客户端(一发一收)
    • 4.1 创建服务端UdpServer.java:
    • 4.2 创建客户端UdpClient.java:
  • 5. UDP构建服务端客户端(翻译)
  • 6. TCP流套接字编程
    • 6.1 ServerSocket API
    • 6.2 Socket API
    • 6.3 TCP中的长短连接
  • 7. TCP构建服务端客户端(一发一收)
    • 7.1 创建服务端TcpServer.java
    • 7.2 创建客户端TcpClient.java
  • 8. 启动多个客户端

1. 网络编程基础

1.1 为什么需要网络编程?

这是因为在我们本地资源中,里面的内容并不丰富,而且下载的资源大多最终还是来源于网络。
而在网络世界中,里面有大量的资源。例如:当我们在网页中打开一个视频,听一段音乐,看一篇文章等,这些都属于网络资源(能从网络中获得的数据资源)。
这些资源都是通过网络编程进行数据传输,所以网络编程的需要是必不可少的。

1.2 网络编程是什么?

网络编程就是指网络主机通过不同的进程,以编程的方式进行网络通信(或称网络数据传输)。
1

1.3 概念

  1. 发送端:数据发送方的进程,称发送端。发送端的主机即网络通信中的源主机。
  2. 接收端:数据接受方的进程,称接受端。接受端的主机即网络通信中的目的主机。
  3. 收发端:发送端和接受端简称收发端。
    注意:
    发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。
    如上图:进程1请求获得资源时,进程1就是发送端,进程2是接收端,进程2响应时,进程2就是发送端,进程1就是接收端。
  4. 服务端:提供服务的一端,称为服务端。
  5. 客户端:获取服务的一端,称为客户端。
    如上图:主机1发出请求,主机2做出响应,那么我们就可以称主机1为客户端,主机2为服务端。

2. Socket套接字

概念
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。
分类

  1. 流套接字:使用传输层TCP协议。
    TCP的特点:
    有连接
    可靠传输
    面向字节流
    有接收缓冲区,也有发送缓冲区
    大小不限
  2. 数据报套接字:使用传输层UDP协议
    UDP的特点:
    无连接
    不可靠传输
    面向数据报
    有接收缓冲区,无发送缓冲区
    大小受限:一次最多传输64k
  3. 原始套接字:原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。

3. UDP数据报套接字编程

3.1 DatagramSocket API

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

DatagramSocket 构造方法:

方法作用
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)
        //创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口
        DatagramSocket socket1 = new DatagramSocket();
        //创建一个UDP数据报套接字的Socket,绑定到本机9090端口
        DatagramSocket socket2 = new DatagramSocket(9090);

DatagramSocket 方法:

方法作用
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacketp)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

3.2 DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报。

DatagramPacket 构造方法:

方法作用
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

DatagramPacket 方法:

方法作用
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

3.3 InetSocketAddress API

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

InetSocketAddress ( SocketAddress 的子类 )构造方法:

方法作用
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

4. UDP构建服务端客户端(一发一收)

知道上面的,就可以创建一个简单的服务端客户端,一发一收,就是客户端请求服务端,请求什么,客户端收到什么。

4.1 创建服务端UdpServer.java:

public class UdpServer {
    //创建服务器socket,不实例化
    private DatagramSocket socket = null;
    public UdpServer(int port) throws SocketException {
        服务器socket绑定固定的端口
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        //服务器放入死循环中,我们并不知道客户端什么时候访问客户端,需要不停的接受客户端的UDP数据报
        while(true){
            //1.创建数据报,读取客户端发送数据
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //转义
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.响应
            String response = process(request);
            //3.返回客户端
            //计算机内部处理数据的基本单位是字节。通过将接收到的数据转义为字节,长度要用字节长度
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
                    request,response);
        }

    }
    //一发一收
    public String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        //实例化服务端,端口号为9092
        UdpServer udpServer = new UdpServer(9092);
        //启动服务端
        udpServer.start();
    }
}

4.2 创建客户端UdpClient.java:

public class UdpClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;
    public UdpClient(String ip, int port) throws SocketException {
        serverIp = ip;
        serverPort = port;
        socket = new DatagramSocket();
    }
    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner sc = new Scanner(System.in);
        while(true){
            //1.输入
            System.out.println("-> ");
            String request = sc.next();
            //2.发送
//            InetSocketAddress inetAddress = new InetSocketAddress(serverIp,serverPort);
//            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
//                    inetAddress);
//			  计算机内部处理数据的基本单位是字节。通过将接收到的数据转义为字节,长度要用字节长度
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);

            //3.读取
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],0,4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            //4.显示
            System.out.println(response );
        }

    }
    public static void main(String[] args) throws IOException {
        UdpClient udpClient = new UdpClient("127.0.0.1",9092);
        udpClient.start();
    }
}

运行结果:
33
44

5. UDP构建服务端客户端(翻译)

4中服务器并没有什么功能,那么我们也可以为服务器赋予一些功能,例如:翻译。
我们只需要基于4代码的基础上,对服务器进行修改。

创建翻译服务端UdpServer.java:

public class UdpServer {
    //创建服务器socket,不实例化
    private DatagramSocket socket = null;
    //翻译集合
    private Map<String,String> dict = new HashMap<>();
    public UdpServer(int port) throws SocketException {
        //服务器socket绑定固定的端口
        socket = new DatagramSocket(port);

        //添加单词
        dict.put("cat","小猫");
        dict.put("dog","小狗");
        dict.put("bird","鸟");
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        //服务器放入死循环中,我们并不知道客户端什么时候访问客户端,需要不停的接受客户端的UDP数据报
        while(true){
            //1.创建数据报,读取客户端发送数据
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //转义,计算机内部处理数据的基本单位是字节。通过将接收到的数据转义为字节,服务器可以更容易地处理和解析数据,不会出错
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.响应
            String response = process(request);
            //3.返回客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
                    request,response);
        }

    }
    //一发一收
    public String process(String request){
        return dict.getOrDefault(request,"我还是个小菜鸡");
    }

    public static void main(String[] args) throws IOException {
        //实例化服务端,端口号为9092
        UdpServer udpServer = new UdpServer(9092);
        //启动服务端
        udpServer.start();
    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述
其实,相对于4只是修改了一些方法和属性,那么,我们也可以重新写一个类继承4中的服务器,这样会更加的简单。

6. TCP流套接字编程

ServerSocket 是创建TCP服务端Socket的API。

6.1 ServerSocket API

ServerSocket 构造方法:

方法作用
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法:

方法作用
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

6.2 Socket API

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

方法作用
Socket(String host, intport)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法:

方法作用
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

6.3 TCP中的长短连接

TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:

  1. 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
  2. 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

对比以上长短连接,两者区别如下:

  1. 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
  2. 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
  3. 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。

7. TCP构建服务端客户端(一发一收)

7.1 创建服务端TcpServer.java

public class TcpServer {
    private ServerSocket serverSocket = null;
    private ExecutorService service = Executors.newCachedThreadPool();
    public TcpServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            Socket socket = serverSocket.accept();
            service.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(socket);
                }
            });
//            Thread thread = new Thread(() -> {
//                processConnection(socket);
//            });
//            thread.start();
        }
    }

    public void processConnection(Socket socket){
        System.out.printf("客户端上线: [%s:%d]\n",socket.getInetAddress().toString(),socket.getPort());
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            while(true){
                Scanner sc = new Scanner(inputStream);
                if(!sc.hasNext()){
                    System.out.printf("客户端下线: [%s:%d]\n",socket.getInetAddress().toString(),socket.getPort());
                    break;
                }
                String request = sc.next();
                String response = process(request);
                PrintWriter writer = new PrintWriter(outputStream);
                writer.println(response);
                writer.flush();
                System.out.printf("[%s:%d] req: %s, resp: %s\n",socket.getInetAddress().toString(),socket.getPort(),
                        request,response);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpServer tcpServer = new TcpServer(9090);
        tcpServer.start();
    }
}

7.2 创建客户端TcpClient.java

public class TcpClient {
    private Socket socket = null;
    public TcpClient(String ip, int port) throws IOException {
        socket = new Socket(ip,port);
    }
    public void start(){
        System.out.println("客服端启动!");
        Scanner sc = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            while(true){
                System.out.println("-> ");
                String request = sc.next();
                PrintWriter writer = new PrintWriter(outputStream);
                writer.println(request);
                writer.flush();
                Scanner scanner = new Scanner(inputStream);
                String response = scanner.next();
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws IOException {
        TcpClient tcpClient = new TcpClient("127.0.0.1",9090);
        tcpClient.start();
    }
}

Tcp简单翻译和Udp修改规则相同。

8. 启动多个客户端

1.这里是引用
2.在这里插入图片描述
3. 在这里插入图片描述
4.
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1057628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QSS之QComboBox

QComboBox在Qt开发过程中经常使用&#xff0c;默认的下载列表风格达不到设计师的要求&#xff0c;本篇介绍基本的QComboBox的qss设置。 属性意思QComboBoxQComboBox基本样式QComboBox:editable右边可选择按钮QComboBox:!editable, QComboBox::drop-down:editable不可编辑或下拉…

Python中匹配模糊的字符串

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 如何使用thefuzz 库&#xff0c;它允许我们在python中进行模糊字符串匹配。 此外&#xff0c;我们将学习如何使用process 模块&#xff0c;该模块允许我们在模糊…

离散数学 学习 之 5.3 一阶逻辑的推理理论

第一个证明中&#xff0c;最后三步的化简很重要&#xff0c;倒数第三步构造出一个可以化简出倒数第二步的公式&#xff0c;最后再化简 上面中的第 1&#xff0c; 2 步 和 3 &#xff0c; 4 步不能换&#xff0c;因为无法保证是同一个 c 尽量弄成前束范式 上面中2&#xff0c;3&…

无状态自动配置 DHCPv6无状态配置 DHCPv6有状态配置

1、无状态自动配置 配置命令 AR1 ipv6 #开启路由器ipv6报文转发功能 interface GigabitEthernet0/0/0 ipv6 enable #开启路由器接口IPv6报文转发功能 ipv6 address FC01::1/64 …

对比两个Series序列中的元素是否不相等,并以Series格式返回结果

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 逐一对比两个Series序列中 元素是否不相等&#xff0c;将结果 以Series格式返回 [太阳]选择题 关于以下代码的说法中正确的是? import pandas as pd a pd.Series([0,1,2],index["x"…

stm32 - 中断/定时器

stm32 - 中断/定时器 概念时钟树定时器类型基准时钟&#xff08;系统时钟&#xff09;预分频器 - 时基单元CNT计数器 - 时基单元自动重装寄存器 - 时基单元基本定时器结构通用定时器计数器模式内外时钟源选择 定时中断基本结构时序预分频器时序计数器时序 概念 时钟树 https:…

vue重修004上部

文章目录 版权声明组件的三大组成部分scoped解决样式冲突scoped原理2.代码演示 组件data函数说明演示 组件通信组件关系分类通信解决方案父子通信流程子向父通信代 props详解props校验props&data、单向数据流 小黑记事本&#xff08;组件版&#xff09;基础组件结构需求和实…

【AI处理器组合】python实现-附ChatGPT解析

1.题目 AI处理器组合 知识点数组 时间限制:1s 空间限制: 256MB 限定语言:不限 题目描述: 某公司研发了一款高性能AI处理器。每台物理设备具备8颗AI处理器,编号分别为0、1、2、3、4、5、6、7。编号0-3的处理器处于同一个链路中,编号4-7的处理器处于另外一个链路中,不通链路中…

【计算机网络笔记九】I/O 多路复用

阻塞 IO 和 非阻塞 IO 阻塞 I/O 和 非阻塞 I/O 的主要区别&#xff1a; 阻塞 I/O 执行用户程序操作是同步的&#xff0c;调用线程会被阻塞挂起&#xff0c;会一直等待内核的 I/O 操作完成才返回用户进程&#xff0c;唤醒挂起线程非阻塞 I/O 执行用户程序操作是异步的&#xf…

阿里云PolarDB数据库详细介绍_3分钟看懂

阿里云PolarDB数据库是阿里巴巴自研的关系型分布式云原生数据库&#xff0c;PolarDB兼容三种数据库引擎&#xff1a;MySQL、PostgreSQL、Oracle&#xff08;语法兼容&#xff09;&#xff0c;目前提供云原生数据库PolarDB MySQL版、云原生数据库PolarDB PostgreSQL版和云原生数…

简单聊聊 TCP 协议

简单聊聊 TCP 协议 如何实现可靠传输 ?完全可靠存在比特差错存在丢包流水线可靠数据传输协议回退N步 (GBN)选择重传 (ARQ) 小结 TCPTCP 连接报文段结构序号和确认号 可靠数据传输避免重传超时时间加倍快速重传回退N步还是选择重传 流量控制连接管理拥塞控制拥塞原因拥塞控制方…

国庆10.03

运算符重载 代码 #include <iostream> using namespace std; class Num { private:int num1; //实部int num2; //虚部 public:Num(){}; //无参构造Num(int n1,int n2):num1(n1),num2(n2){}; //有参构造~Num(){}; //析构函数const Num operator(const Num &other)co…

想用ChatGPT写申请文书?那你肯定会被拒!

美国总统乔拜登&#xff08;Joe Biden&#xff09;、诗人TS艾略特&#xff08;T. S. Eliot&#xff09;和历史学家斯蒂芬安布罗斯&#xff08;Stephen Ambrose&#xff09;&#xff0c;他们的名字都曾与抄袭事件联系在一起。 其中&#xff0c;艾略特的抄袭行为是在他去世后才被…

A3纸内容分2页打在A4纸上

需求&#xff1a;文档是A3纸大小&#xff0c;因为打印机只能打A4纸&#xff0c;需要将内容分2页打在A4纸上。 网上搜索了一圈&#xff0c;可行解决方案如下&#xff1a; 1、打印纸的输出改成2分A4文件&#xff0c;首先设置打印输出的文档是A4纸大小&#xff0c;如图&#xff…

维基百科启用HTTPS的全球影响

2015 年 6 月&#xff0c;维基媒体基金会宣布维基百科默认启用 HTTPS&#xff0c;基金会称此举旨在保护访问者的隐私和安全&#xff0c;让用户能安全和不被审查的自由获取知识。在没有启用 HTTPS 的年代&#xff0c;审查者能知道访问者访问了维基百科上的哪些条目&#xff0c;它…

阿里云数据库RDS有哪些?细数关系型数据库大全

阿里云RDS关系型数据库大全&#xff0c;关系型数据库包括MySQL版、PolarDB、PostgreSQL、SQL Server和MariaDB等&#xff0c;NoSQL数据库如Redis、Tair、Lindorm和MongoDB&#xff0c;阿里云百科分享阿里云RDS关系型数据库大全&#xff1a; 目录 阿里云RDS关系型数据库大全 …

项目实训 文章评论

1.需求实现 以下功能&#xff1a; 1&#xff09;基本增删改查API 2&#xff09;根据文章id查询评论 3&#xff09;评论点赞 数据库&#xff1a;articledb 2 文章微服务模块搭建 &#xff08;1&#xff09;搭建项目工程article&#xff0c;并设置pom.xml引入依赖&#xff…

阿里云数据库大全_3分钟看懂阿里云RDS和NoSQL数据库汇总

阿里云数据库大全&#xff1a;RDS关系型数据库如MySQL版、PolarDB、PostgreSQL、SQL Server和MariaDB等&#xff0c;NoSQL数据库如Redis、Tair、Lindorm和MongoDB&#xff0c;数据仓库如AnalyticDB MySQL版、PostgreSQL、ClickHouse&#xff0c;阿里云还提供数据库管理工具如数…

leetcode 习题集 【9月】

leetcode 习题集 [9月] 回溯 77. 组合 class Solution { private:vector<vector <int>> result;vector<int> path;// path用来存放符合条件的结果 void backtracking(int n, int k, int startIndex){if(path.size() k){result.push_back(path);return;…

常用的分布式ID解决方案原理解析

目录 前言 一&#xff1a;分布式ID的使用场景 二&#xff1a;分布式ID设计的技术指标 三&#xff1a;常见的分布式ID生成策略 3.1 UUID 3.2 数据库生成 3.3 数据库的多主模式 3.4 号段模式 3.5 雪花算法 前言 分布式ID的生成是分布式系统中非常核心的基础性模块&#…