用Go编写ChatGPT插件

ChatGPT插件平台有望成为影响深远的"下一件大事",因此对于开发者来说,有必要对ChatGPT插件的开发有一定的了解。原文: Writing a ChatGPT Plugin With Go[1]

alt

我工作的附带福利之一是偶尔可以接触试用一些很酷的新技术,最近的一项技术是OpenAI的ChatGPT插件平台。

ChatGPT是一款突破性的AI聊天机器人,无论好坏,它都席卷了世界。在2023年3月,ChatGPT插件和插件平台的发布引发了持续关注(包括我),这可是件大事。

如果你把ChatGPT的发布等同于2007年发布iPhone,那么插件的发布就像是在2008年发布的移动应用和App Store。这不仅是当今最强大、最先进的AI模型开发服务平台,也是一个可以立即触达1亿用户的机会。

对于像我这样的程序员来说,就像猫薄荷之于猫一样,当我拿到访问权限时,立马跳了起来。

ChatGPT插件非常简单,实际上只不过是ChatGPT调用并获取信息的API,可以基于返回信息向用户提供答案。是的,你没看错,ChatGPT插件只是标准API。

那么,怎么实现ChatGPT插件呢?实现ChatGPT插件必须提供2个文件:

  1. 描述插件的manifest文件(本质上是JSON文件)
  2. 描述插件中API的 OpenAPI [2]规范(YAML文件)

接下来看看我是如何创建新加坡HDB停车场插件的。

停车场插件

我决定从一个非常简单的插件开始。在新加坡,住房发展局(HDB)[3]是负责公共住房的政府机构。公共住房在新加坡是件大事,约有80%的人住在公共住房中,因此HDB停车场占新加坡住宅停车场的大部分。

我想创建一个插件,可以告诉我关于新加坡HDB停车场的使用情况。这些信息都可以在data.gov.sg上获得,这是一个免费数据门户网站,提供新加坡政府的公开数据集和API。

简而言之,插件有两个功能:

  1. 提供HDB停车场的资料,可以指定地点或指定停车场
  2. 提供HDB停车场的可用情况,可以指定地点或指定停车场

data.gov.sg门户网站有个针对这些目标很有用的API——HDB停车场使用情况API[4],这是一个实时API。至于HDB停车场信息,有一个定期更新的数据集,称为HDB停车场信息[5]。幸运的是,HDB停车场信息数据集是CKAN action API的前端。

无论如何,现在这两种功能都有API可用。这就完事了,对吧?没那么快。CKAN action API根据日期参数在数据集中返回所有内容,并不完全有用。我不能把所有数据都转到ChatGPT去,数据集是324kb,超过了token限制。然而,解决这个问题相对简单,只需要过滤一下。

此外,我们不能直接公开API。记住,ChatGPT插件需要manifest文件和OpenAI规范。manifest文件还指向像logo和合法页面这样的东西,需要提供具有相同域名和插件URL的电子邮件。所有这一切都意味着我们真的需要开发一个单独的API程序,在将data.gov.sg API发布到ChatGPT之前用来进行处理。

API程序

我用Go语言开发了API程序,这是很自然的选择,Go非常适合API。由于很多AI的东西都用Python,我最近一直在使用Python,所以也比较渴望回到Go。

JSON数据结构

我们从JSON数据结构定义开始。

package main

import "time"

// for car park information
type CarParkData struct {
 CarParkInfo []struct {
  TotalLots     string `json:"total_lots"`
  LotType       string `json:"lot_type"`
  LotsAvailable string `json:"lots_available"`
 } `json:"carpark_info"`
 CarParkNumber  string `json:"carpark_number"`
 UpdateDatetime string `json:"update_datetime"`
}

type CarParkAvailability struct {
 Items []struct {
  Timestamp time.Time     `json:"timestamp"`
  Data      []CarParkData `json:"carpark_data"`
 } `json:"items"`
}

// for car park availability
type CarParkRecord struct {
 FullCount           string  `json:"_full_count"`
 ShortTermParking    string  `json:"short_term_parking"`
 CarParkType         string  `json:"car_park_type"`
 YCoord              string  `json:"y_coord"`
 XCoord              string  `json:"x_coord"`
 Rank                float64 `json:"rank"`
 FreeParking         string  `json:"free_parking"`
 GantryHeight        string  `json:"gantry_height"`
 CarParkBasement     string  `json:"car_park_basement"`
 NightParking        string  `json:"night_parking"`
 Address             string  `json:"address"`
 CarParkDecks        string  `json:"car_park_decks"`
 ID                  int     `json:"_id"`
 CarParkNo           string  `json:"car_park_no"`
 TypeOfParkingSystem string  `json:"type_of_parking_system"`
}

type CarParks struct {
 Help    string `json:"help"`
 Success bool   `json:"success"`
 Result  struct {
  ResourceID string `json:"resource_id"`
  Fields     []struct {
   Type string `json:"type"`
   ID   string `json:"id"`
  } `json:"fields"`
  Q       string          `json:"q"`
  Records []CarParkRecord `json:"records"`
  Links   struct {
   Start string `json:"start"`
   Next  string `json:"next"`
  } `json:"_links"`
  Total int `json:"total"`
 } `json:"result"`
}

看起来很复杂,但其实我作弊了,我只是从data.gov.sg API中获取JSON样本和输出,并使用Matt Holt提供的JSON-to-Struct[6]服务,该服务会立即创建相应的结构体,然后只需根据需要对其进行调整。

API

接下来是API程序本身。

package main

import (
 "encoding/json"
 "io"
 "log"
 "net/http"
 "net/url"
 "os"
 "time"
)

const infoUrl = "https://data.gov.sg/api/action/datastore_search?\
  resource_id=139a3035-e624-4f56-b63f-89ae28d4ae4c&q="

const availUrl = "https://api.data.gov.sg/v1/transport/\
  carpark-availability?date_time="


func main() {
 port := os.Getenv("PORT")
 mux := http.NewServeMux()
 mux.Handle("/static/", http.StripPrefix("/static"
  http.FileServer(http.Dir("./static"))))
 mux.Handle("/.well-known/ai-plugin.json", cors(manifest))
 mux.Handle("/openapi.yaml", cors(specs))
 mux.Handle("/info", cors(info))
 mux.Handle("/availability", cors(availability))

 server := &http.Server{
  Addr:    ":" + port,
  Handler: mux,
 }
 server.ListenAndServe()
}

// middleware to set CORS for handlers
func cors(h http.HandlerFunc) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Access-Control-Allow-Origin""*")
  w.Header().Set("Access-Control-Allow-Methods""GET")
  w.Header().Set("Access-Control-Allow-Headers"
    "Origin,Content-Type,OpenAI-Conversation-ID,OpenAI-Ephemeral-User-ID")
  h.ServeHTTP(w, r)
 })
}

// returns openai.yaml file
func specs(w http.ResponseWriter, r *http.Request) {
 http.ServeFile(w, r, "openapi.yaml")
}

// returns .well-known/ai-plugin.json file
func manifest(w http.ResponseWriter, r *http.Request) {
 http.ServeFile(w, r, ".well-known/ai-plugin.json")
}

// handler function
// get information on car park
func info(w http.ResponseWriter, r *http.Request) {
 query := r.URL.Query().Get("q")
 records := getCarParkRecords(query)
 w.Header().Set("Content-Type""application/json")
 json.NewEncoder(w).Encode(records)
}

// handler function
// get availability on car park
func availability(w http.ResponseWriter, r *http.Request) {
 // get the car parks requested
 query := r.URL.Query().Get("q")
 records := getCarParkRecords(query)

 // get the availability of car parks in Singapore now
 now := time.Now()
 dt := now.Format(time.RFC3339)
 availability := new(CarParkAvailability)
 carparkdata := []CarParkData{}

 resp, err := http.Get(availUrl + url.QueryEscape(dt))
 if err != nil {
  log.Println("Cannot call url", availUrl+dt, err)
 }
 defer resp.Body.Close()
 data, err := io.ReadAll(resp.Body)
 if err != nil {
  log.Println("Cannot read JSON file", err)
 }
 err = json.Unmarshal(data, availability)
 if err != nil {
  log.Println("Error unmarshalling json data:", err)
 }
 // filter off those that we want to look for
 for _, item := range availability.Items {
  for _, data := range item.Data {
   for _, record := range records {
    if data.CarParkNumber == record.CarParkNo {
     carparkdata = append(carparkdata, data)
    }
   }
  }
 }
 w.Header().Set("Content-Type""application/json")
 json.NewEncoder(w).Encode(carparkdata)
}

// get card park records based on a query
func getCarParkRecords(query string) []CarParkRecord {
 carparks := new(CarParks)
 resp, err := http.Get(infoUrl + query)
 if err != nil {
  log.Println("Cannot call url", infoUrl+query, err)
 }
 defer resp.Body.Close()
 data, err := io.ReadAll(resp.Body)
 if err != nil {
  log.Println("Cannot read JSON file", err)
 }
 err = json.Unmarshal(data, carparks)
 if err != nil {
  log.Println("Error unmarshalling json data:", err)
 }

 return carparks.Result.Records
}

这就是整个API程序,大约120行左右代码。我们来分析一下。

Manifest文件

之前提到有两个文件定义ChatGPT插件,一个是manifest文件,需要放在运行API程序的服务器上的.well-known/ai-plugin.json路径下。

为此,我提供了一个JSON文件。如果不需要身份验证,则格式相对简单。

{
    "schema_version""v1",
    "name_for_human""HDB Car Park",
    "name_for_model""hdbcarpark",
    "description_for_human""For checking availability of car park \
      lots at various HDB car parks around Singapore."
,
    "description_for_model""For checking availability of car park \
      lots at various HDB car parks around Singapore."
,
    "auth": {
      "type""none"
    },
    "api": {
      "type""openapi",
      "url""https://carpark.sausheong.com/openapi.yaml",
      "is_user_authenticated"false
    },
    "logo_url""https://carpark.sausheong.com/static/logo.png",
    "contact_email""sausheong@sausheong.com",
    "legal_info_url""https://carpark.sausheong.com/static/legal.html"
}
OpenAPI规范

第二个是API的OpenAPI规范。和前面一样,我提供了openapi.yaml文件,文件位置在上面的manifest文件中指定。

openapi: 3.0.1
info:
  title: HDB Car Park
  description: For checking avaiability of car park lots at various HDB \
    car parks around Singapore
  version: 'v1'
servers:
  - url: https://carpark.sausheong.com
paths:
  /info?q={location}:
    get:
      operationId: getCarParkInfo
      summary: Get information about HDB car parks at a location
      parameters:
      - in: path
        name: location
        schema:
            type: string
        required: true
        description: location to search for HDB car parks
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/getCarParkInfo'
  /availability?q={location}:
    get:
      operationId: getCarParkAvailability
      summary: Get availability of HDB car parks in Singapore at this moment
      parameters:
      - in: path
        name: location
        schema:
            type: string
        required: true
        description: location to search for HDB car parks      
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/getCarParkAvailability' 

components:
  schemas:
    getCarParkInfo:
      type: array
      items: 
        type: object
        properties: 
          _full_count: 
            type: string
          short_term_parking: 
            type: string
          car_park_type: 
            type: string
          y_coord: 
            type: string
          x_coord: 
            type: string
          rank: 
            type: number
          free_parking: 
            type: string
          gantry_height: 
            type: string
          car_park_basement: 
            type: string
          night_parking: 
            type: string
          address: 
            type: string
          car_park_decks: 
            type: string
          _id: 
            type: integer
            format: int
          car_park_no: 
            type: string
          type_of_parking_system: 
            type: string
    getCarParkAvailability:
      type: object
      properties: 
        timestamp: 
          type: string
          format: date-time
        carpark_data: 
          type: array
          items: 
            type: object
            properties: 
              carpark_info: 
                type: array
                items: 
                  type: object
                  properties: 
                    total_lots: 
                      type: string
                    lot_type: 
                      type: string
                    lots_available: 
                      type: string
              carpark_number: 
                type: string
              update_datetime: 
                type: string

该文件定义了两个路径,/info/availability,用于提供对应的两个功能。这两个路径还可以接受查询参数location,用于过滤位置。

接下来看看具体功能。

停车场信息

getCarParkRecords函数直接向data.gov.sg API发送GET请求,并返回CarParkRecord结构的切片。

// get card park records based on a query
func getCarParkRecords(query string) []CarParkRecord {
 carparks := new(CarParks)
 resp, err := http.Get(infoUrl + query)
 if err != nil {
  log.Println("Cannot call url", infoUrl+query, err)
 }
 defer resp.Body.Close()
 data, err := io.ReadAll(resp.Body)
 if err != nil {
  log.Println("Cannot read JSON file", err)
 }
 err = json.Unmarshal(data, carparks)
 if err != nil {
  log.Println("Error unmarshalling json data:", err)
 }
 return carparks.Result.Records
}

info处理程序使用getCarParkRecords来获取记录,并作为JSON响应返回。

// get information on car park
func info(w http.ResponseWriter, r *http.Request) {
 query := r.URL.Query().Get("q")
 records := getCarParkRecords(query)
 w.Header().Set("Content-Type""application/json")
 json.NewEncoder(w).Encode(records)
}
停车场使用情况

检查停车场的使用情况稍微有点棘手。availability处理程序首先调用getCarParkRecords来获取感兴趣的停车场。

然后调用data.gov.sg CKAN API来获取新加坡所有HDB停车场的当前使用情况,并放入CarParkAvailability结构体中。

// get availability on car park
func availability(w http.ResponseWriter, r *http.Request) {
 // get the car parks requested
 query := r.URL.Query().Get("q")
 records := getCarParkRecords(query[:len(query)-1])

 // get the availability of car parks in Singapore now
 now := time.Now()
 dt := now.Format(time.RFC3339)
 availability := new(CarParkAvailability)
 carparkdata := []CarParkData{}

 resp, err := http.Get(availUrl + url.QueryEscape(dt))
 if err != nil {
  log.Println("Cannot call url", availUrl+dt, err)
 }
 defer resp.Body.Close()
 data, err := io.ReadAll(resp.Body)
 if err != nil {
  log.Println("Cannot read JSON file", err)
 }
 err = json.Unmarshal(data, availability)
 if err != nil {
  log.Println("Error unmarshalling json data:", err)
 }

 // filter off those that we want to look for
 for _, item := range availability.Items {
  for _, data := range item.Data {
   for _, record := range records {
    if data.CarParkNumber == record.CarParkNo {
     carparkdata = append(carparkdata, data)
    }
   }
  }
 }
 w.Header().Set("Content-Type""application/json")
 json.NewEncoder(w).Encode(carparkdata)
}

然后遍历CarParkAvailabilityCarParkRecords中的停车场数据,并匹配停车场编号以过滤CarParkAvailability。最后,以JSON格式返回停车场使用数据。

启用CORS

需要注意,要为API程序启用CORS(跨域资源共享,Cross-Origin Resource Sharing),从而允许ChatGPT调用API。我将其实现为每个处理程序的HTTP中间件。

// middleware to set CORS for handlers
func cors(h http.HandlerFunc) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Access-Control-Allow-Origin""https://chat.openai.com")
  w.Header().Set("Access-Control-Allow-Methods""GET")
  w.Header().Set("Access-Control-Allow-Headers"
    "Origin,Content-Type,OpenAI-Conversation-ID,OpenAI-Ephemeral-User-ID")
  h.ServeHTTP(w, r)
 })
}

就这么多!

部署插件

ChatGPT允许我们安装运行在计算机上的插件,也就是说,可以在本地主机上运行,这对于测试和调试非常有用。同时也意味着需要将manifest文件和OpenAPI规范指向localhost。

一旦对测试结果感到满意,就可以将其部署到互联网上,让最多15个用户进行测试。部署插件类似于部署任何API,在此不再详述,除了需要为服务提供适当的域名,并且API域名需要与manifest文件中的联系电子邮件地址相匹配,还需要通过HTTPS运行。

一旦部署了API,就可以将其作为插件安装在ChatGPT上。

为什么这么繁琐?

如果你认为对于API来说太过于繁琐,只要看看当我在ChatGPT上问更复杂的问题时,这个插件是如何回应的。请记住,插件不只是向用户提供数据,也为当今最先进的AI模型之一提供数据,以用于回答问题。

我试着比较多层停车场和地面停车场,这很有效,感觉我是在问一个拥有所有数据并能够为我分析数据的人。

问: 在淡滨尼,多层停车场是否比地面停车场有更多可用车位?

ChatGPT: 根据数据,这里是淡滨尼多层停车场和地面停车场的比较:

多层停车场:

总停车位: 26,486

空停车位: 14,070

空停车位占比: 53.1%

地面停车场:

总停车位: 26,486

空停车位: 198

空停车位占比: 18.6%

因此,与地面停车场相比,淡滨尼的多层停车场的可用车位比例更高。

接下来,我试着问哪个停车场车位最多,离这里有多远。

*问: 淡滨尼哪个停车场的车位最多,地址是什么? 离淡滨尼购物中心有多远?

ChatGPT: 淡滨尼可用车位最多的停车场位于NT5,共有1489个车位,其中有812个空车位。

此停车场地址为"淡滨尼中环7号510C座/淡滨尼广场"。

至于到淡滨尼购物中心的距离,我需要计算一下,请稍等。

"NT5"停车场位于"淡滨尼中环7号510C座/淡滨尼广场",距离淡滨尼购物中心约500米,步行大约6分钟。请注意,实际时间可能会根据路线和步行速度而有所不同。

这就很有意思了,当ChatGPT没有数据时,就会胡编乱造。它不知道停车场离购物中心有多远,所以就编了一个数字,猜测人们从停车场走到购物中心需要多长时间。实际距离为1公里,步行时间约为12分钟(谷歌地图)。

我还试着让它比较新加坡两个不同地区的停车场使用情况,也很有效。

问: 淡滨尼的空停车位与宏茂桥相比,占停车场容量的百分比如何?

ChatGPT: 以下是淡滨尼和宏茂桥的停车场可用情况:

淡滨尼:

总停车位: 13,739

空停车位: 4,751

空停车位占比: 34.6%

宏茂桥:

总停车位: 30,544

空停车位: 9,380

空停车位占比: 30.7%

请注意,这些数字是实时更新的,随时可能会发生变化。

总结

编写ChatGPT插件非常简单,并且是一个强大的工具。编写插件的技能与目前技能没什么不同,不像刚开始开发移动应用时需要更多专业技能。很容易看出,当它正式发布时,很可能会有一个插件热潮。更令人兴奋的是,插件可以相互协作以提供协同功能。

ChatGPT仍然存在问题,当数据不可用时,会产生幻觉现象。然而,从长远来看,这是可以解决的。我认为一个潜力巨大的AI市场正在开始。

代码

可以从下面Git仓库获得所有代码。

ChatGPT plugin for Singapore HDB car park availability[7]


你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

参考资料

[1]

Writing a ChatGPT Plugin With Go: https://betterprogramming.pub/writing-a-chatgpt-plugin-with-go-c5a70764915d

[2]

OpenAPI: https://www.openapis.org

[3]

住房发展局(HDB): https://www.hdb.gov.sg/cs/infoweb/homepage

[4]

HDB停车场使用情况API: https://data.gov.sg/dataset/carpark-availability

[5]

HDB停车场信息: https://data.gov.sg/dataset/hdb-carpark-information

[6]

JSON-to-Struct: https://mholt.github.io/json-to-go

[7]

ChatGPT plugin for Singapore HDB car park availability: https://github.com/sausheong/carpark-cgpt/tree/main

- END -

本文由 mdnice 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实战:基于卷积的MNIST手写体分类

前面实现了基于多层感知机的MNIST手写体识别,本章将实现以卷积神经网络完成的MNIST手写体识别。 1. 数据的准备 在本例中,依旧使用MNIST数据集,对这个数据集的数据和标签介绍,前面的章节已详细说明过了,相对于前面章…

控制goroutine 的并发执行数量

goroutine的数量上限是1048575吗? 正常项目,协程数量超过十万就需要引起重视。如果有上百万goroutine,一般是有问题的。 但并不是说协程数量的上限是100多w 1048575的来自类似如下的demo代码: package mainimport ( "fmt" "ma…

MySQL的mysql-bin.00xx binlog日志文件的清理

目录 引言手工清理配置自动清理 引言 公司一个项目生产环境mysql数据盘占用空间增长得特别快,经过排查发现是开启了mysql的binlog日志。如果把binlog日志关闭,如果操作万一出现问题,就没有办法恢复数据,很不安全,只能…

WPF怎么实现文件拖放功能winform怎么实现拖拽功能

WPF怎么实现文件拖放功能winform怎么实现文件拖拽功能,在管理员模式下wpf winform怎么实现文件的拖拽功能 WPF实现文件拖放功能,正常情况并没有什么问题,但是如果你的程序使用管理员身份启动,你就会发现文件拖放功能就会失效。同…

css元素定位:通过元素的标签或者元素的id、class属性定位

前言 大部分人在使用selenium定位元素时,用的是xpath元素定位方式,因为xpath元素定位方式基本能解决定位的需求。xpath元素定位方式更直观,更好理解一些。 css元素定位方式往往被忽略掉了,其实css元素定位方式也有它的价值&…

全新纠错码将量子计算提效10倍!

上周,来自两个研究小组的最新模拟报告称,一类新兴的量子纠错码的效率比目前的“黄金标准”(即表面码)高出一个数量级。 量子纠错码的工作原理都是将大量容易出错的量子比特转换成更小的“受保护”量子比特,这些量子比特…

前端Vue仿企查查天眼查高管信息列表组件

随着技术的不断发展,传统的开发方式使得系统的复杂度越来越高。在传统开发过程中,一个小小的改动或者一个小功能的增加可能会导致整体逻辑的修改,造成牵一发而动全身的情况。为了解决这个问题,我们采用了组件化的开发模式。通过组…

Ansible学习笔记8

group模块: 创建一个group组: [rootlocalhost ~]# ansible group1 -m group -a "nameaaa gid5000" 192.168.17.105 | CHANGED > {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}…

穿上App外衣,保持Web灵魂——PWA温故

早在2015年,设计师弗朗西斯贝里曼和Google Chrome的工程师亚历克斯罗素提出“PWA(渐进式网络应用程序)”概念,将网络之长与应用之长相结合,其核心目标就是提升 Web App 的性能,改善 Web App以媲美Native的流…

HttPClient简介及示例:学习如何与Web服务器进行通信

文章目录 前言一、引入依赖二、使用步骤1.创建被调用者2.创建调用者三、结果被调用者服务:调用者服务: 总结 前言 欢迎来到本篇博客,这是一个关于HttPClient的入门案例的指南。🎉 在今天的网络世界中,与服务器进行数据…

qt.qpa.plugin:找不到Qt平台插件“wayland“|| (下载插件)Ubuntu上解决方案

相信大家也都知道这个地方应该做什么,当然是下载这个qt平台的插件wayland,但是很多人可能不知道怎么下载这个插件。 那么我现在要说的这个方法就是针对这种的。 sudo apt install qtwayland5完事儿了奥兄弟们。 看看效果 正常了奥。

FFmpeg5.0源码阅读——FFmpeg大体框架(以GIF转码为示例)

摘要:前一段时间熟悉了下FFmpeg主流程源码实现,对FFmpeg的整体框架有了个大概的认识,因此在此做一个笔记,希望以比较容易理解的文字描述FFmpeg本身的结构,加深对FFmpeg的框架进行梳理加深理解,如果文章中有…

java从入门到起飞(六)——用Socket实现网络通信

文章目录 背景网络编程网络编程三要素 2.DatagramSocket之UDP通信程序2.1 UDP发送数据2.2UDP接收数据2.3 3. Socket之TCP通信程序3.1TCP发送数据3.2TCP接收数据 背景 网络编程 ● 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线…

Matlab图像处理-加法运算

加法运算 图像加法运算的一个应用是将一幅图像的内容叠加到另一幅图像上,生成叠加图像效果,或给图像中每个像素叠加常数改变图像的亮度。 在MATLAB图像处理工具箱中提供的函数imadd()可实现两幅图像的相加或者一幅图像和常量的相加。 程序代码 I1 i…

剑指 Offer 44. 数字序列中某一位的数字(中等)

题目: class Solution { //本题单纯找规律,要注意通过n%digits来判断有几个位数为digits的数 public:int findNthDigit(int n) {long base 9, digits 1; //digits代表位数while(n-base*digits>0){ //该循环是为了确定目标数字所在…

指针(一)------指针概念+指针类型+野指针+指针运算+二级指针

💓博主csdn个人主页:小小unicorn ⏩专栏分类:C语言 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 指针(一) 指针是什么指针…

WordPress关注公众号可见内容插件源码

Wordpress公众号引流工具——关注公众号可见内容插件推荐 通过关注微信公众号,获取随机验证码从而获得隐藏文本的访问权限。 插件特点 隐藏内容扫码关注获取验证码 可以作为引流公众号 支持无必须API接口,无备案域名也可以 自定义验证接口URL 自定…

java八股文面试[数据库]——B树和B+树的区别

B树是一种树状数据结构,它能够存储数据、对其进行排序并允许以O(logn)的时间复杂度进行查找、顺序读取、插入和删除等操作。 1、B树的特性 B树中允许一个结点中包含多个key,可以是3个、4个、5个甚至更多,并不确定,需要看具体的实…

Linux——常用命令大汇总(带你快速入门Linux)

纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。 💬文章目录 一.终端和shell命令解析器终端和shell命令解析器概述终端提示符的格式常用快捷键 二.Linux命令格式帮助文档:man 三.目录基础知识Wind…

LabVIEW是如何控制硬件的?

概述 工程 师 和 科学 家 可以 使用 LabVIEW 与 数千 种 不同 的 硬件 设备 无缝 集成, 并 通过 方便 的 功能 和 跨 所有 硬件 的 一致 编 程 框架 帮助 节省 开发 时间。 内容 通过更简单的系统集成节省开发时间 连接到任何硬件 NI 硬件 第三方硬件 快速找到…