찾다
백엔드 개발GolangGo 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

socker编程

我们所학적인TCPTCPUDP,统称为SockerUDP,统称为Socker编程,也叫做

套接字编程多台机器要实现互상통讯,其实是一个不常复杂的过程,底层从 铺设网线网线接口 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

응용 프로그램 레이어로 이동QQQQ微信等软件。

如果没有一套标准,每次使用都要自己去实现,可能每个程序员都不是掉头发那么简单了!

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

有了Socker之后,Socker会在应用层之前,将各种繁琐的的底层操作隐藏,我们可能只需要Socker.TCP就实现了TCP, WeChat

및 기타 소프트웨어. 🎜🎜

🎜if 정해진 표준은 없습니다. 사용할 때마다 직접 구현해야 합니다. 어쩌면 모든 프로그래머는 머리가 빠지는 것만큼 간단하지 않을 수도 있습니다. 🎜🎜

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사🎜🎜 알겠습니다🎜🎜 소커 🎜🎜 이후 🎜🎜Socker🎜🎜는 애플리케이션 계층 이전에 다양한 지루한 기본 작업을 숨길 것입니다. 우리는 🎜🎜Socker.TCP🎜🎜가 달성되었습니다🎜🎜TCP🎜🎜 프로토콜 통신. 🎜🎜🎜

Go 언어 TCP

TCP는 안정적이고 신뢰할 수 있는 긴 연결입니다.

통신이 필요하므로 두 개의 터미널이 있어야 하며 적어도 하나는 server입니다. 하나는 클라이언트 입니다. Taobao를 열 때마다 연결해야 합니다. 물론 Taobao가 직접 TCP은 아닙니다.

Server

Go에서 서버를 구현하면 서버에서의 동시성은 매우 간단합니다. 코루틴이 각 연결을 처리하도록 하면 됩니다!

Code

package main


import (
    "bufio"
    "fmt"
    "net"
)


func process(conn net.Conn) {
    defer conn.Close()
    for {
        reader := bufio.NewReader(conn)
        buf := make([]byte, 128)
        n, err := reader.Read(buf)
        if err != nil {
            fmt.Println("数据读取失败", err)
            return
        }
        recvStr := string(buf[:n])
        fmt.Println("客户端发送过来的值:", recvStr)
}


}
func main() {
    lister, err := net.Listen("tcp", "0.0.0.0:8008")
    if err != nil {
        fmt.Println("连接失败", err)
}
    for {
        fmt.Println("等待建立连接,此时会阻塞住")
        conn, err := lister.Accept() //等待建立连接
        fmt.Println("连接建立成功,继续")
        if err != nil {
            fmt.Println("建立连接失败", err)
            //继续监听下次链接
            continue
        }
        go process(conn)
}
}

Client

클라이언트는 상대적으로 매우 간단하며 동시성이 필요하지 않고 연결만 필요합니다.

代码

package main


import (
    "bufio"
    "fmt"
    "net"
    "os"
)


//客户端
func main() {
    conn, err := net.Dial("tcp", "192.168.10.148:8008")
    if err != nil {
        fmt.Println("连接服务器失败",err)
}
    defer conn.Close()
    inputReader:=bufio.NewReader(os.Stdin)
    for{
        fmt.Println(":")
        input,_:=inputReader.ReadString('\n')
        _, err = conn.Write([]byte(input))
        if err != nil {
            fmt.Println("发送成功")
        }
}
}

执行结果

就这样,我们实现了服务端并发的处理所有客户端的请求。

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

粘包

我们先看一下什么是粘包。

服务端

package main


import (
    "bufio"
    "fmt"
    "io"
    "net"
)


func process(conn net.Conn) {
    defer conn.Close()
    reader := bufio.NewReader(conn)
    buf := make([]byte, 1024)
    for {
        n, err := reader.Read(buf)
        //读完了
        if err == io.EOF {
            fmt.Println("读完了")
            break
        }
        //读错了
        if err != nil {
            fmt.Println("数据读取失败", err)
            return
        }
        recvStr := string(buf[:n])
        fmt.Println("客户端发送过来的值:", recvStr)
}


}
func main() {
    lister, err := net.Listen("tcp", "0.0.0.0:8008")
    if err != nil {
        fmt.Println("连接失败", err)
        return
}
    defer lister.Close()
    for {
        fmt.Println("等待建立连接,此时会阻塞住")
        conn, err := lister.Accept() //等待建立连接
        fmt.Println("连接建立成功,继续")
        if err != nil {
            fmt.Println("建立连接失败", err)
            //继续监听下次链接
            continue
        }
        go process(conn)
}
}

客户端

package main


import (
    "fmt"
    "net"
)


//客户端
func main() {
    conn, err := net.Dial("tcp", "192.168.10.148:8008")
    if err != nil {
        fmt.Println("连接服务器失败", err)
}
    defer conn.Close()
    for i := 0; i < 10; i++ {
        sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads "
        conn.Write([]byte(sendStr))
        time.Sleep(time.Second)
}
}

注意:18行代码睡眠了1s

执行结果

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

코드 18번째 줄을 주석 처리하면

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

실행 결과

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

이 한 줄에 바로 추가되는데 뭐죠? 무슨 일이 일어나고 있는 걸까요? 이전과 같아야 하지 않나요? ? ?

값이 전송될 때마다 그곳에서 수신됩니다. 이것을 어떻게 하나로 통합할 수 있나요? ! !

이유

가장 큰 이유는 우리가 운영 체제에서 실행되는 소프트웨어인 애플리케이션 레이어소프트웨어이기 때문입니다. 운영 체제 관련 인터페이스 를 호출하여 전송됩니다. 그런 다음 운영 체제는 여러 가지 복잡한 작업을 거쳐 다른 시스템

으로 보냅니다. , 운영 체제에는 기본적으로 버퍼가 특정 크기인 경우 버퍼가 가득 차지 않으면 데이터가 전송되지 않습니다. 따라서 위의 클라이언트가 데이터를 보낼 때 시스템 버퍼가 가득 차지 않습니다. 그리고 항상 운영체제 버퍼에 눌려져 있는데, 결국 데이터가 없다는 걸 발견해서 한꺼번에 서버로 보냈습니다

그런데 왜sleep(1)sleep(1)又管用了呢?这是因为缓冲区不止一个程序在用,1s的时间足够其他程序将缓冲区打满,然后各自发各自的数据,这也是为什么第一次操作没问题,第二次有问题,因为第二次全部都是我们客户端打满的

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

解决粘包

工具函数

我们将解包封包的函数封装一下

socker_sitck/stick.go다시 작동하나요? 이는 버퍼가 두 개 이상의 프로그램에서 사용되기 때문입니다. 1초는 다른 프로그램이 버퍼를 채우고 자체 데이터를 보내는 데 충분한 시간입니다. 첫 번째 작업에는 문제가 없었지만 두 번째에는 문제가 발생했습니다. 두 번째에는 클라이언트에 모든 것이 완전히 로드되었기 때문입니다

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

🎜 끈끈한 가방 해결🎜

🎜도구 기능🎜

🎜패킷 풀기 기능을 캡슐화하겠습니다🎜🎜🎜socker_sitck/stick.go 🎜🎜🎜🎜🎜

package socker_stick


import (
    "bufio"
    "bytes"
    "encoding/binary"
    "fmt"
)


//Encode 将消息编码
func Encode(message string) ([]byte, error) {
    length := int32(len(message))
    var pkg = new(bytes.Buffer)
    //写入消息头
    err := binary.Write(pkg, binary.LittleEndian, length)
    if err != nil {
        fmt.Println("写入消息头失败", err)
        return nil, err
}
    //写入消息实体
    err = binary.Write(pkg, binary.LittleEndian, []byte(message))
    if err != nil {
        fmt.Println("写入消息实体失败", err)
        return nil, err
}
    return pkg.Bytes(), nil
}


//Decode解码消息
func Decode(reader *bufio.Reader) (string, error) {
    //读取信息长度
    lengthByte, _ := reader.Peek(4)
    lengthBuff := bytes.NewBuffer(lengthByte)
    var length int32
    err := binary.Read(lengthBuff, binary.LittleEndian, &length)
    if err != nil {
        return "", err
}
    //BuffRead 返回缓冲区现有的可读的字节数
    if int32(reader.Buffered()) < length+4 {
        return "", err
}
    pack := make([]byte, int(4+length))
    _, err = reader.Read(pack)
    if err != nil {
        return "", err
}
    return string(pack[4:]), nil
}

服务端

package main


import (
    "a3_course/socker_stick"
    "bufio"
    "fmt"
    "io"
    "net"
)


func process(conn net.Conn) {
    defer conn.Close()
    reader := bufio.NewReader(conn)


    for {
        msg, err := socker_stick.Decode(reader)
        //读完了
        if err == io.EOF {
            fmt.Println("读完了")
            break
        }
        //读错了
        if err != nil {
            fmt.Println("数据读取失败", err)
            return
        }


        fmt.Println("客户端发送过来的值:", msg)
}


}
func main() {
    lister, err := net.Listen("tcp", "0.0.0.0:8008")
    if err != nil {
        fmt.Println("连接失败", err)
        return
}
    defer lister.Close()
    for {
        fmt.Println("等待建立连接,此时会阻塞住")
        conn, err := lister.Accept() //等待建立连接
        fmt.Println("连接建立成功,继续")
        if err != nil {
            fmt.Println("建立连接失败", err)
            //继续监听下次链接
            continue
        }
        go process(conn)
}
}

客户端

package main


import (
    "a3_course/socker_stick"
    "fmt"
    "net"
)


//客户端
func main() {
    conn, err := net.Dial("tcp", "192.168.10.148:8008")
    if err != nil {
        fmt.Println("连接服务器失败", err)
}
    defer conn.Close()
    for i := 0; i < 10; i++ {
        sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads "
        data, err := socker_stick.Encode(sendStr)
        if err != nil {
            fmt.Println("编码失败",err)
            return
        }
        conn.Write(data)
        //time.Sleep(time.Second)
}
}

执行结果

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

这次真的不管执行几次,都是这样的结果

对了,只有TCP才有粘包

Go语言UDP

UDP是一个无连接协议,客户端不会在乎服务端有没有问题,客户端只管发,通常用于实时性比较高的领域

例如直播行业

服务端

package main


import (
    "fmt"
    "net"
)


func main() {
    listen, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 8009,
})
    if err != nil {
        panic(fmt.Sprintf("udp启动失败,err:%v", err))
}
    defer listen.Close()
    for{
        var data = make([]byte,1024)
        n, addr, err := listen.ReadFromUDP(data)
        if err != nil {
            panic(fmt.Sprintf("读取数据失败,err:%v", err))
        }
        fmt.Println(string(data[:n]),addr,n)
}
}

客户端

package main


import (
    "fmt"
    "net"
)


func main() {
    socker, err := net.DialUDP("udp", nil, &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 8009,
})
    if err != nil {
        panic(fmt.Sprintf("连接服务器失败,err:%v", err))
}
    defer socker.Close()
    sendStr:="你好呀"
    _, err = socker.Write([]byte(sendStr))
    if err != nil {
        panic(fmt.Sprintf("数据发送失败,err:%v", err))
}
}

执行结果

Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사

总结

本次章节我们讲述了什么是TCP,什么是UDP。

并且编写了代码如何实现TCP服务端TCP客户端UDP服务端UDP客户端

讲述了为什么会出现粘包,该怎么解决粘包

위 내용은 Go 언어 네트워크 프로그래밍의 기본을 이해하는 데 도움이 되는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 Go语言进阶学习에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
GO 프로그래밍 언어로 확장 가능한 시스템 구축GO 프로그래밍 언어로 확장 가능한 시스템 구축Apr 25, 2025 am 12:19 AM

goisidealforbuildingscalablesystemsduetoitssimplicity, 효율성 및 빌드-내부 컨 컨 오렌 스upport.1) go'scleansyntaxandminimalisticdesignenenhance-reductivityandreduceerrors.2) itsgoroutinesandChannelsableefficedsoncurrentProgramming, DistributingLoa

GO에서 시작 기능을 효과적으로 사용하기위한 모범 사례GO에서 시작 기능을 효과적으로 사용하기위한 모범 사례Apr 25, 2025 am 12:18 AM

initTectionsIntOnaUtomaticallyBeforemain () andAreSefulforsettingupenvirondentAnitializingVariables.usethemforsimpletasks, propoysideeffects 및 withtestingntestingandloggingtomaincodeclarityAndestability.

GO 패키지에서 시작 함수의 실행 순서GO 패키지에서 시작 함수의 실행 순서Apr 25, 2025 am 12:14 AM

goinitializespackages는 theyareimported, theexecutesinitfunctions, theneiredefinitionorder, andfilenamesDeterMineDeTerMineTeRacrossMultipleFiles.ThemayLeadTocomplexInitializations의 의존성 의존성의 의존성을 확인합니다

이동 중에 사용자 정의 인터페이스를 정의하고 사용합니다이동 중에 사용자 정의 인터페이스를 정의하고 사용합니다Apr 25, 2025 am 12:09 AM

CustomInterfacesingoAreCrucialForwritingFlectible, 관리 가능 및 TestAblEcode.theyenabledeveloperstofocusonBehaviorimplementation, 향상 ModularityAndRobustness

이동 중에 조롱 및 테스트를위한 인터페이스 사용이동 중에 조롱 및 테스트를위한 인터페이스 사용Apr 25, 2025 am 12:07 AM

시뮬레이션 및 테스트에 인터페이스를 사용하는 이유는 인터페이스가 구현을 지정하지 않고 계약의 정의를 허용하여 테스트를보다 고립되고 유지 관리하기 쉽기 때문입니다. 1) 인터페이스를 암시 적으로 구현하면 테스트에서 실제 구현을 대체 할 수있는 모의 개체를 간단하게 만들 수 있습니다. 2) 인터페이스를 사용하면 단위 테스트에서 서비스의 실제 구현을 쉽게 대체하여 테스트 복잡성과 시간을 줄일 수 있습니다. 3) 인터페이스가 제공하는 유연성은 다른 테스트 사례에 대한 시뮬레이션 동작의 변화를 허용합니다. 4) 인터페이스는 처음부터 테스트 가능한 코드를 설계하여 코드의 모듈성과 유지 관리를 향상시키는 데 도움이됩니다.

GO에서 패키지 초기화에 Init을 사용합니다GO에서 패키지 초기화에 Init을 사용합니다Apr 24, 2025 pm 06:25 PM

GO에서는 INT 기능이 패키지 초기화에 사용됩니다. 1) INT 기능은 패키지 초기화시 자동으로 호출되며 글로벌 변수 초기화, 연결 설정 및 구성 파일로드에 적합합니다. 2) 파일 순서로 실행할 수있는 여러 개의 초기 함수가있을 수 있습니다. 3)이를 사용할 때 실행 순서, 테스트 난이도 및 성능 영향을 고려해야합니다. 4) 부작용을 줄이고, 종속성 주입을 사용하고, 초기화를 지연하여 초기 기능의 사용을 최적화하는 것이 좋습니다.

GO의 선택 설명 : 다중화 동시 작업GO의 선택 설명 : 다중화 동시 작업Apr 24, 2025 pm 05:21 PM

go'selectStatementsTreamLinesconcurramprogrammingBymultiplexingOperations.1) ItallowSwaitingOnMultipLechannelOperations, executingThefirStreadYone.2) thedefaultCasePreventsDeadLocksHavingThepRamToproCeedifNooperationSready.3) Itcanusedfored

GO의 고급 동시성 기술 : 컨텍스트 및 대기 그룹GO의 고급 동시성 기술 : 컨텍스트 및 대기 그룹Apr 24, 2025 pm 05:09 PM

Contextandwaitgroupsarecrucialingformaninggoroutineeseforoutineeseferfectial

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음