protoBuf 实现客户端与服务端

转载请注明出处:

1.定义消息格式

   在 src/main/proto 目录下创建 person.proto 文件,并定义消息格式,例如:

syntax = "proto3";
package example;

message Person {
  string name = 1;
  int32 age = 2;
  repeated string interests = 3;
}

  这个文件定义了一个名为 Person 的消息类型,包括三个字段:name、age 和 interests

2.生成代码

  使用 protoc 工具来生成 Java 代码,需要安装相应的插件和工具,可以通过 Maven 或 Gradle 等构建工具自动下载和配置。这里演示手动下载和安装的方式。

  首先下载 protoc 工具及其插件,例如从官方网站下载对应版本的 protoc-3.x.x-linux-x86_64.zip,以及 protoc-gen-grpc-java 插件,例如从 Maven 中央仓库下载最新版的 protoc-gen-grpc-java-1.42.0-linux-x86_64.exe。

  然后解压 protoc 工具,将 protoc 命令所在的路径添加到环境变量 PATH 中,例如:

export PATH="/path/to/protoc/bin:$PATH"

  接下来安装 protobuf-java 和 grpc-java 两个依赖,例如通过 Maven 引入以下依赖:

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.17.3</version>
</dependency>

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-netty-shaded</artifactId>
  <version>1.42.0</version>
</dependency>

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-protobuf</artifactId>
  <version>1.42.0</version>
</dependency>

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-stub</artifactId>
  <version>1.42.0</version>
</dependency>

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-testing</artifactId>
  <version>1.42.0</version>
  <scope>test</scope>
</dependency>

  接着使用 protoc 生成 Java 代码,例如:

protoc --java_out=src/main/java --grpc-java_out=src/main/java src/main/proto/person.proto

  这个命令会在 src/main/java/example 目录下生成 Person.java、PersonGrpc.java 和 PersonGrpc$PersonStub.java 等文件。

3.实现服务端

package example;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;

import java.io.IOException;

public class PersonServer {
    private final int port;
    private final Server server;

    public PersonServer(int port) throws IOException {
        this.port = port;
        this.server = ServerBuilder.forPort(port)
                .addService(new PersonServiceImpl())
                .build();
    }

    public void start() throws IOException {
        server.start();
        System.out.println("Server started, listening on " + port);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.err.println("*** shutting down gRPC server since JVM is shutting down");
            PersonServer.this.stop();
            System.err.println("*** server shut down");
        }));
    }

    public void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    private static class PersonServiceImpl extends PersonGrpc.PersonImplBase {
        @Override
        public void getMessage(PersonRequest request, StreamObserver<PersonResponse> responseObserver) {
            String name = request.getName();
            int age = request.getAge();
            String interests = String.join(", ", request.getInterestsList());
            
            // 将请求的内容响应回去
            PersonResponse response = PersonResponse.newBuilder()
                    .setMessage("Received person info: name=" + name + ", age=" + age + ", interests=[" + interests + "]")
                    .build();
            responseObserver.onNext(response);
            responseObserver.onCompleted();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        PersonServer server = new PersonServer(8989);
        server.start();
        server.blockUntilShutdown();
    }
}

  

4.实现客户端

package example;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class PersonClient {
    private final ManagedChannel channel;
    private final PersonGrpc.PersonStub stub;

    public PersonClient(String host, int port) {
        this.channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();
        this.stub = PersonGrpc.newStub(channel);
    }

    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public void sendMessage(String name, int age, String... interests) throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(1);

        StreamObserver<PersonResponse> responseObserver = new StreamObserver<PersonResponse>() {
            @Override
            public void onNext(PersonResponse response) {
                System.out.println("Received response: " + response.getMessage());
            }

            @Override
            public void onError(Throwable t) {
                System.err.println("Received error: " + t.getMessage());
                latch.countDown();
            }

            @Override
            public void onCompleted() {
                System.out.println("Request completed");
                latch.countDown();
            }
        };

        List<String> interestList = Arrays.asList(interests);
        PersonRequest request = PersonRequest.newBuilder()
                .setName(name)
                .setAge(age)
                .addAllInterests(interestList)
                .build();

        stub.getMessage(request, responseObserver);

        latch.await();
    }

    public static void main(String[] args) throws InterruptedException {
        PersonClient client = new PersonClient("localhost", 8989);

        // 向服务器发送请求
        client.sendMessage("Alice", 20, "reading", "swimming");

        // 关闭连接
        client.shutdown();
    }
}

  这个客户端会向服务器发送一个包含 name、age 和 interests 字段的 PersonRequest 消息,并等待接收服务器的响应信息。

 

 

本文转载于网络 如有侵权请联系删除

相关文章

  • Redis 客户端连接

    Redis客户端连接Redis通过监听一个TCP端口或者Unixsocket的方式来接收来自客户端的连接,当一个连接建立后,Redis内部会进行以下一些操作:首先,客户端socket会被设置为非阻塞模式,因为Redis在网络事件处理上采用的是非阻塞多路复用模型。然后为这个socket设置TCP_NODELAY属性,禁用Nagle算法然后创建一个可读的文件事件用于监听这个客户端socket的数据发送最大连接数在Redis2.4中,最大连接数是被直接硬编码在代码里面的,而在2.6版本中这个值变成可配置的。maxclients的默认值是10000,你也可以在redis.conf中对这个值进行修改。[root@localhost~]#redis-cli127.0.0.1:6379>configgetmaxclients1)"maxclients"2)"10000"实例以下实例我们在服务启动时设置最大连接数为100000:[root@localhost~]#redis-server--maxclients100000客户端命令S.N.命令描述1CLI

  • 大数据,云计算系统架设卫星授时(GPS北斗时钟)的重要性

    大数据,云计算系统架设卫星授时(GPS北斗时钟)的重要性大数据,云计算系统架设卫星授时(GPS北斗时钟)的重要性云计算(CloudComputing)是基于互联网的相关服务的增加、使用和交互模式,通常涉及通过互联网来提供动态易扩展且经常是虚拟化的资源。云是网络、互联网的一种比喻说法。过去在图中往往用云来表示电信网,后来也用来表示互联网和底层基础设施的抽象。因此,云计算甚至可以让你体验每秒10万亿次的运算能力,拥有这么强大的计算能力可以模拟核爆炸、预测气候变化和市场发展趋势。用户通过电脑、笔记本、手机等方式接入数据中心,按自己的需求进行运算。云计算(CloudComputing)是分布式计算(DistributedComputing)、并行计算(ParallelComputing)、效用计算(UtilityComputing)、网络存储(NetworkStorageTechnologies)、虚拟化(Virtualization)、负载均衡(LoadBalance)、热备份冗余(HighAvailable)等传统计算机和网络技术发展融合的产物。它是通过使计算分布在大量的分布式计算机上,而

  • Python版本切换与虚拟环境管理

    Python2和Python3之间存在较大的差异,并且由于各种原因导致Python2和Python3长期共存。我们在使用的时候,可能会遇到不同的Python版本问题或者是Python工作环境的切换问题。这里介绍pyenv、virtualenv、conda、venv,pyenv用于管理不同的Python版本,virtualenv、conda以及venv管理不同的工作环境。1.pyenv管理不同的Python版本我们直接从github上clone项目到本地gitclonehttps://github.com/pyenv/pyenv.git~/.pyenv复制把以下内容添加进~/.bashrc文件exportPYENV_ROOT="$HOME/.pyenv" exportPATH="$PATH:$PYENV_ROOT/bin" eval"$(pyenvinit-)"复制 接着,source~/.bashrc复制我们通过pyenv的help命令验证pyenv是否正确安装以及获取pyenv的帮助信息pyenv--help复制 通过pye

  • 回顾使用云桌面的那些经验

    最近汇报工作较多,公众号5天没有更新的,许下的诺必须对现。晚上11点,继续。 今天回顾一下最近正在处理的云桌面专项问题,相信对于云桌面的使用者、云桌面运营者都有相当帮助,我们一起来看看那些经验(或者说是用金钱、时间换来的教训)。一、云桌面使用了15天后,为什么越来越慢 一般客户在关闭瘦终端电源后,以为像使用电脑一样,云桌面也关闭了;下次打开瘦终端,云桌面重新开机了。但实际并不是这样,瘦终端、云桌面相当于是两台不同的电脑,关闭瘦终端的硬件电源,只是关了瘦终端,但云端的云桌面依然处于运行状态。 原理懂了,15天后慢的原因也找到了。相当于云端的电脑一直处于运行状态,内存中的脏数据越来越多。正确的处理方式是:当发现速度慢、内存占用率高时,重启云桌面。二、云桌面为什么频繁出现“未注册”的问题 云桌面的启动镜像中内嵌了许多程序,用于实现远程登录等功能。经过工程师分析,使用者可以安装了很多软件造成冲突、误中病毒、删除了云桌面的网卡等,造成云桌面的远程登录功能无法使用。正确的处理方式:在云桌面中安装杀毒软件,不要像使本地电脑一样,删除岗卡、关闭一些不认识的系统进程。三、云桌面为什么很多软件无法使用客户

  • react进阶之render props

    前言Renderprops作为共享组件逻辑的一种有效模式,此模式借助state和辅助参数,可以提供ui的更好的灵活性。renderfuntion在我们的组件中,我们都需要定义一个render方法,在这个方法中定义我们需要渲染的部分。//之前 render(){ const{on}=this.state return<Switchon={on}onClick={this.toggle}/> } //之后 renderUI(){ const{on}=this.state return<Switchon={on}onClick={this.toggle}/> } render(){ returnthis.renderUI() }复制优化renderUI为纯函数不依赖于组件,参数全部依赖传入constrenderUI=({on,toggle})=><Switchon={on}onClick={toggle}/> render(){ returnthis.renderUI({ on:this.state.on, toggle:this.toggle }

  • 揭开人工智能、机器学习和深度学习的神秘面纱

    深入学习,机器学习,人工智能——所有代表分析的未来的流行词。在这篇文章中,我们将通过一些现实世界的例子来解释什么是机器学习和深度学习。在以后的文章中,我们将探讨垂直用例。这样做的目的不是让你成为一名数据科学家,而是让你更好地理解机器学习能做些什么。什么是人工智能?纵观人工智能的历史,这一名词不断被重新定义。AI是一个总括术语(这个想法始于50年代);机器学习是AI的子集,深度学习是ML的子集。1985年,我在国安局实习时,人工智能是一个非常热门的话题。在美国国家安全局,我甚至参加了麻省理工学院关于专家系统的人工智能视频(VCR)课程。专家系统在规则引擎中捕获专家的知识。规则引擎在金融和医疗等行业有着广泛的应用,最近用于事件处理。但是当数据发生变化时,规则却变得很难更新和维护。机器学习的优势在于从数据中学习,它可以提供数据驱动的概率预测。根据TedDunning的说法,最好使用精确的术语,如机器学习或深度学习,而不是术语“AI”。在过去的十年里,分析技术发生了怎样的变化?根据HBR的ThomasDavenport的说法,分析技术在过去十年中发生了巨大的变化,在商用服务器,流分析和改进的机

  • 使用VideoToolbox硬解码H.264

    前言使用VideoToolbox硬编码H.264 在上一篇的硬编码简单介绍了H.264和VideoToolbox以及如何使用VideoToolbox硬编码从摄像头采集到的数据为H.264文件,这次使用VideoToolbox硬解码上一篇生成的H.264文件并渲染显示到屏幕。概念介绍CVPixelBuffer包含未压缩的像素数据,包括图像宽度、高度等; CVPixelBufferPoolCVPixelBuffer的缓冲池,因为CVPixelBuffer的创建和销毁代价很大; pixelBufferAttributesCFDictionary包括宽高、像素格式(RGBA、YUV)、使用场景(OpenGLES、CoreAnimation) CMTime64位的value,32位的scale,media的时间格式; CMVideoFormatDescriptionvideo的格式,包括宽高、颜色空间、编码格式等;对于H.264的视频,PPS和SPS的数据也在这里; CMBlockBuffer未压缩的图像数据; CMSampleBuffer存放一个或者多个压缩或未压缩的媒体文件; CMClock

  • 操作系统几种I/O访问类型以及异步I/O性能评估

    几种I/O类型概念的介绍AIOAIO的全称为AsynchronousI/O,即异步I/O。在AIO的工作模式下,应用程序向操作系统发起I/O请求(读/写)以后,不必等I/O完成,即可发起新的I/O请求。通过这种方法,可以提示提升I/O吞吐量和性能。从AIX5L起,AIX支持两种AIO:legacyAIO和POSIXAIO。AIO既支持文件系统也支持裸设备。DIOAIO的全称为DirectI/O,即直接I/O。在DIO的工作模式下,数据直接从磁盘传送到应用的缓存,而不经过文件的buffercache。DIO是JFS文件系统的一个选项,对于一些应用,如Oracle数据库,它本身有自己的缓存,如果再使用文件系统缓存,反而会造成性能的下降,在这种情况下,使用DIO会提升一定的性能。但是,当应用有大量的顺序读I/O的时候,使用DIO的方式由于缺少读缓存,会造成一定的性能下降。CIOCIO的全称为ConcurrentI/O即并发I/O。CIO的工作模式是建立在DIO模式基础之上的。在JFS2的环境下,如果应用需要绕过文件系统缓存,经常会使用CIO模式来替代DIO模式。在CIO的工作模式下,数据会从

  • Redis实战总结

                                                                                                                        

  • python连接Oracel、postgreSQL、SQLserver、Mysql、mongodb、redis等常用数据库方法汇总!

    python对接常用数据库,快速上手! 很多同学在使用python进行自动化测试的时候,会涉及到数据库数据校验的问题,因为不知道如何在python中如何对数据库,这个时候会一脸茫然,今天在这里给大家汇总一下python对接几大常用的数据库操作的方法!   作为近两年来最火的编程语言的python,受到广大程序员的追捧必然是有其原因的,如果要挑出几点来讲的话,人生苦短,我用python,第一条那就python语法简洁,易上手,第二条呢?便是python有着极其丰富的第三方的库,如此强大的python语言操作各大数据库,不管你使用的关系型数据库是oracle,mysql,sqlserver,还是关系型数据库redis,mongoDB。python都有有与之对应的第三方库。下面就来为大家一一介绍一下! 1、mysql 咱们先来看看如何对接mysql数据库,python2和python3中对接mysql的库是不一样的,在我们以这里python3为标准(毕竟python2在不久的将来官方就不再维护了),在python3中对接mysql数据库使用到的库为pymysql模块。 安装pymysq

  • P1975 [国家集训队]排队 线段树套平衡树维护动态逆序对查询

    $ \color{#0066ff}{题目描述}$ 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。 红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足i<j且hi>hj的(i,j)数量。 幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。 \(\color{#0066ff}{输入格式}\) 第一行为一个正整数n,表示小朋友的数量; 第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高; 第三行为一个正整数m,表示交换操作的次数; 以下m行每行包含两个正整数ai和bi­,表示交换位置ai与位置bi的小朋友。 \(\color{#0066ff}{输出格式}\) 输出文件共m+1行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。 \(\color

  • angular.js demo

    <!DOCTYPEhtml> <html> <head> <title></title> <scripttype="text/javascript"src="angular.min.js"></script> <scripttype="text/javascript"> varapp=angular.module("test",[]); app.controller("zhangshan",function($scope,$http){ $scope.list=[]; $scope.alert=function(ddd){ alert(ddd); $http.get("/one.php") .then(function(ret){ $scope.list=ret.data; angular.forEach($scope.list,function(value,key){ alert(key+">>

  • systemd service 如何开启 core dump

    如何查看coredump是否处于开启状态 Coredump中文翻译为“核心转储”,它是进程运行时突然崩溃的那一刻的内存快照。操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里,可使用gdb工具来分析。coredump生产环境一般处于禁用状态,对于内存消耗性的进程,coredump时会占用很多系统资源,磁盘空间也可能被写满。   使用普通用户登录CentOS7系统后,执行以下命令,你会发现corefilesizesoftlimit默认是0,即 coredump 处于禁用状态,hardlimit是unlimited,也可以直接通过ulimit-c命令查看。 $ulimit-a corefilesize(blocks,-c)0 $ulimit-a-H corefilesize(blocks,-c)unlimited复制 soft及hardlimit区别可以看ulimit的-S和-H参数解释。 The-Hand-Soptionsspecifythatthehardorsoftlimiti

  • spring boot使用自定义注解+AOP实现对Controller层指定方法的日志记录

    1.创建一个springboot项目,导入maven依赖: <dependencies> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-s

  • [Ubuntu]Firefox书签Ubuntu与Windows同步

    Ubuntu默认使用Firefox国际版。其他平台访问官网下载到的都是中国版,而国际版和中国版使用两套账号体系,相互之间无法同步,导致Ubuntu的Firefox无法和其他平台的Firefox同步书签等,为此可将Firefox改为使用中国版。   1.访问Firefox中国官网,下载最新版Firefox:http://www.firefox.com.cn/download/   2.解压:tarxfFirefox-latest-x86_64.tar.bz2   3.将系统预装的Firefox备份:sudomv/usr/lib/firefox/usr/lib/firefox_ubuntu   4.用中国版替换:sudomvfirefox/usr/lib/firefox   5.系统预装的Firefox是通过脚本启动,而中国版没有,因此要将该脚本复制过来:sudocp/usr/lib/firefox_ubuntu/firefox.sh/usr

  • Reverse Nodes in k-Group

    题目: Givenalinkedlist,reversethenodesofalinkedlistkatatimeandreturnitsmodifiedlist. Ifthenumberofnodesisnotamultipleofkthenleft-outnodesintheendshouldremainasitis. Youmaynotalterthevaluesinthenodes,onlynodesitselfmaybechanged. Onlyconstantmemoryisallowed. Forexample,Giventhislinkedlist:1->2->3->4->5 Fork=2,youshouldreturn:2->1->4->3->5 Fork=3,youshouldreturn:3->2->1->4->5 按一定数量反转链表,可以直接用反转整个链表的办法局部反转,直接反转整个链表是使用三个指针操作一下就可以,因此只需要分出要反转的部分来处理然后调整一下前驱和后继。代码: 1Lis

  • XML 新手入门基础知识(复制,留着自己看)

    如果您是XML新手,本文将为您介绍XML文档的基础结构,以及创建构造良好的XML需要遵循的规则,包括命名约定、正确的标记嵌套、属性规则、声明和实体。您还可以从本文了解到DTD和schema的验证。   XML 是可扩展标记语言(ExtensibleMarkupLanguage)的缩写,其中的 标记(markup)是关键部分。您可以创建内容,然后使用限定标记标记它,从而使每个单词、短语或块成为可识别、可分类的信息。您创建的文件,或文档实例 由元素(标记)和内容构成。当从打印输出读取或以电子形式处理文档时,元素能够帮助更好地理解文档。元素的描述性越强,文档各部分越容易识别。自从出现标记至今,带有标记的内容就有一个优势,即在计算机系统缺失时,仍然可以通过标记理解打印出来数据。 标记语言从早期的私有公司和政府制定形式逐渐演变成标准通用标记语言(StandardGeneralizedMarkupLanguage,SGML)、超文本标记语言(HypertextMarkupLanguage,HTML),并且最终演变成XML。SGML比较复杂,HTML(实际上仅

  • spring(二) AOP注入

    AOP概念 l AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码 l 经典应用:事务管理、性能监视、安全检查、缓存、日志等 l SpringAOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码 l AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,SpringAOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入   Aop的实现原理 laop底层将采用代理机制进行实现。 专业术语 1.target:目标类,需要被代理的类。例如:UserService 2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法 3.PointCut切入点:已经被增强的连接点。例如:addUser() 4.advice通知/增强,增强代码。例如:after、before 5.Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程. 6.

  • RDLC页眉页脚的小坑

    项目要求,固定的格式要求: /***********************************************************/ 合同号:bulabula 列名:blingbling列名:balabala 内容:(限定50行,不足50行补空行) 汇总: /************************************************************/ ps:汇总行是最后一页才具有, 我的解决方案是把合同号及列名行放置页眉中,计算行数是否够整页,不够整页俺需要补齐空行。 页脚部分默认留2cm位置,因方便观看效果,故未设置边距。 发现若只设置页脚,则打印区域内容仍会占用页脚空间。 解决办法,加个空白矩形。问题解决。 其实也可以设置下边距。

  • C#实现K-MEDOIDS聚类算法

    1、任意选取K个对象作为初始聚类中心(O1,O2,…Oi…Ok)。  2)将余下的对象分到各个类中去(该对象与哪一个聚类中心最近就被分配到哪一个聚类簇中);  3)对于每个类(Oi)中,顺序选取一个Or,重复步骤2,计算用Or代替Oi后的误差E=各个点到其对应的中心点欧式距离之和。选择E最小的那个Or来代替Oi。4)重复步骤3,直到K个medoids固定下来。 usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.IO; namespaceK_medoids { classProgram { ///<summary> ///程序文本数据文件应位于同一文件夹下 ///</summary> ///<paramname="args"></param> staticvoidMain(string[]args) { varpath=string.Empty; intk=0; try { path=Path.Com

  • P3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一

    还是蛮简单的一道题,首先dfs一遍,在所有能到达放有干草的洞穴的所有路径中,找出路径上最小伐值的最大值,按这个值由小到大,再来一遍贪心就行了,能放就放,不能放拉倒(也可以理解为,不能放把最前一个删了)。 但是如果题目改为每个洞穴不止一堆干草的话,也是没有问题的,只要在队列上在维护一个小根堆,判断队列中最小的干草堆是否比当前小,小则替换,否则不变。 1constmaxn=200; 2type 3node=record 4f,t,w:longint; 5end; 6varn,i,j,m,k,u,v,x,now,ans:longint; 7head:array[0..101]oflongint; 8b:array[0..2001]ofnode; 9f:array[0..100000]oflongint; 10p:array[0..101]ofboolean; 11a:array[0..15]oflongint; 12max:array[0..101]oflongint; 13functionmin(a,b:longint):longint; 14begin 15ifa>bthene

相关推荐

推荐阅读