Home Backend Development Golang How to implement a high-concurrency network programming framework in Go language

How to implement a high-concurrency network programming framework in Go language

Apr 06, 2023 am 09:11 AM

In realizing high-concurrency network programming, the Workerman framework of PHP language has always been known for its excellent performance and simplicity and ease of use. However, compared to the PHP language, Golang is more suitable for high concurrency and distributed system development, so implementing the Golang version of the workerman framework has become the pursuit of many developers. In this article, we will introduce how to use the Golang language to implement a high-concurrency network programming framework, similar to Workerman.

1. Prerequisite knowledge

Before we start, we need to master some basic knowledge:

1.Golang language basics: variables, functions, structures, interfaces, etc. concept.

2. Network programming basics: basic knowledge of TCP/UDP, HTTP and other protocols.

3.Goroutine: The coroutine of Golang language can greatly improve the efficiency of concurrent programming.

4.Channel: A communication mechanism provided by the Golang language, which can be used for data transmission and synchronization between different coroutines.

5.Select: A multiplexing mechanism provided by the Golang language, which can monitor the status of multiple Channels and improve program efficiency.

2. Framework architecture

According to the implementation of the Workerman framework, we can divide it into three parts:

1. Receive the connection and generate the client.

2. Business process used to process client requests.

3. Monitor the client connection status and recycle it.

In the Golang language, we can use goroutine to implement the above three parts respectively.

1. Receive the connection and generate the client

We can use the "net" package that comes with the Golang language to create a TCP server, and at the same time open a goroutine to monitor the client connection status.

import (
  "fmt"
  "net"
)

func main() {
  listener, err := net.Listen("tcp", "127.0.0.1:8080")
  if err != nil {
    fmt.Println("failed to listen:", err)
    return
  }

  go func() {
    for {
      conn, err := listener.Accept()
      if err != nil {
        fmt.Println("failed to accept:", err)
        continue
      }
      // 生成客户端
    }
  }()

  // 等待进程退出
  select {}
}
Copy after login

After receiving the client connection, we need to encapsulate a Client object to handle all requests and responses for the connection.

type Client struct {
  Conn   net.Conn
  RespCh chan []byte
}

func NewClient(conn net.Conn) *Client {
  return &Client {
    Conn:   conn,
    RespCh: make(chan []byte, 10),
  }
}
Copy after login

2. Business process used to process client requests

The client's requests and responses are delivered directly through the Channel. When a new connection is received, we need to encapsulate it into a Client object and open a goroutine to handle the connection. This goroutine will listen to all requests sent by the client through the Channel and respond accordingly.

We encapsulate the business process into a Handler interface.

type Handler interface {
  OnConnect(*Client) error
  OnMessage(*Client, []byte) error
  OnClose(*Client) error
}
Copy after login

The client's request and response are passed through the RespCh attribute of the Client object. Therefore, in the Handler interface, we need to define a RespCh property to receive the response from the client.

type Handler interface {
  OnConnect(*Client) error
  OnMessage(*Client, []byte) error
  OnClose(*Client) error
  RespCh() chan []byte
}
Copy after login

We can create an EchoHandler to implement the Handler interface.

type EchoHandler struct {
  clients   []*Client
  respChan  chan []byte
}

func NewEchoHandler() *EchoHandler {
  return &EchoHandler{
    clients:  make([]*Client, 0),
    respChan: make(chan []byte, 10),
  }
}

func (h *EchoHandler) OnConnect(c *Client) error {
  h.clients = append(h.clients, c)
  return nil
}

func (h *EchoHandler) OnMessage(c *Client, data []byte) error {
  // 将客户端发送的数据广播给所有其他客户端,并将其存入respChan中
  for _, client := range h.clients {
    if client == c {
      continue
    }
    client.RespCh <- data
  }
  return nil
}

func (h *EchoHandler) OnClose(c *Client) error {
  for index, client := range h.clients {
    if client == c {
      h.clients = append(h.clients[:index], h.clients[index+1:]...)
    }
  }
  return nil
}

func (h *EchoHandler) RespCh() chan []byte {
  return h.respChan
}
Copy after login

When the Client objects of each connected client are stored in the clients array, we can receive the data sent by each client through the RespCh attribute and broadcast the information sent by the client to other clients. Client functionality.

3. Monitor the client connection status and recycle it

For the old version of the Workerman framework, Workerman will recycle idle connections within a certain period of time. The new version of Workerman implements this function through TCP keepalive.

When implementing the Golang version of workererman, we can also solve the idle connection problem through TCP keepalive. We can monitor the status of its socket in the goroutine of each client. If a client does not send data after 10 seconds of idle time, it will be regarded as an illegal connection and its socket will be closed.

func (c *Client) Process() {
  defer func() {
    c.Conn.Close()
    c.handler.OnClose(c)
  }()
  // 设置 socket keepalive
  tcpConn, ok := c.Conn.(*net.TCPConn)
  if ok {
    tcpConn.SetKeepAlive(true)
    tcpConn.SetKeepAlivePeriod(10 * time.Second)
  }
  // 进入读协程,接收客户端发送的所有数据
  go func() {
    for {
      buf := make([]byte, 1024)
      n, err := c.Conn.Read(buf)
      if err != nil {
        if err != io.EOF {
          fmt.Println("failed to read:", err)
        }
        break
      }
      // 将客户端发送的消息交给Handler处理
      c.handler.OnMessage(c, buf[:n])
    }
  }()
  // 进入写协程,将respChan中的所有响应发送给当前客户端
  go func() {
    for resp := range c.handler.RespCh() {
      _, err := c.Conn.Write(resp)
      if err != nil {
        fmt.Println("failed to write:", err)
        break
      }
    }
  }()
  // OnConnect
  err := c.handler.OnConnect(c)
  if err != nil {
    fmt.Println("failed to on connect:", err)
    return
  }
  // 在Worker进程退出时进行清理
  select {}
}
Copy after login

3. Implement the Worker process

After completing the above three steps, we need to create a Worker process to manage all client connections. One or more Handlers need to be loaded in the Worker process to handle all data requests sent by clients.

type Worker struct {
  listener  net.Listener
  handlers  map[string]Handler
}

func NewWorker(addr string) (*Worker, error) {
  listener, err := net.Listen("tcp", addr)
  if err != nil {
    fmt.Println("failed to listen:", err)
    return nil, err
  }
  return &Worker{
    listener: listener,
    handlers: make(map[string]Handler),
  }, nil
}

func (w *Worker) Register(name string, handler Handler) {
  w.handlers[name] = handler
}

func (w *Worker) Start() {
  go func() {
    for {
      conn, err := w.listener.Accept()
      if err != nil {
        fmt.Println("failed to accept:", err)
        continue
      }
      // 封装连接客户端为Client对象,用于后续的处理
      client := NewClient(conn)
      client.handler = w.handlers["Echo"]
      // 开启客户端goroutine来处理该连接
      go client.Process()
    }
  }()
  // 等待进程退出
  select {}
}
Copy after login

In the Worker process, we need to define a handlers attribute to store instances of different Handlers, and monitor client connections in the Start() function and start new goroutines to handle client requests.

4. Test

We can use the following code to create a Worker process and register an EchoHandler in it to handle all client requests.

func main() {
  server, _ := NewWorker("127.0.0.1:8080")
  handler := NewEchoHandler()
  server.Register("Echo", handler)
  server.Start()
}
Copy after login

We can use the telnet tool to simulate multiple clients sending messages to the server and view their reception.

We use the following command to connect to the server:

telnet 127.0.0.1 8080
Copy after login

We can enter the following text in telnet:

Hello workerman!
Copy after login

We can open multiple telnet windows at the same time to simulate multiple Client requests in parallel.

On the server, we can see the output:

$ go run worker.go 
服务器已启动...
failed to read: read tcp 127.0.0.1:8080->127.0.0.1:56182: use of closed network connection
Copy after login

This is because when we close the client connection, we cancel its listening operation, resulting in a read error.

After the telnet input is completed, we can see that each telnet window will receive the text returned by the server.

5. Summary

In this article, we introduced how to use the Golang language to implement a highly concurrent network programming framework, similar to the workerman in the PHP language. During the implementation process, we used the coroutine, communication mechanism and multiplexing mechanism in the Golang language, and successfully implemented a high-concurrency network programming framework similar to Workerman by encapsulating the Client object and Handler interface.

In fact, in daily programming, we recommend directly using the net/http package provided by the Golang language to implement high-concurrency network programming, which is more concise and has better performance than the workerman framework. We only need to open an http server and use goroutine to process each request concurrently to easily implement high-concurrency network programming.

The above is the detailed content of How to implement a high-concurrency network programming framework in Go language. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What are the vulnerabilities of Debian OpenSSL What are the vulnerabilities of Debian OpenSSL Apr 02, 2025 am 07:30 AM

OpenSSL, as an open source library widely used in secure communications, provides encryption algorithms, keys and certificate management functions. However, there are some known security vulnerabilities in its historical version, some of which are extremely harmful. This article will focus on common vulnerabilities and response measures for OpenSSL in Debian systems. DebianOpenSSL known vulnerabilities: OpenSSL has experienced several serious vulnerabilities, such as: Heart Bleeding Vulnerability (CVE-2014-0160): This vulnerability affects OpenSSL 1.0.1 to 1.0.1f and 1.0.2 to 1.0.2 beta versions. An attacker can use this vulnerability to unauthorized read sensitive information on the server, including encryption keys, etc.

How do you use the pprof tool to analyze Go performance? How do you use the pprof tool to analyze Go performance? Mar 21, 2025 pm 06:37 PM

The article explains how to use the pprof tool for analyzing Go performance, including enabling profiling, collecting data, and identifying common bottlenecks like CPU and memory issues.Character count: 159

How do you write unit tests in Go? How do you write unit tests in Go? Mar 21, 2025 pm 06:34 PM

The article discusses writing unit tests in Go, covering best practices, mocking techniques, and tools for efficient test management.

What is the problem with Queue thread in Go's crawler Colly? What is the problem with Queue thread in Go's crawler Colly? Apr 02, 2025 pm 02:09 PM

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

What libraries are used for floating point number operations in Go? What libraries are used for floating point number operations in Go? Apr 02, 2025 pm 02:06 PM

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

PostgreSQL monitoring method under Debian PostgreSQL monitoring method under Debian Apr 02, 2025 am 07:27 AM

This article introduces a variety of methods and tools to monitor PostgreSQL databases under the Debian system, helping you to fully grasp database performance monitoring. 1. Use PostgreSQL to build-in monitoring view PostgreSQL itself provides multiple views for monitoring database activities: pg_stat_activity: displays database activities in real time, including connections, queries, transactions and other information. pg_stat_replication: Monitors replication status, especially suitable for stream replication clusters. pg_stat_database: Provides database statistics, such as database size, transaction commit/rollback times and other key indicators. 2. Use log analysis tool pgBadg

What is the go fmt command and why is it important? What is the go fmt command and why is it important? Mar 20, 2025 pm 04:21 PM

The article discusses the go fmt command in Go programming, which formats code to adhere to official style guidelines. It highlights the importance of go fmt for maintaining code consistency, readability, and reducing style debates. Best practices fo

Transforming from front-end to back-end development, is it more promising to learn Java or Golang? Transforming from front-end to back-end development, is it more promising to learn Java or Golang? Apr 02, 2025 am 09:12 AM

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

See all articles