2023,江端さんの技術メモ

UbuntuでFTPサーバを停止するには、サーバソフトウェアによって異なります。一般的に、Ubuntuでよく使われるFTPサーバソフトウェアはvsftpd(Very Secure FTP Daemon)です。以下に、vsftpdを停止する方法を説明します。もし他のFTPサーバーソフトウェアを使用している場合は、それに対応した手順を適用してください。

vsftpdを停止する手順:

  1. ターミナルを開きます。
  2. vsftpdサービスを停止します。次のコマンドを使用します:
    sudo systemctl stop vsftpd
  3. vsftpdサービスが停止したことを確認するために、次のコマンドを使用してサービスのステータスを確認します:
    sudo systemctl status vsftpd

    ステータスが「inactive」(非アクティブ)になっているはずです。

  4. vsftpdサービスが自動起動しないように設定したい場合、次のコマンドを使用して自動起動を無効にします:
    sudo systemctl disable vsftpd

これにより、システムの再起動時にvsftpdサービスが起動しないようになります。

以上の手順に従うことで、vsftpd FTPサーバーを停止し、必要に応じて自動起動を無効にできます。

2023,江端さんの技術メモ

/etc/vsftpd.conf

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_file=/var/log/vsftpd.log
ascii_upload_enable=YES
ascii_download_enable=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
utf8_filesystem=YES

2023,江端さんの技術メモ

pt@pt-desktop:~/www$ more docker-compose.yml
version: '3'

services:
  nginx:
    build: ./
    image: nginx
    ports:
      - 8888:80
    volumes:
      - ./src:/usr/share/nginx/html

    restart: always

の(ネストの位置に気をつけて)"restart: always"を付けた後、"$ docker compose build"をしておくこと。

以上

2023,江端さんの技術メモ

今回の実験のケースでは、

192.168.11.232/ 255.255.248.0 / 192.168.11.1 あたりにすれば良いのであろう(多分)。

 

2023,江端さんの忘備録

本当に一所懸命やっているんだけど、法律で定められている時間内では、仕事の量と質から考えても絶対に間に合わない ――

I am working hard, but I will never make it within the legal time frame, given the quantity and quality of the work I have to do.

これって、誰のせい?

Whose fault is this?

私(の無能)のせい?

Is it my (incompetence) fault?

-----

10年前、30年前、そして、有史以来、人類がずっと問い続けてきたことを、リタイアをスコープに入ってきている今でさえ、自分の問題として、自問していることに腹が立ちます。

I am angry that even now, as I am scoping my retirement, I am asking myself the same question humanity has been asking since ten years ago, 30 years ago, and since the beginning of time, as my problem.

もしかしたら、『人間って、本質的にバカなの?』と思ってしまいます。

Perhaps, 'Are humans inherently stupid?' I think.

太陽にブラックホールが突っ込んでくる日が、明日やって来たとしても、今の私は歓迎します(by さよならジュピター(故小松左京先生))。

Even if the day when a black hole crashes into the sun comes tomorrow, I would welcome it now (by Byebye Jupiter (the late Sakyo Komatsu)).

さよならジュピター

2023,江端さんの技術メモ

Go言語で、redisを使って2つの型の異なるデータをブロードキャストしている場合、その受信している部分を1つのswitchで受けとるにはどうしたら良いですか

を、異なるエージェントで、異なるメッセージを受信できるか試してみた件。

 

// C:\Users\ebata\tomioka3B\src\others\main28.go
// 2つのクロック(goroutine)を用意して、異なるエージェントで受けとれるかどうかの実験

package main

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/gomodule/redigo/redis"
)


type Clock_Info struct {
	VirtualTime time.Time
	RealTime    time.Time
}

type SubClockInfo_2 struct {
    // 異なるデータ型のフィールドをここに追加
    SomeField string
    AnotherField int
}

func BaseClock() {

	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// スタート時刻を指定
	startTime := time.Date(2023, 10, 1, 7, 0, 0, 0, time.UTC)

	// 1秒値を保持する変数
	seconds := 0

	var ci Clock_Info

	// ループを開始
	for {
		// 現在の時刻を計算
		ci.VirtualTime = startTime.Add(time.Duration(seconds) * time.Second)
		ci.RealTime = time.Now()

		// 現在の時刻を表示
		// fmt.Println("シミュレータの時刻:", ci.VirtualTime.Format("2006/01/02 15:04:05"))
		// fmt.Println("現在の時刻:", ci.RealTime.Format("2006/01/02 15:04:05")) // "2006/01/02 15:04:05"はフォーマットの形を真似るもので、内容に意味なし

		// パブリッシュ
		json_ci, _ := json.Marshal(ci)
		r, err := redis.Int(conn.Do("PUBLISH", "ClockInfo_1", json_ci))
		if err != nil {
			panic(err)
		}
		fmt.Println(r)

		// 5秒待つ (実際は、0.05秒くらいだが、確認用に長くしている)
		time.Sleep(5000 * time.Millisecond)

		// 1秒値を増加させる
		seconds++
	}
}


func SubClock() {  // 実験用に追加(時間ではなく、単なる文字列と数値を送り込むだけ)

	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()


	// 1秒値を保持する変数
	seconds := 0

	var sci2 SubClockInfo_2

	// ループを開始
	for {
		// 現在の時刻を計算
		sci2.SomeField = "ebata is great"
    	sci2.AnotherField = seconds

		// パブリッシュ
		json_sci2, _ := json.Marshal(sci2)
		r, err := redis.Int(conn.Do("PUBLISH", "SubClockInfo_2", json_sci2))
		if err != nil {
			panic(err)
		}
		fmt.Println(r)

		// 7秒待つ (実際は、0.05秒くらいだが、確認用に長くしている)
		time.Sleep(7000 * time.Millisecond)

		// 1秒値を増加させる
		seconds += 1 
	}
}



func person_1(person_num int, wg *sync.WaitGroup) {
	defer wg.Done()
	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)

	}
	defer conn.Close()

	psc := redis.PubSubConn{Conn: conn}
	psc.Subscribe("ClockInfo_1") // 2つに増やした

	for {	
		switch v := psc.Receive().(type) { // redisのメッセージを受けとると、ここでロックが外れる

		case redis.Message:

			switch v.Channel{

			case "ClockInfo_1":  // ブロードキャスト"ClockInfo_1"のメッセージは、こっちでキャッチ
				ci := new(Clock_Info) 
        		_ = json.Unmarshal(v.Data, &ci)
        		fmt.Println("Person_1:", person_num, "VirtualTime (ClockInfo_1):", ci.VirtualTime)

			case "SubClockInfo_2": // ブロードキャスト"SubClockInfo_2"のメッセージは、こっちでキャッチ
        		subClockData := new(SubClockInfo_2)
        		_ = json.Unmarshal(v.Data, &subClockData)
        		fmt.Println("Person_1:", person_num, "SomeField (SubClockInfo_2):", subClockData.SomeField)
         		fmt.Println("Person_1:", person_num, "AnotherField (SubClockInfo_2):", subClockData.AnotherField)


    	}
		
		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)

		case error:
			return
		}
	}

}

func person_2(person_num int, wg *sync.WaitGroup) {
	defer wg.Done()
	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)

	}
	defer conn.Close()

	psc := redis.PubSubConn{Conn: conn}
	psc.Subscribe("SubClockInfo_2") // 2つに増やした

	for {	
		switch v := psc.Receive().(type) { // redisのメッセージを受けとると、ここでロックが外れる

		case redis.Message:

			switch v.Channel{


			case "ClockInfo_1":  // ブロードキャスト"ClockInfo_1"のメッセージは、こっちでキャッチ
				ci := new(Clock_Info) 
        		_ = json.Unmarshal(v.Data, &ci)
        		fmt.Println("Person_2:", person_num, "VirtualTime (ClockInfo_1):", ci.VirtualTime)

			case "SubClockInfo_2": // ブロードキャスト"SubClockInfo_2"のメッセージは、こっちでキャッチ
        		subClockData := new(SubClockInfo_2)
        		_ = json.Unmarshal(v.Data, &subClockData)
        		fmt.Println("Person_2:", person_num, "SomeField (SubClockInfo_2):", subClockData.SomeField)
         		fmt.Println("Person_2:", person_num, "AnotherField (SubClockInfo_2):", subClockData.AnotherField)
    	}
		
		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)

		case error:
			return
		}
	}

}


func main() {

	wg := sync.WaitGroup{}

	//wg.Add(1)
	//go BaseClock(&wg)
	go BaseClock()
	go SubClock()

	for i := 0; i < 5; i++ { // 5人
		wg.Add(1)
		go person_1(i, &wg)
	}

	for i := 0; i < 5; i++ { // 5人
		wg.Add(1)
		go person_2(i, &wg)
	}


	wg.Wait()
	fmt.Println("end of ... main()")
}

ちゃんと動くみたいです。

2023,江端さんの技術メモ

"SubClockInfo_2" チャンネルから受信したデータを処理するために、新しい構造体を定義します。異なるデータ型に合わせて構造体を定義し、Unmarshal でデータを解析します。

"SubClockInfo_2" チャンネルからのメッセージを受け取るために、person 関数内の switch ステートメントを更新します。具体的には、"SubClockInfo_2" チャンネルのデータ型に合わせて処理を分岐させます。

このようにすることで、"SubClockInfo_2" チャンネルから異なる型のデータを受信し、それに応じた処理を行うことができます。異なるデータ型ごとに適切な構造体を用意し、Unmarshal でデータを解析しましょう。

// C:\Users\ebata\tomioka3B\src\others\main27.go
// 2つのクロック(goroutine)を用意して、一つのswitchで受けとれるかどうかの実験

package main

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/gomodule/redigo/redis"
)


type Clock_Info struct {
	VirtualTime time.Time
	RealTime    time.Time
}

type SubClockInfo_2 struct {
    // 異なるデータ型のフィールドをここに追加
    SomeField string
    AnotherField int
}

func BaseClock() {

	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// スタート時刻を指定
	startTime := time.Date(2023, 10, 1, 7, 0, 0, 0, time.UTC)

	// 1秒値を保持する変数
	seconds := 0

	var ci Clock_Info

	// ループを開始
	for {
		// 現在の時刻を計算
		ci.VirtualTime = startTime.Add(time.Duration(seconds) * time.Second)
		ci.RealTime = time.Now()

		// 現在の時刻を表示
		// fmt.Println("シミュレータの時刻:", ci.VirtualTime.Format("2006/01/02 15:04:05"))
		// fmt.Println("現在の時刻:", ci.RealTime.Format("2006/01/02 15:04:05")) // "2006/01/02 15:04:05"はフォーマットの形を真似るもので、内容に意味なし

		// パブリッシュ
		json_ci, _ := json.Marshal(ci)
		r, err := redis.Int(conn.Do("PUBLISH", "ClockInfo_1", json_ci))
		if err != nil {
			panic(err)
		}
		fmt.Println(r)

		// 5秒待つ (実際は、0.05秒くらいだが、確認用に長くしている)
		time.Sleep(5000 * time.Millisecond)

		// 1秒値を増加させる
		seconds++
	}
}


func SubClock() {  // 実験用に追加(時間ではなく、単なる文字列と数値を送り込むだけ)

	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()


	// 1秒値を保持する変数
	seconds := 0

	var sci2 SubClockInfo_2

	// ループを開始
	for {
		// 現在の時刻を計算
		sci2.SomeField = "ebata is great"
    	sci2.AnotherField = seconds

		// パブリッシュ
		json_sci2, _ := json.Marshal(sci2)
		r, err := redis.Int(conn.Do("PUBLISH", "SubClockInfo_2", json_sci2))
		if err != nil {
			panic(err)
		}
		fmt.Println(r)

		// 7秒待つ (実際は、0.05秒くらいだが、確認用に長くしている)
		time.Sleep(7000 * time.Millisecond)

		// 1秒値を増加させる
		seconds += 1 
	}
}




func person(person_num int, wg *sync.WaitGroup) {
	defer wg.Done()
	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	psc := redis.PubSubConn{Conn: conn}
	psc.Subscribe("ClockInfo_1", "SubClockInfo_2") // 2つに増やした

	for {	
		switch v := psc.Receive().(type) { // redisのメッセージを受けとると、ここでロックが外れる

		case redis.Message:

			switch v.Channel{

			case "ClockInfo_1":  // ブロードキャスト"ClockInfo_1"のメッセージは、こっちでキャッチ
				ci := new(Clock_Info) 
        		_ = json.Unmarshal(v.Data, &ci)
        		fmt.Println("Person:", person_num, "VirtualTime (ClockInfo_1):", ci.VirtualTime)

			case "SubClockInfo_2": // ブロードキャスト"SubClockInfo_2"のメッセージは、こっちでキャッチ
        		subClockData := new(SubClockInfo_2)
        		_ = json.Unmarshal(v.Data, &subClockData)
        		fmt.Println("Person:", person_num, "SomeField (SubClockInfo_2):", subClockData.SomeField)
         		fmt.Println("Person:", person_num, "AnotherField (SubClockInfo_2):", subClockData.AnotherField)
    	}
		
		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)

		case error:
			return
		}
	}

	/*
	for {
		ci := new(Clock_Info)
		switch v := psc.Receive().(type) {
		case redis.Message:
			_ = json.Unmarshal(v.Data, &ci)
			fmt.Println("Person:", person_num, "VirtualTime:", ci.VirtualTime)
			//fmt.Println("Person:", person_num, "RealTime:", ci.RealTime)

		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)

		case error:
			return
		}
	}
	*/

}

func main() {

	wg := sync.WaitGroup{}

	//wg.Add(1)
	//go BaseClock(&wg)
	go BaseClock()
	go SubClock()

	for i := 0; i < 5; i++ { // 5人
		wg.Add(1)
		go person(i, &wg)
	}

	wg.Wait()
	fmt.Println("end of ... main()")
}

出力結果はこんな感じになり、期待した通りの動きをしているようです。

Person: 1 VirtualTime (ClockInfo_1): 2023-10-01 07:00:03 +0000 UTC
Person: 3 VirtualTime (ClockInfo_1): 2023-10-01 07:00:03 +0000 UTC
Person: 0 VirtualTime (ClockInfo_1): 2023-10-01 07:00:03 +0000 UTC
Person: 4 VirtualTime (ClockInfo_1): 2023-10-01 07:00:03 +0000 UTC
Person: 2 VirtualTime (ClockInfo_1): 2023-10-01 07:00:03 +0000 UTC
5
Person: 1 VirtualTime (ClockInfo_1): 2023-10-01 07:00:04 +0000 UTC
Person: 0 VirtualTime (ClockInfo_1): 2023-10-01 07:00:04 +0000 UTC
Person: 3 VirtualTime (ClockInfo_1): 2023-10-01 07:00:04 +0000 UTC
Person: 2 VirtualTime (ClockInfo_1): 2023-10-01 07:00:04 +0000 UTC
Person: 4 VirtualTime (ClockInfo_1): 2023-10-01 07:00:04 +0000 UTC
5
Person: 3 SomeField (SubClockInfo_2): ebata is great
Person: 3 AnotherField (SubClockInfo_2): 3
Person: 0 SomeField (SubClockInfo_2): ebata is great
Person: 0 AnotherField (SubClockInfo_2): 3
Person: 1 SomeField (SubClockInfo_2): ebata is great
Person: 1 AnotherField (SubClockInfo_2): 3
Person: 4 SomeField (SubClockInfo_2): ebata is great
Person: 4 AnotherField (SubClockInfo_2): 3
Person: 2 SomeField (SubClockInfo_2): ebata is great
Person: 2 AnotherField (SubClockInfo_2): 3
5
Person: 3 VirtualTime (ClockInfo_1): 2023-10-01 07:00:05 +0000 UTC
Person: 4 VirtualTime (ClockInfo_1): 2023-10-01 07:00:05 +0000 UTC
Person: 1 VirtualTime (ClockInfo_1): 2023-10-01 07:00:05 +0000 UTC
Person: 0 VirtualTime (ClockInfo_1): 2023-10-01 07:00:05 +0000 UTC
Person: 2 VirtualTime (ClockInfo_1): 2023-10-01 07:00:05 +0000 UTC
5
Person: 3 SomeField (SubClockInfo_2): ebata is great
Person: 3 AnotherField (SubClockInfo_2): 4
Person: 0 SomeField (SubClockInfo_2): ebata is great
Person: 4 SomeField (SubClockInfo_2): ebata is great
Person: 4 AnotherField (SubClockInfo_2): 4
Person: 1 SomeField (SubClockInfo_2): ebata is great
Person: 1 AnotherField (SubClockInfo_2): 4
Person: 0 AnotherField (SubClockInfo_2): 4
Person: 2 SomeField (SubClockInfo_2): ebata is great
Person: 2 AnotherField (SubClockInfo_2): 4
5

以上

2023,江端さんの技術メモ

[サーバ側] Windows10
https://iperf.fr/iperf-download.php#windows からダウンロード
インストールとかではなくて、バイナリが直接解凍される

[クライアント側] Ubuntu22.04
$ sudo apt install iperf3

使い方
[サーバ側] iperf3.exe -s
[クライアント側]iperf3.exe -c 192.168.11.167(サーバのIPアドレス等)


構成1

サーバ側の表示はこんな感じでした。

C:\Users\maoeb\iperf-3.1.3-win64>iperf3.exe -s
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
Accepted connection from 192.168.11.125, port 33940
[  5] local 192.168.11.167 port 5201 connected to 192.168.11.125 port 33946
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-1.00   sec  8.85 MBytes  74.2 Mbits/sec
[  5]   1.00-2.00   sec  5.86 MBytes  49.0 Mbits/sec
[  5]   2.00-3.00   sec  4.79 MBytes  40.2 Mbits/sec
[  5]   3.00-4.01   sec  5.13 MBytes  42.9 Mbits/sec
[  5]   4.01-5.00   sec  5.10 MBytes  42.8 Mbits/sec
[  5]   5.00-6.00   sec  8.65 MBytes  72.8 Mbits/sec
[  5]   6.00-7.01   sec  5.84 MBytes  48.7 Mbits/sec
[  5]   7.01-8.00   sec  5.06 MBytes  42.6 Mbits/sec
[  5]   8.00-9.01   sec  5.25 MBytes  43.9 Mbits/sec
[  5]   9.01-10.00  sec  8.37 MBytes  70.6 Mbits/sec
[  5]  10.00-10.02  sec   194 KBytes  84.6 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-10.02  sec  0.00 Bytes  0.00 bits/sec                  sender
[  5]   0.00-10.02  sec  63.1 MBytes  52.8 Mbits/sec                  receiver

構成2

C:\Users\maoeb\iperf-3.1.3-win64>iperf3.exe -s
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
Accepted connection from 192.168.1.15, port 39780
[  5] local 192.168.1.8 port 5201 connected to 192.168.1.15 port 39784
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-1.00   sec  11.2 MBytes  94.2 Mbits/sec
[  5]   1.00-2.00   sec  10.9 MBytes  91.2 Mbits/sec
[  5]   2.00-3.00   sec  11.3 MBytes  94.9 Mbits/sec
[  5]   3.00-4.00   sec  11.3 MBytes  94.9 Mbits/sec
[  5]   4.00-5.00   sec  11.3 MBytes  94.9 Mbits/sec
[  5]   5.00-6.00   sec  11.3 MBytes  94.9 Mbits/sec
[  5]   6.00-7.00   sec  11.3 MBytes  94.9 Mbits/sec
[  5]   7.00-8.00   sec  11.3 MBytes  94.8 Mbits/sec
[  5]   8.00-9.00   sec  11.3 MBytes  94.9 Mbits/sec
[  5]   9.00-10.00  sec  11.3 MBytes  94.9 Mbits/sec
[  5]  10.00-10.01  sec  85.5 KBytes  89.1 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-10.01  sec  0.00 Bytes  0.00 bits/sec                  sender
[  5]   0.00-10.01  sec   113 MBytes  94.5 Mbits/sec                  receiver

構成3

劣化通信環境を使う上での工夫

-----------------------------------------------------------
Accepted connection from 192.168.11.125, port 39260
[  5] local 192.168.11.167 port 5201 connected to 192.168.11.125 port 39270
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-1.01   sec  4.23 MBytes  35.0 Mbits/sec
[  5]   1.01-2.01   sec  3.69 MBytes  31.2 Mbits/sec
[  5]   2.01-3.00   sec  4.46 MBytes  37.4 Mbits/sec
[  5]   3.00-4.00   sec  4.41 MBytes  37.1 Mbits/sec
[  5]   4.00-5.00   sec  3.74 MBytes  31.4 Mbits/sec
[  5]   5.00-6.00   sec  4.13 MBytes  34.5 Mbits/sec
[  5]   6.00-7.00   sec  4.39 MBytes  36.9 Mbits/sec
[  5]   7.00-8.01   sec  4.14 MBytes  34.5 Mbits/sec
[  5]   8.01-9.00   sec  4.23 MBytes  35.7 Mbits/sec
[  5]   9.00-10.00  sec  5.12 MBytes  42.9 Mbits/sec
[  5]  10.00-10.02  sec   153 KBytes  74.3 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-10.02  sec  0.00 Bytes  0.00 bits/sec                  sender
[  5]   0.00-10.02  sec  42.7 MBytes  35.7 Mbits/sec                  receiver


安定した、劣化環境を作るのは、これで、なかなか難しい。

2023,江端さんの技術メモ

今迄、エージェントプログラムでは、エージェントの中に内部時計(正確にはSleep())を組み込んで、エージェント間の時刻同期については、無視してきたのですが、交通シミュレーションに時刻表を入れる必要になって、無視できなくなってきました。

今や、私の十八番となったredisを使ったgolangのgoroutineで作った複数エージェントへのメッセージのブロードキャストを使って、時刻同期をするサンプルプログラムを作ってみました。

BaseClock()から、所定時間間隔で、シミュレーション共通の時刻をブロードキャストして、person()のエージェントで、その時刻情報を割り込み受信させることにしました。

ブロードキャストによる遅延や割り込み取りこぼしが心配ではありますが、これまでの経験上redisのブロードキャストは十分に高速なようなので、多分大丈夫だと思います。

// C:\Users\ebata\tomioka3B\src\others\main26.go

package main

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/gomodule/redigo/redis"
)

var Clock1 chan interface{}

type Clock_Info struct {
	VirtualTime time.Time
	RealTime    time.Time
}

func BaseClock(wg *sync.WaitGroup) {
	defer wg.Done()

	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// スタート時刻を指定
	startTime := time.Date(2023, 10, 1, 7, 0, 0, 0, time.UTC)

	// 1秒値を保持する変数
	seconds := 0

	var ci Clock_Info

	// ループを開始
	for {
		// 現在の時刻を計算
		ci.VirtualTime = startTime.Add(time.Duration(seconds) * time.Second)
		ci.RealTime = time.Now()

		// 現在の時刻を表示
		fmt.Println("シミュレータの時刻:", ci.VirtualTime.Format("2006/01/02 15:04:05"))
		fmt.Println("現在の時刻:", ci.RealTime.Format("2006/01/02 15:04:05")) // "2006/01/02 15:04:05"はフォーマットの形を真似るもので、内容に意味なし

		// パブリッシュ
		json_ci, _ := json.Marshal(ci)
		r, err := redis.Int(conn.Do("PUBLISH", "ClockInfo_1", json_ci))
		if err != nil {
			panic(err)
		}
		fmt.Println(r)

		// 5秒待つ (実際は、0.05秒くらいだが、確認用に長くしている)
		time.Sleep(5000 * time.Millisecond)

		// 1秒値を増加させる
		seconds++
	}
}

func person(person_num int, wg *sync.WaitGroup) {
	defer wg.Done()
	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	psc := redis.PubSubConn{Conn: conn}
	psc.Subscribe("ClockInfo_1")

	for {
		ci := new(Clock_Info)
		switch v := psc.Receive().(type) {
		case redis.Message:
			_ = json.Unmarshal(v.Data, &ci)
			fmt.Println("Person:", person_num, "VirtualTime:", ci.VirtualTime)
			fmt.Println("Person:", person_num, "RealTime:", ci.RealTime)

		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)

		case error:
			return
		}
	}
}

func main() {

	wg := sync.WaitGroup{}

	wg.Add(1)
	go BaseClock(&wg)

	for i := 0; i < 10; i++ { // 10人
		wg.Add(1)
		go person(i, &wg)
	}

	wg.Wait()
	fmt.Println("end of ... main()")
}