回答編集履歴

1

実装例追記

2022/01/13 11:32

投稿

nobonobo
nobonobo

スコア3367

test CHANGED
@@ -1,3 +1,75 @@
1
1
  普通にgoroutineで受信スレッドを作っておいて、
2
2
  そこで受けた内容を振り分け、返信だけをチャネルに載せます。通知は通知向けの処理を行います。
3
3
  「返信の受け取りの必要な送信」側の処理では送信したあと上記のチャネルから受け取りを行うという流れはどうでしょうか。(実際には受け取れなかった時のタイムアウト処理なども必要になります)
4
+
5
+ [クライアント実装例](https://go.dev/play/p/8TLfKQswItX)
6
+ ```go
7
+ package main
8
+
9
+ import (
10
+ "log"
11
+ "net"
12
+ "strings"
13
+ "time"
14
+ )
15
+
16
+ type Client struct {
17
+ conn net.Conn
18
+ repCh chan []byte
19
+ }
20
+
21
+ func NewClient(conn net.Conn) *Client {
22
+ c := &Client{
23
+ conn: conn,
24
+ repCh: make(chan []byte),
25
+ }
26
+ go func() {
27
+ buff := make([]byte, 4096)
28
+ for {
29
+ n, err := c.conn.Read(buff)
30
+ if err != nil {
31
+ log.Print(err)
32
+ return
33
+ }
34
+ rec := string(buff[:n])
35
+ switch {
36
+ case strings.HasPrefix(rec, "evt:"):
37
+ log.Print(rec)
38
+ case strings.HasPrefix(rec, "rep:"):
39
+ c.repCh <- buff[:n]
40
+ default:
41
+ log.Print("invalid packet: %q", rec)
42
+ }
43
+ }
44
+ }()
45
+ return c
46
+ }
47
+
48
+ func (c *Client) Send(msg string) (string, error) {
49
+ _, err := c.conn.Write([]byte(msg))
50
+ if err != nil {
51
+ return "", err
52
+ }
53
+ return string(<-c.repCh), nil
54
+ }
55
+
56
+ func main() {
57
+ c, err := net.Dial("tcp", ":8080")
58
+ if err != nil {
59
+ log.Fatal(err)
60
+ }
61
+ defer c.Close()
62
+ client := NewClient(c)
63
+ for {
64
+ msg := time.Now().Format("req:" + time.RFC3339Nano + "\n")
65
+ log.Print(msg)
66
+ rep, err := client.Send(msg)
67
+ if err != nil {
68
+ log.Print(err)
69
+ return
70
+ }
71
+ log.Print(rep)
72
+ time.Sleep(5 * time.Second)
73
+ }
74
+ }
75
+ ```