欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

現(xiàn)代的服務(wù)端技術(shù)棧:Golang/Protobuf/gRPC詳解

電子設(shè)計 ? 來源:電子設(shè)計 ? 作者:電子設(shè)計 ? 2020-12-25 17:32 ? 次閱讀

譯注:

并發(fā)與并行:并發(fā)是虛擬的并行,比如通過時間切片技術(shù)在單核CPU上運(yùn)行多個任務(wù),讓每個使用者“以為”自己在獨(dú)占這一CPU資源;并行是實(shí)際的同一時間多任務(wù)同時運(yùn)行,多數(shù)是指在多核CPU的場景下。

隊(duì)列與雙端隊(duì)列:隊(duì)列遵循先入先出的原則,從一端存數(shù),從另一端取數(shù),雙端隊(duì)列支持從隊(duì)列的兩端存數(shù)和取數(shù)。

阻塞和非阻塞:阻塞和非阻塞描述了程序等待返回結(jié)果時的狀態(tài),阻塞代表不返回結(jié)果就掛起,不進(jìn)行任何操作;非阻塞是在沒返回結(jié)果時可以執(zhí)行其他任務(wù)。

合作和搶占:高優(yōu)先級任務(wù)可以打斷其他正在運(yùn)行的低優(yōu)先級任務(wù),則調(diào)度器是搶占式的;反之,則是合作式的。

服務(wù)端編程的陣營中有很多新面孔,一水兒的谷歌血統(tǒng)。在谷歌開始將Golang應(yīng)用于其產(chǎn)品系統(tǒng)后,Golang快速的吸引了大量的關(guān)注。隨著微服務(wù)架構(gòu)的興起,人們開始關(guān)注一些現(xiàn)代的數(shù)據(jù)通信解決方案,如gRPC和Protobuf。在本文中,我們會對以上這些概念作一些簡要的介紹。

一、Golang

Golang又稱Go語言,是一個開源的、多用途的編程語言,由Google研發(fā),并由于種種原因,正在日益流行。Golang已經(jīng)有10年的歷史,并且據(jù)Google稱已經(jīng)在生產(chǎn)環(huán)境中使用了接近7年的時間,這一點(diǎn)可能讓大多數(shù)人大跌眼鏡。

Golang的設(shè)計理念是,簡單、現(xiàn)代、易于理解和快速上手。Golang的創(chuàng)造者將Golang設(shè)計為一個普通的程序員可以在一個周末的時間就可以掌握,并達(dá)到使用Golang進(jìn)行工作的程度。這一點(diǎn)我已經(jīng)親身證實(shí)。Golang的創(chuàng)造者,都是C語言原始草案的專家組成員,可以說,Golang根紅苗正,值得信賴。

理都懂,但話說回來,為什么我們需要另一門編程語言呢

多數(shù)場景下,確實(shí)并不需要。事實(shí)上,Go語言并不能解決其他語言或工具無法解決的新問題。但在一些強(qiáng)調(diào)效率、優(yōu)雅與直觀的場景下,人們通常會面臨一系列的相關(guān)問題,這正是Go所致力于解決的領(lǐng)域。Go的主要特點(diǎn)是:

一流的并發(fā)支持

內(nèi)核十分簡單,語言優(yōu)雅、現(xiàn)代

高性能

提供現(xiàn)代軟件開發(fā)所需要的原生工具支持

我將簡要介紹Go是如何提供上述的支持的。在Go語言的官網(wǎng)可以了解更多的特性和細(xì)節(jié)。

一流的并發(fā)支持

并發(fā)是多數(shù)服務(wù)端應(yīng)用所需要考慮的主要問題之一,考慮到現(xiàn)代微處理器的特性,并發(fā)也成為編程語言的主要關(guān)切之一。Go語言引入了“goroutine”的理念??梢园选癵oroutine”理解為一個“輕量級的用戶空間線程”(現(xiàn)實(shí)中,當(dāng)然遠(yuǎn)比這要復(fù)雜得多,同一線程可能會附著多路的goroutine,但這樣的提法可以讓你有一個大致的概念)。所謂“輕量級”,可以這樣理解,由于采用了十分袖珍的堆棧,你可以同時啟動數(shù)以百萬計的goroutine,事實(shí)上這也是Go語言官方所推薦的方式。在Go語言中,任何函數(shù)或方法都可以生成一個goroutine。比如,只需要運(yùn)行“go myAsyncTask()”就可以從“myAsyncTask”函數(shù)生成一個goroutine。示例代碼如下:

// This function performs the given task concurrently by spawing a goroutine

// for each of those tasks.

func performAsyncTasks(task []Task) {

for _, task := range tasks {

// This will spawn a separate goroutine to carry out this task.

// This call is non-blocking

go task.Execute()

goroutineExample.go hosted with ? by GitHub

(左右滑動查看全部代碼)

怎么樣,是不是很簡單?Go是一門簡單的語言,因此注定是以這樣的方式來解決問題。你可以為每個獨(dú)立的異步任務(wù)生成一個goroutine而不需要顧慮太多事情。如果處理器支持多核運(yùn)行,Go語言運(yùn)行時會自動的以并行的方式運(yùn)行所有的goroutine。那么,goroutine之間是如何通信的呢,答案是channel。

“channel”也是Go語言的一個概念,用于進(jìn)行g(shù)oroutine之間的通信。通過channel,你可以向另一個goroutine傳遞各種信息(比如Go語言概念里的type或者struct甚至是channel)。一個channel大體上是一個“雙端阻塞隊(duì)列”(也可以單端的)。如果需要goroutine基于特定條件觸發(fā)下一步的行動,也可以利用channel來實(shí)現(xiàn)goroutine的協(xié)作阻塞任務(wù)模式。

在編寫異步或者并發(fā)的代碼時,goroutine和channel這兩個概念賦予了編程者大量的靈活性和簡便性??梢约撕苋菀椎慕⑵渌苡杏玫膸?,比如goroutine pool,舉個簡單的例子:

package executor

import (

"log"

"sync/atomic"

// The Executor struct is the main executor for tasks.

// 'maxWorkers' represents the maximum number of simultaneous goroutines.

// 'ActiveWorkers' tells the number of active goroutines spawned by the Executor at given time.

// 'Tasks' is the channel on which the Executor receives the tasks.

// 'Reports' is channel on which the Executor publishes the every tasks reports.

// 'signals' is channel that can be used to control the executor. Right now, only the termination

// signal is supported which is essentially is sending '1' on this channel by the client.

type Executor struct {

maxWorkers int64

ActiveWorkers int64

Tasks chan Task

Reports chan Report

signals chan int

// NewExecutor creates a new Executor.

// 'maxWorkers' tells the maximum number of simultaneous goroutines.

// 'signals' channel can be used to control the Executor.

func NewExecutor(maxWorkers int, signals chan int) *Executor {

chanSize := 1000

if maxWorkers > chanSize {

chanSize = maxWorkers

executor := Executor{

maxWorkers: int64(maxWorkers),

Tasks: make(chan Task, chanSize),

Reports: make(chan Report, chanSize),

signals: signals,

go executor.launch()

return &executor

// launch starts the main loop for polling on the all the relevant channels and handling differents

// messages.

func (executor *Executor) launch() int {

reports := make(chan Report, executor.maxWorkers)

for {

select {

case signal := <-executor.signals:

if executor.handleSignals(signal) == 0 {

return 0

case r := <-reports:

executor.addReport(r)

default:

if executor.ActiveWorkers < executor.maxWorkers && len(executor.Tasks) > 0 {

task := <-executor.Tasks

atomic.AddInt64(&executor.ActiveWorkers, 1)

go executor.launchWorker(task, reports)

// handleSignals is called whenever anything is received on the 'signals' channel.

// It performs the relevant task according to the received signal(request) and then responds either

// with 0 or 1 indicating whether the request was respected(0) or rejected(1).

func (executor *Executor) handleSignals(signal int) int {

if signal == 1 {

log.Println("Received termination request...")

if executor.Inactive() {

log.Println("No active workers, exiting...")

executor.signals <- 0

return 0

executor.signals <- 1

log.Println("Some tasks are still active...")

return 1

// launchWorker is called whenever a new Task is received and Executor can spawn more workers to spawn

// a new Worker.

// Each worker is launched on a new goroutine. It performs the given task and publishes the report on

// the Executor's internal reports channel.

func (executor *Executor) launchWorker(task Task, reports chan<- Report) {

report := task.Execute()

if len(reports) < cap(reports) {

reports <- report

} else {

log.Println("Executor's report channel is full...")

atomic.AddInt64(&executor.ActiveWorkers, -1)

// AddTask is used to submit a new task to the Executor is a non-blocking way. The Client can submit

// a new task using the Executor's tasks channel directly but that will block if the tasks channel is

// full.

// It should be considered that this method doesn't add the given task if the tasks channel is full

// and it is up to client to try again later.

func (executor *Executor) AddTask(task Task) bool {

if len(executor.Tasks) == cap(executor.Tasks) {

return false

executor.Tasks <- task

return true

// addReport is used by the Executor to publish the reports in a non-blocking way. It client is not

// reading the reports channel or is slower that the Executor publishing the reports, the Executor's

// reports channel is going to get full. In that case this method will not block and that report will

// not be added.

func (executor *Executor) addReport(report Report) bool {

if len(executor.Reports) == cap(executor.Reports) {

return false

executor.Reports <- report

return true

// Inactive checks if the Executor is idle. This happens when there are no pending tasks, active

// workers and reports to publish.

func (executor *Executor) Inactive() bool {

return executor.ActiveWorkers == 0 && len(executor.Tasks) == 0 && len(executor.Reports) == 0

executor.go hosted with ? by GitHub

(左右滑動查看全部代碼)

內(nèi)核十分簡單,語言優(yōu)雅、現(xiàn)代

與其他多數(shù)的現(xiàn)代語言不同,Golang本身并沒有提供太多的特性。事實(shí)上,嚴(yán)格限制特性集的范圍正是Go語言的顯著特征,且Go語言著意于此。Go語言的設(shè)計與Java的編程范式不同,也不支持如Python一樣的多語言的編程范式。Go只是一個編程的骨架結(jié)構(gòu)。除了必要的特性,其他一無所有。

看過Go語言之后,第一感覺是其不遵循任何特定的哲學(xué)或者設(shè)計指引,所有的特性都是以引用的方式解決某一個特定的問題,不會畫蛇添足做多余的工作。比如,Go語言提供方法和接口但沒有類;Go語言的編譯器生成動態(tài)鏈接庫,但同時保留垃圾回收器;Go語言有嚴(yán)格的類型但不支持泛型;Go語言有一個輕量級的運(yùn)行時但不支持異常。

Go的這一設(shè)計理念的主要用意在于,在表達(dá)想法、算法或者編碼的環(huán)節(jié),開發(fā)者可以盡量少想或者不去想“在某種編程語言中處理此事的最佳方案”,讓不同的開發(fā)者可以更容易理解對方的代碼。不支持泛型和異常使得Go語言并不那么完美,也因此在很多場景下束手束腳 ,因此在“Go 2”版本中,官方加入了對這些必要特性的考慮。

高性能

單線程的執(zhí)行效率并不足以評估一門語言的優(yōu)劣,當(dāng)語言本身聚焦于解決并發(fā)和并行問題的時候尤其如此。即便如此,Golang還是跑出了亮眼的成績,僅次于一些硬核的系統(tǒng)編程語言,如C/C++/Rust等等,并且Golang還在不斷的改進(jìn)??紤]到Go是有垃圾回收機(jī)制的語言,這一成績實(shí)際上相當(dāng)?shù)牧钊擞∠笊羁?,這使得Go語言的性能可以應(yīng)付幾乎所有的使用場景。

(Image Source: Medium)

提供現(xiàn)代軟件開發(fā)所需要的原生工具支持

是否采用一種新的語言或工具,直接取決于開發(fā)者體驗(yàn)的好壞。就Go語言來說,其工具集是用戶采納的主要考量。同最小化的內(nèi)核一樣,Go的工具集也采用了同樣的設(shè)計理念,最小化,但足夠應(yīng)付需要。執(zhí)行所有Go語言工具,都采用 go 命令及其子命令,并且全部是以命令行的方式。

Go語言中并沒有類似pip或者npm這類包管理器。但只需要下面的命令,就可以得到任何的社區(qū)包:

go get github.com/farkaskid/WebCrawler/blob/master/executor/executor.go

(左右滑動查看全部代碼)

是的,這樣就行??梢灾苯訌腉ithub或其他地方拉取所需要的包。所有的包都是源代碼文件的形態(tài)。

對于package.json這類的包,我沒有看到與 goget 等價的命令。事實(shí)上也沒有。在Go語言中,無須在一個單一文件中指定所有的依賴,可以在源文件中直接使用下面的命令:

import "github.com/xlab/pocketsphinx-go/sphinx"

(左右滑動查看全部代碼)

那么,當(dāng)執(zhí)行g(shù)o build命令的時候,運(yùn)行時會自動的運(yùn)行 goget 來獲取所需要的依賴。完整的源碼如下:

package main

import (

"encoding/binary"

"bytes"

"log"

"os/exec"

"github.com/xlab/pocketsphinx-go/sphinx"

pulse "github.com/mesilliac/pulse-simple" // pulse-simple

var buffSize int

func readInt16(buf []byte) (val int16) {

binary.Read(bytes.NewBuffer(buf), binary.LittleEndian, &val)

return

func createStream() *pulse.Stream {

ss := pulse.SampleSpec{pulse.SAMPLE_S16LE, 16000, 1}

buffSize = int(ss.UsecToBytes(1 * 1000000))

stream, err := pulse.Capture("pulse-simple test", "capture test", &ss)

if err != nil {

log.Panicln(err)

return stream

func listen(decoder *sphinx.Decoder) {

stream := createStream()

defer stream.Free()

defer decoder.Destroy()

buf := make([]byte, buffSize)

var bits []int16

log.Println("Listening...")

for {

_, err := stream.Read(buf)

if err ?。?nil {

log.Panicln(err)

for i := 0; i < buffSize; i += 2 {

bits = append(bits, readInt16(buf[i:i+2]))

process(decoder, bits)

bits = nil

func process(dec *sphinx.Decoder, bits []int16) {

if !dec.StartUtt() {

panic("Decoder failed to start Utt")

dec.ProcessRaw(bits, false, false)

dec.EndUtt()

hyp, score := dec.Hypothesis()

if score > -2500 {

log.Println("Predicted:", hyp, score)

handleAction(hyp)

func executeCommand(commands ...string) {

cmd := exec.Command(commands[0], commands[1:]...)

cmd.Run()

func handleAction(hyp string) {

switch hyp {

case "SLEEP":

executeCommand("loginctl", "lock-session")

case "WAKE UP":

executeCommand("loginctl", "unlock-session")

case "POWEROFF":

executeCommand("poweroff")

func main() {

cfg := sphinx.NewConfig(

sphinx.HMMDirOption("/usr/local/share/pocketsphinx/model/en-us/en-us"),

sphinx.DictFileOption("6129.dic"),

sphinx.LMFileOption("6129.lm"),

sphinx.LogFileOption("commander.log"),

dec, err := sphinx.NewDecoder(cfg)

if err ?。?nil {

panic(err)

listen(dec)

client.go hosted with ? by GitHub

(左右滑動查看全部代碼)

上述的代碼將把所有的依賴聲明與源文件綁定在一起。

如你所見,Go語言是如此的簡單、最小化但仍足夠滿足需要并且十分優(yōu)雅。Go語言提供了諸多的直接的工具支持,既可用于單元測試,也可以用于benchmark的火焰圖。誠然,正如前面所講到的特性集方面的限制,Go語言也有其缺陷。比如, goget 并不支持版本化,一旦源文件中引用了某個URL,就將鎖定于此。但是,Go也還在逐漸的演進(jìn),一些依賴管理的工具也正在涌現(xiàn)。

Golang最初是設(shè)計用來解決Google的一些產(chǎn)品問題,比如厚重的代碼庫,以及滿足編寫高效并發(fā)類應(yīng)用的急迫需求。在需要利用現(xiàn)代處理器的多核特性的場景,Go語言使得在應(yīng)用和庫文件的編程方面變得更加容易。并且,這些都不需要開發(fā)者來考慮。Go語言是一門現(xiàn)代的編程語言,簡單是其主旨,Go語言永遠(yuǎn)不會考慮超過這一主旨的范疇。

二、Protobuf(Protocol Buffers)

Protobuf 或者說 Protocol Buffers是由Google研發(fā)的一種二進(jìn)制通信格式,用以對結(jié)構(gòu)化數(shù)據(jù)進(jìn)行序列化。格式是什么意思?類似于JSON這樣?是的。Protobuf已經(jīng)有10年的歷史,在Google內(nèi)部也已經(jīng)使用了一段時間。

既然已經(jīng)有了JSON這種通信格式,并且得到了廣泛的應(yīng)用,為什么需要Protobuf?

與Golang一樣,Protobuf實(shí)際上并有解決任何新的問題,只是在解決現(xiàn)有的問題方面更加高效,更加現(xiàn)代化。與Golang不同的是,Protobuf并不一定比現(xiàn)存的解決方案更加優(yōu)雅。下面是Protobuf的主要特性:

Protobuf是一種二進(jìn)制格式,不同于JSON和XML,后者是基于文本的也因此相對比較節(jié)省空間。

Protobuf提供了對于schema的精巧而直接的支持

Protobuf為生成解析代碼和消費(fèi)者代碼提供直接的多語言支持。

Protobuf的二進(jìn)制格式帶來的是傳輸速度方面的優(yōu)化

那么Protobuf是不是真的很快?簡單回答,是的。根據(jù)Google Developer的數(shù)據(jù),相對于XML來說,Protobuf在體積上只有前者的1/3到1/10,在速度上卻要快20到100倍。毋庸置疑的是,由于采用了二進(jìn)制格式,序列化的數(shù)據(jù)對于人類來說是不可讀的。

(Image Source: Beating JSON performance with Protobuf)

相對其他傳輸協(xié)議格式來說,Protobuf采用了更有規(guī)劃性的方式。首先需要定義 .proto 文件,這種文件與schema類似,但更強(qiáng)大。在 .proto 文件中定義消息結(jié)構(gòu),哪些字段是必選的哪些是可選的,以及字段的數(shù)據(jù)類型等。接下來,Protobuf編譯器會生成用于數(shù)據(jù)訪問的類,開發(fā)者可以在業(yè)務(wù)邏輯中使用這些類來更方便的進(jìn)行數(shù)據(jù)傳輸。

觀察某個服務(wù)的 .proto 文件,可以清晰的獲知通信的細(xì)節(jié)以及暴露的特性。一個典型的 .proto 文件類似如下:

message Person {

required string name = 1;

required int32 id = 2;

optional string email = 3;

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];

repeated PhoneNumber phone = 4;

protobufExample.proto hosted with ? by GitHub

(左右滑動查看全部代碼)

曝個料:Stack Overflow的大牛Jon Skeet也是Protobuf項(xiàng)目的主要貢獻(xiàn)者之一。

三、gRPC

gRPC,物如其名,是一種功能齊備的現(xiàn)代的RPC框架,提供了諸多內(nèi)置支持的機(jī)制,如負(fù)載均衡、跟蹤、健康檢查和認(rèn)證等。gRPC由Google在2015年開源,并由此日益火爆。

既然已經(jīng)有了REST,還搞個RPC做什么?

在SOA架構(gòu)的時代,有相當(dāng)長的時間,基于WSDL的SOAP協(xié)議是系統(tǒng)間通信的解決方案。彼時,通信協(xié)議的定義是十分嚴(yán)格的,龐大的單體架構(gòu)系統(tǒng)暴露大量的接口用于擴(kuò)展。

隨著B/S理念的興起,服務(wù)器和客戶端開始解耦,在這樣的架構(gòu)下,即使客戶端和服務(wù)端分別進(jìn)行獨(dú)立的編碼,也不影響對服務(wù)的調(diào)用??蛻舳讼氩樵円槐緯男畔ⅲ?wù)端會根據(jù)請求提供相關(guān)的列表供客戶端瀏覽。REST范式主要解決的就是這種場景下的問題,REST允許服務(wù)端和客戶端可以自由的通信,而不需要定義嚴(yán)格的契約以及獨(dú)有的語義。

從某種意義上講,此時的服務(wù)已經(jīng)開始變得像是單體式架構(gòu)系統(tǒng)一樣,對于某個特定的請求,會返回一坨毫無必要的數(shù)據(jù),用以滿足客戶端的“瀏覽”需求。但這并不是所有場景下都會發(fā)生的情況,不是么?

跨入微服務(wù)的時代

采用微服務(wù)架構(gòu)理由多多。最常提及的事實(shí)是,單體架構(gòu)太難擴(kuò)展了。以微服務(wù)架構(gòu)設(shè)計大型系統(tǒng),所有的業(yè)務(wù)和技術(shù)需求都傾向于實(shí)現(xiàn)成互相合作的組件,這些組件就是“微”服務(wù)。

微服務(wù)不需要以包羅萬象的信息響應(yīng)用戶請求,而僅需要根據(jù)請求完成特定的任務(wù)并給出所需要的回應(yīng)。理想情況下,微服務(wù)應(yīng)該像一堆可以無縫組裝的函數(shù)。

使用REST做為此類服務(wù)的通信范式變得不那么有效。一方面,采用REST API確實(shí)可以讓服務(wù)的表達(dá)能力更強(qiáng),但同時,如果這種表達(dá)的能力既非必要也并不出自設(shè)計者的本意,我們就需要根據(jù)不同的因素考慮其他范式了。

gRPC嘗試在如下的技術(shù)方面改進(jìn)傳統(tǒng)的HTTP請求:

默認(rèn)支持HTTP/2協(xié)議,并可以享受該協(xié)議帶來的所有好處

采用Protobuf格式用于機(jī)器間通信

得益于HTTP/2協(xié)議,提供了對流式調(diào)用的專有支持

對所有常用的功能提供了插件化的支持,如認(rèn)證、跟蹤、負(fù)載均衡和健康檢查等。

當(dāng)然,既然是RPC框架,仍舊會有服務(wù)定義和接口描述語言(DSL)的相關(guān)概念,REST世代的開發(fā)者可能會感覺這些概念有些格格不入,但是由于gRPC采用Protobuf做為通信格式,就不會顯得像以前那么笨拙。

Protobuf的設(shè)計理念使得其既是一種通信格式,又可以是一種協(xié)議規(guī)范工具,在此過程中無需做任何額外的工作。一個典型的gRPC服務(wù)定義類似如下:

service HelloService {

rpc SayHello (HelloRequest) returns (HelloResponse);

message HelloRequest {

string greeting = 1;

message HelloResponse {

string reply = 1;

serviceDefinition.proto hosted with ? by GitHub

(左右滑動查看全部代碼)

只需要為服務(wù)定義一個 .proto 文件,并在其中描述接口名稱,服務(wù)的需求,以及以Protobuf格式返回的消息即可。Protobuf編譯器會生成客戶端和服務(wù)端代碼??蛻舳丝梢灾苯诱{(diào)用這些代碼,服務(wù)端可以用這些代碼實(shí)現(xiàn)API來填充業(yè)務(wù)邏輯。

四、結(jié)語

Golang,Protobuf和gRPC是現(xiàn)代服務(wù)端編程的后起之秀。Golang簡化了并發(fā)/并行應(yīng)用的編程,gRPC和Protobuf的結(jié)合提供了更高效的通信并同時提供了更愉悅的開發(fā)者體驗(yàn)。

審核編輯:符乾江
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4831

    瀏覽量

    69112
  • 服務(wù)端
    +關(guān)注

    關(guān)注

    0

    文章

    66

    瀏覽量

    7065
收藏 人收藏

    評論

    相關(guān)推薦

    SSR與微服務(wù)架構(gòu)的結(jié)合應(yīng)用

    隨著互聯(lián)網(wǎng)技術(shù)的快速發(fā)展,前端技術(shù)不斷更新迭代,后端架構(gòu)也經(jīng)歷了從單體應(yīng)用到微服務(wù)的變革。在這個過程中,服務(wù)端渲染(SSR)作為一種提升頁
    的頭像 發(fā)表于 11-18 11:34 ?410次閱讀

    【米爾NXP i.MX 93開發(fā)板試用評測】4、使用golang搭建Modbus 服務(wù)

    負(fù)責(zé)處理來自客戶(通常稱為Modbus客戶或從站)的請求,并根據(jù)請求提供相應(yīng)的數(shù)據(jù)或執(zhí)行操作。 快速開發(fā)modbus服務(wù)器 可以使用golang快速部署一個modbus
    發(fā)表于 09-21 22:51

    調(diào)試stm32的TCP服務(wù)端程序,會導(dǎo)致hard fault的原因?

    最近調(diào)試stm32的TCP服務(wù)端程序,遇到了想不明白的問題,具體過程如下: 使用的是rt-thread4.1.0的內(nèi)核; 通過串口和esp32-c3通信; 啟用at_socket; 建立tcp
    發(fā)表于 09-13 06:59

    軟通動力數(shù)據(jù)庫全服務(wù),助力企業(yè)數(shù)據(jù)庫體系全面升級

    。在企業(yè)節(jié)與"數(shù)博會"展區(qū),軟通動力受邀分享數(shù)據(jù)庫專業(yè)服務(wù)解決方案,并重點(diǎn)展示以全服務(wù)為核心的數(shù)智化能力。 軟通動力高級數(shù)據(jù)庫服務(wù)
    的頭像 發(fā)表于 09-05 15:30 ?385次閱讀
    軟通動力數(shù)據(jù)庫全<b class='flag-5'>棧</b><b class='flag-5'>服務(wù)</b>,助力企業(yè)數(shù)據(jù)庫體系全面升級

    使用NS1串口服務(wù)器HTTP模式上傳服務(wù)器數(shù)據(jù)

    HTTP協(xié)議工作于客戶-服務(wù)端架構(gòu)之上。瀏覽器作為HTTP客戶通過URL向HTTP服務(wù)端即Web服務(wù)器發(fā)送所有請求。Web
    的頭像 發(fā)表于 08-30 12:36 ?490次閱讀
    使用NS1串口<b class='flag-5'>服務(wù)</b>器HTTP模式上傳<b class='flag-5'>服務(wù)</b>器數(shù)據(jù)

    LwIP協(xié)議源碼詳解—TCP/IP協(xié)議的實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《LwIP協(xié)議源碼詳解—TCP/IP協(xié)議的實(shí)現(xiàn).pdf》資料免費(fèi)下載
    發(fā)表于 07-03 11:22 ?3次下載

    請問ESP32作為藍(lán)牙服務(wù)端如何修改MTU?

    我們的工程把esp32當(dāng)作藍(lán)牙服務(wù)端讓電腦去連,由于一些老電腦上沒有藍(lán)牙,要用外置藍(lán)牙驅(qū)動,默認(rèn)MTU只有23,但是說明上驅(qū)動是支持最大mtu的,所以有什么辦法可以通過服務(wù)端去修改mtu嗎
    發(fā)表于 06-27 07:47

    請問esp_local_ctrl中服務(wù)端如何主動發(fā)消息?

    請問,在wifi本地控制例程esp_local_ctrl中,設(shè)備作為服務(wù)端在客戶沒有請求的情況下,如何主動發(fā)送消息給客戶呢?
    發(fā)表于 06-06 06:11

    服務(wù)端測試包括什么類型

    服務(wù)端測試是確保軟件系統(tǒng)在服務(wù)器端正常運(yùn)行和滿足性能要求的重要環(huán)節(jié)。本文將詳細(xì)介紹服務(wù)端測試的類型、方法和最佳實(shí)踐。 1. 服務(wù)端測試的定義 服務(wù)端
    的頭像 發(fā)表于 05-30 16:03 ?861次閱讀

    服務(wù)端測試是web測試嗎為什么

    服務(wù)端測試和Web測試是兩個不同的概念,但它們在軟件開發(fā)和測試過程中是相互關(guān)聯(lián)的。本文將詳細(xì)解釋這兩個概念以及它們之間的關(guān)系。 服務(wù)端測試 服務(wù)端測試主要關(guān)注服務(wù)器端的軟件組件,這些組
    的頭像 發(fā)表于 05-30 15:30 ?694次閱讀

    服務(wù)端測試和客戶測試區(qū)別在哪

    服務(wù)端測試和客戶測試是軟件開發(fā)過程中的兩個重要環(huán)節(jié),它們分別針對服務(wù)器端和客戶的軟件進(jìn)行測試。本文將詳細(xì)介紹服務(wù)端測試和客戶
    的頭像 發(fā)表于 05-30 15:27 ?3449次閱讀

    服務(wù)端的測試主要是測什么內(nèi)容

    服務(wù)端測試是軟件開發(fā)過程中的一個重要環(huán)節(jié),主要目的是確保服務(wù)端程序的穩(wěn)定性、性能、安全性和可靠性。 功能測試 功能測試是服務(wù)端測試的基礎(chǔ),主要驗(yàn)證服務(wù)端程序是否按照需求實(shí)現(xiàn)了所有功能。
    的頭像 發(fā)表于 05-30 15:24 ?4307次閱讀

    智行者聯(lián)合清華完成國內(nèi)首套全自動駕駛系統(tǒng)的開放道路測試

    近日,智行者與清華大學(xué)車輛學(xué)院李克強(qiáng)院士、李升波教授領(lǐng)導(dǎo)的研究團(tuán)隊(duì),完成了國內(nèi)首套全自動駕駛系統(tǒng)的開放道路測試。
    的頭像 發(fā)表于 04-22 09:24 ?847次閱讀
    智行者聯(lián)合清華完成國內(nèi)首套全<b class='flag-5'>棧</b>式<b class='flag-5'>端</b>到<b class='flag-5'>端</b>自動駕駛系統(tǒng)的開放道路測試

    PLC采用HTTP協(xié)議JSON文件對接MES等服務(wù)系統(tǒng)平臺

    文件的字段與PLC寄存器地址,配置URL即可。支持POST/GET/PUT等多種方法。智能網(wǎng)關(guān)IGT-DSER可同時作為HTTP協(xié)議的客戶服務(wù)端。作為客戶通訊時將JSON文件提交給HTTP
    發(fā)表于 03-25 14:25

    lwip stm407作為服務(wù)端 pc連接不上怎么解決?

    lwip stm407作為服務(wù)端 pc連接不上
    發(fā)表于 03-20 06:32