Go ่ฏญ่จๅฎ็ฐ็ Ethernet/IP ๅ่ฎฎๅบ๏ผๆฏๆไธ Allen-Bradley PLC ็ญ่ฎพๅค่ฟ่ก้ไฟกใ
- ๅ่ฝ็นๆง
- ๅฟซ้ๅผๅง
- ๆฏๆ็ๆฐๆฎ็ฑปๅ
- ๆถๆ่ฎพ่ฎก
- ่ฐ็จๆต็จ
- ่ฎฟ้ฎๆจกๅผ
- ้ ็ฝฎ้้กน
- ่ฏๆญ็ๆง
- UDP ่ฎพๅคๅ็ฐ
- ไบๅกๆงๆฏๆ
- cpppo ๅ ผๅฎนๆง
- API ๅ่
- ็คบไพไปฃ็
- ๆต่ฏ
- ๆง่ฝไผๅ
- ็ๆฌๆดๆฐ
- โ TCP ่ฟๆฅ็ฎก็๏ผไผ่ฏๆณจๅ/ๆณจ้๏ผ
- โ UDP ่ฟๆฅๆฏๆ
- โ UDP ่ฎพๅคๅ็ฐ๏ผBroadcast Discovery๏ผ
- โ Tag ่ฏปๅๆไฝ
- โ ๆน้ Tag ๆไฝ๏ผTagGroup๏ผ
- โ ่ฟๆฅๆฑ ๆฏๆ๏ผEIPTCPPool๏ผ
- โ UDT๏ผ็จๆทๅฎไน็ฑปๅ๏ผๆฏๆ
- โ ็ฌฆๅทๅฏปๅ๏ผSymbolic Addressing๏ผ
- โ ่ฟๆฅๅๅๅผๆพ๏ผForward Open๏ผ/ๅ ณ้ญ๏ผForward Close๏ผ
- โ ๆถๆฏ่ทฏ็ฑๅจ๏ผMessage Router๏ผ
- โ ็ผๅฒๅบๆฑ ๅไผๅ
- โ ็บฟ็จๅฎๅ จ่ฎพ่ฎก
- โ ๅ ผๅฎน๏ผLogix Class 2 ๅฏน่ฑกๆ ็ญพ่ฎฟ้ฎ๏ผ
- โ ่ฟๆฅ็ถๆๆฃๆฅ๏ผIsConnected๏ผ
- โ ่ชๅจ้่ฟๆบๅถ๏ผๆๆฐ้้ฟ๏ผๆๅค 3 ๆฌก้่ฏ๏ผ
- โ ๆน้ๆฐๆฎๅ ๆไฝ๏ผBatchRead/BatchWrite๏ผ
- โ ่ถ ๆถ้ ็ฝฎ๏ผ่ฟๆฅ่ถ ๆถใ่ฏปๅ่ถ ๆถใๆไฝ่ถ ๆถ๏ผ
- โ ไบๅกๆงๆฏๆ๏ผTagGroup ๅๅญๅๅ ฅ๏ผ
- โ ่ฏๆญ็ๆง๏ผ่ฟๆฅ็ถๆใ็ป่ฎกๆๆ ใไบไปถ็ๅฌ๏ผ
- โ STRING ๅๅ ฅไผๅ๏ผๅๆฌก่ฏทๆฑๅฎๆ๏ผ
go get github.com/anviod/ethernet-ip@latest# ไฝฟ็จ็นๅฎ็ๆฌ๏ผๆจ่็จไบ็ไบง็ฏๅข๏ผ
go get github.com/anviod/ethernet-ip@v0.0.4
# ไฝฟ็จ็นๅฎๆไบค
go get github.com/anviod/ethernet-ip@abc1234
# ไฝฟ็จๅๆฏ
go get github.com/anviod/ethernet-ip@mainimport (
"log"
"github.com/anviod/ethernet-ip"
)// ๅๅปบ TCP ่ฟๆฅๅฏน่ฑก
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal("ๅๅปบ่ฟๆฅๅคฑ่ดฅ:", err)
}
defer conn.Close()
// ๅปบ็ซ่ฟๆฅ
if err := conn.Connect(); err != nil {
log.Fatal("่ฟๆฅๅคฑ่ดฅ:", err)
}// ่ทๅๆๆ Tag
tags, err := conn.AllTags()
if err != nil {
log.Fatal("่ทๅ Tag ๅ่กจๅคฑ่ดฅ:", err)
}
// ่ฏปๅๅไธช Tag
tag := tags["Counter"]
if err := tag.Read(); err != nil {
log.Fatal("่ฏปๅ Tag ๅคฑ่ดฅ:", err)
}
// ่ทๅๅผ
log.Printf("Tag ๅผ: %d\n", tag.Int32())// ่ฎพ็ฝฎๆฐๅผๅนถๅๅ
ฅ
tag.SetInt32(12345)
if err := tag.Write(); err != nil {
log.Fatal("ๅๅ
ฅ Tag ๅคฑ่ดฅ:", err)
}
log.Println("ๅๅ
ฅๆๅ")// ๅๅปบ Tag ็ป
lock := new(sync.Mutex)
group := ethernet_ip.NewTagGroup(lock)
// ๆทปๅ ๅคไธช Tag
group.Add(tags["tag1"])
group.Add(tags["tag2"])
// ๆน้่ฏปๅ
if err := group.Read(); err != nil {
log.Fatal("ๆน้่ฏปๅๅคฑ่ดฅ:", err)
}
// ๆน้ๅๅ
ฅ
tags["tag1"].SetInt32(100)
tags["tag2"].SetString("updated")
if err := group.Write(); err != nil {
log.Fatal("ๆน้ๅๅ
ฅๅคฑ่ดฅ:", err)
}| ็ฑปๅ | ่ฏดๆ | ็ฌฆๅท |
|---|---|---|
BOOL |
ๅธๅฐๅ | 0xc1 |
SINT / INT8 |
8ไฝๆ็ฌฆๅทๆดๆฐ | 0xc2 |
INT / INT16 |
16ไฝๆ็ฌฆๅทๆดๆฐ | 0xc3 |
DINT / INT32 |
32ไฝๆ็ฌฆๅทๆดๆฐ | 0xc4 |
LINT / INT64 |
64ไฝๆ็ฌฆๅทๆดๆฐ | 0xc5 |
USINT / UINT8 |
8ไฝๆ ็ฌฆๅทๆดๆฐ | 0xc6 |
UINT / UINT16 |
16ไฝๆ ็ฌฆๅทๆดๆฐ | 0xc7 |
UDINT / UINT32 |
32ไฝๆ ็ฌฆๅทๆดๆฐ | 0xc8 |
ULINT / UINT64 |
64ไฝๆ ็ฌฆๅทๆดๆฐ | 0xc9 |
REAL / FLOAT |
32ไฝๆตฎ็นๆฐ | 0xca |
LREAL / DOUBLE |
64ไฝๆตฎ็นๆฐ | 0xcb |
STRING |
ๅญ็ฌฆไธฒ | 0xfce |
ethernet-ip/
โโโ bufferx/ # ๅญ่็ผๅฒๅบๆไฝ
โ โโโ bufferx.go # ๆฏๆๅฐ็ซฏ/ๅคง็ซฏ่ฏปๅใ็ผๅฒๅบๆฑ ๅ
โ โโโ bufferx_test.go # ๅๅ
ๆต่ฏ
โ โโโ bufferx_benchmark_test.go # ๆง่ฝๆต่ฏ
โโโ command/ # EIP ๅฝไปคๅฎไน
โ โโโ command.go # ๅฝไปคๅธธ้๏ผๆณจๅไผ่ฏใๅ้ๆฐๆฎ็ญ๏ผ
โ โโโ command_test.go # ๅๅ
ๆต่ฏ
โโโ messages/ # ๆถๆฏๅค็
โ โโโ packet/ # ๆฐๆฎๅ
็ผ่งฃ็
โ โ โโโ packet.go # ๆฐๆฎๅ
็ปๆ
โ โ โโโ commonPacketFormat.go # CPF ๆ ผๅผ
โ โ โโโ messageRouter.go # ๆถๆฏ่ทฏ็ฑๅจ
โ โ โโโ services.go # ๆๅกๅฎไน
โ โ โโโ cmm.go # CIP ๆถๆฏ็ฎก็
โ โ โโโ ucmm.go # ้่ฟๆฅๆถๆฏ็ฎก็
โ โ โโโ data.go # ๆฐๆฎ้กนๅค็
โ โ โโโ utils.go # ๅทฅๅ
ทๅฝๆฐ
โ โ โโโ packet_test.go # ๅๅ
ๆต่ฏ
โ โโโ registerSession/ # ไผ่ฏๆณจๅ
โ โโโ unRegisterSession/ # ไผ่ฏๆณจ้
โ โโโ listIdentity/ # ่ฎพๅค่ฏๅซไฟกๆฏ
โ โโโ listInterface/ # ๆฅๅฃๅ่กจ
โ โโโ listServices/ # ๆๅกๅ่กจ
โ โโโ sendRRData/ # ๅ้่ทฏ็ฑๆฐๆฎ
โ โโโ sendUnitData/ # ๅ้ๅๅ
ๆฐๆฎ
โ โโโ nop/ # NOP ๅฝไปค๏ผ็ฉบๆไฝ๏ผ
โโโ path/ # CIP ่ทฏๅพๆๅปบ
โ โโโ path.go # ้ป่พ่ทฏๅพใ็ซฏๅฃ่ทฏๅพใๆฐๆฎ่ทฏๅพ
โ โโโ path_test.go # ๅๅ
ๆต่ฏ
โโโ types/ # ็ฑปๅๅฎไน
โ โโโ types.go # ๆๆๆฐๆฎ็ฑปๅๅฎไน
โโโ utils/ # ๅทฅๅ
ทๅฝๆฐ
โ โโโ len.go # ้ฟๅบฆ่ฎก็ฎ
โ โโโ mmap.go # ๅ
ๅญๆ ๅฐ
โ โโโ mmap_unix.go # Unix ๅนณๅฐๅ
ๅญๆ ๅฐ
โ โโโ mmap_windows.go # Windows ๅนณๅฐๅ
ๅญๆ ๅฐ
โ โโโ simd.go # SIMD ไผๅ
โโโ test/ # ้ๆๆต่ฏ
โ โโโ cpppo/ # cpppo ๅ
ผๅฎนๆงๆต่ฏ
โ โโโ protocol_verifier_test.go # ๅ่ฎฎ้ช่ฏๆต่ฏ
โ โโโ access_mode_test.go # ่ฎฟ้ฎๆจกๅผๆต่ฏ
โ โโโ concurrency_test.go # ๅนถๅๆต่ฏ
โ โโโ benchmark_test.go # ๆง่ฝๅบๅๆต่ฏ
โโโ doc/ # ๆๆกฃ
โ โโโ PERFORMANCE_OPTIMIZATION*.md # ๆง่ฝไผๅๆๆกฃ
โ โโโ performance_report.json # ๆง่ฝๆฅๅ
โ โโโ 2026ๅนด5ๆ25ๆฅ.md # ๅ
ผๅฎนๆงๅฎกๆฅๆฅๅ
โโโ config.go # ้
็ฝฎ็ปๆ๏ผๅซ่ถ
ๆถ้
็ฝฎ๏ผ
โโโ context.go # ไธไธๆ็ๆๅจ
โโโ doc.go # Go ๆๆกฃๆณจ้
โโโ tcp.go # TCP ่ฟๆฅ็ฎก็๏ผๅซ้่ฟๆบๅถใ็ๆง้ๆ๏ผ
โโโ tcp_pool.go # TCP ่ฟๆฅๆฑ
โโโ tag.go # Tag ๆไฝๆ ธๅฟ๏ผๅซไบๅกๆงๆฏๆ๏ผ
โโโ request.go # ่ฏทๆฑๅค็๏ผๅซ ForwardClose๏ผ
โโโ monitoring.go # ่ฏๆญ็ๆง๏ผ่ฟๆฅ็ถๆใ็ป่ฎกๆๆ ๏ผ
โโโ udp.go # UDP ๅนฟๆญๅ็ฐ
โโโ example.go # ไฝฟ็จ็คบไพ
โโโ go.mod # Go ๆจกๅ้
็ฝฎ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ EIPTCP โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ Config โ โ TCPConn โ โ Session โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Request Handler โ โ
โ โ - RegisterSession() โ โ
โ โ - UnRegisterSession() โ โ
โ โ - ListIdentity() โ โ
โ โ - SendRRData() / SendUnitData() โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Tag โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ Name โ โ Type โ โ Value โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Read/Write Methods โ โ
โ โ - Read() / Write() โ โ
โ โ - SetInt32() / SetString() โ โ
โ โ - Int32() / String() โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโ
โ ๅผๅง โ
โโโโโโโโฌโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ NewTCP() โ ๅๅปบ TCP ่ฟๆฅๅฏน่ฑก
โ - ่งฃๆๅฐๅ โ
โ - ๅๅงๅ้
็ฝฎ โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Connect() โ ๅปบ็ซ TCP ่ฟๆฅ
โ - DialTCP() โ
โ - SetKeepAlive โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ RegisterSession โ ๆณจๅไผ่ฏ
โ - ็ๆไธไธๆ โ
โ - ๅ้ๆณจๅ่ฏทๆฑ โ
โ - ่ทๅไผ่ฏๅฅๆ โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโ
โๅฎๆ โ
โโโโโโโโโ
โโโโโโโโโโโโโโโ
โ ๅผๅง โ
โโโโโโโโฌโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ AllTags() โ ่ทๅๆๆ Tag
โ - ๆฅ่ฏขๅฎไพๅฑๆง โ
โ - ๆๅปบ Tag ๆ ๅฐ โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ tag.Read() โ ่ฏปๅๅไธช Tag
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TCP.Send() โ ๅ้่ฏทๆฑ
โ โโโโโโโโโโโโโโโโโโโโโโโโ
โ โ readRequest() โโ ๆๅปบ่ฏป่ฏทๆฑ
โ โ - ๆๅปบ่ทฏๅพ โโ
โ โ - ็ผ็ ๆๅก่ฏทๆฑ โโ
โ โโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TCP.SendRRData() โ ๅ้่ทฏ็ฑๆฐๆฎ
โ - ๅฐ่ฃ
ไธบ CPF ๅ
โ
โ - ๅ้ๅฐ PLC โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๆฅๆถๅๅบ โ
โ - ่งฃ็ MessageRouter โ
โ - ่งฃๆๅๅบๆฐๆฎ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ readParser() โ ่งฃๆ่ฏปๅ็ปๆ
โ - ๆๅ็ฑปๅ โ
โ - ๆๅๅผ โ
โ - ๆดๆฐ Tag.value โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโ
โๅฎๆ โ
โโโโโโโโโ
โโโโโโโโโโโโโโโ
โ ๅผๅง โ
โโโโโโโโฌโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ tag.SetInt32() โ ่ฎพ็ฝฎๅผ๏ผๆๅ
ถไป Set ๆนๆณ๏ผ
โ - ๅบๅๅๅผ โ
โ - ๅญๅ
ฅ wValue โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ tag.Write() โ ๆง่กๅๅ
ฅ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ writeRequest() โ ๆๅปบๅ่ฏทๆฑ
โ - ็ผ็ ็ฑปๅ โ
โ - ็ผ็ ๅผ โ
โ - ๆๅปบ่ทฏๅพ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TCP.Send() โ ๅ้ๅๅ
ฅ่ฏทๆฑ
โ - multiple() ๅฐ่ฃ
โ
โ - SendRRData/SendUnit โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๆฅๆถๅๅบ โ
โ - ๆฃๆฅ็ถๆ โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๆดๆฐ Tag.value โ
โ - copy(wValue, value) โ
โ - ๆธ
็ฉบ wValue โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโ
โๅฎๆ โ
โโโโโโโโโ
โโโโโโโโโโโโโโโ
โ ๅผๅง โ
โโโโโโโโฌโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ NewTCPPool() โ ๅๅปบ่ฟๆฅๆฑ
โ - ๆๅฎๅฎน้ โ
โ - ๅๅงๅ่ฟๆฅ โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Get() โ ่ทๅ่ฟๆฅ
โ - ไปๆฑ ไธญ่ทๅ โ
โ - ้ปๅก็ญๅพ
โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ ไฝฟ็จ่ฟๆฅ โ
โ - Tag ่ฏปๅ โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Put() โ ๅฝ่ฟ่ฟๆฅ
โ - ๆพๅๆฑ ไธญ โ
โโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโ
โๅฎๆ โ
โโโโโโโโโ
type Config struct {
TCPPort uint16 // TCP ็ซฏๅฃ๏ผ้ป่ฎค 44818๏ผ
UDPPort uint16 // UDP ็ซฏๅฃ๏ผ้ป่ฎค 44818๏ผ
Slot uint8 // ๆงๅถๅจๆงฝไฝ
TimeTick types.USInt // ่ฟๆฅๆถ้ดๅปๅบฆ๏ผๆฏซ็ง๏ผ
TimeTickOut types.USInt // ่ฟๆฅ่ถ
ๆถ๏ผTimeTick ๅไฝ๏ผ
ConnectTimeout time.Duration // ่ฟๆฅ่ถ
ๆถ๏ผ้ป่ฎค 30 ็ง๏ผ
ReadTimeout time.Duration // ่ฏปๅ่ถ
ๆถ๏ผ้ป่ฎค 10 ็ง๏ผ
WriteTimeout time.Duration // ๅๅ
ฅ่ถ
ๆถ๏ผ้ป่ฎค 10 ็ง๏ผ
OperationTimeout time.Duration // ๆไฝ่ถ
ๆถ๏ผ้ป่ฎค 15 ็ง๏ผ
}config := ethernet_ip.DefaultConfig()
config.ConnectTimeout = time.Second * 60 // ่ชๅฎไน่ฟๆฅ่ถ
ๆถ
config.ReadTimeout = time.Second * 15 // ่ชๅฎไน่ฏปๅ่ถ
ๆถ
conn, err := ethernet_ip.NewTCP("192.168.1.10", config)state := conn.GetConnectionState()
fmt.Printf("ๅฝๅ็ถๆ: %s\n", state.String())
// ็ถๆๅผ: Disconnected, Connecting, Connected, Reconnectingstats := conn.GetConnectionStats()
fmt.Printf("่ฟๆฅๆฌกๆฐ: %d\n", stats.ConnectCount)
fmt.Printf("ๆญๅผๆฌกๆฐ: %d\n", stats.DisconnectCount)
fmt.Printf("้่ฟๆฌกๆฐ: %d\n", stats.ReconnectCount)
fmt.Printf("ๆป่ฏทๆฑๆฐ: %d\n", stats.TotalRequests)
fmt.Printf("ๆๅ่ฏทๆฑๆฐ: %d\n", stats.SuccessfulRequests)
fmt.Printf("ๅคฑ่ดฅ่ฏทๆฑๆฐ: %d\n", stats.FailedRequests)
fmt.Printf("ๅนณๅๅๅบๆถ้ด: %v\n", stats.AvgResponseTime)
fmt.Printf("ๆๅฐๅๅบๆถ้ด: %v\n", stats.MinResponseTime)
fmt.Printf("ๆๅคงๅๅบๆถ้ด: %v\n", stats.MaxResponseTime)
fmt.Printf("ๆปๅ้ๅญ่: %d\n", stats.TotalBytesSent)
fmt.Printf("ๆปๆฅๆถๅญ่: %d\n", stats.TotalBytesReceived)// ๆณจๅ่ฟๆฅ็ถๆ็ๅฌๅจ
listener := func(event ethernet_ip.ConnectionEvent) {
fmt.Printf("[%s] ็ถๆๅๅ: %s\n",
event.Timestamp.Format(time.RFC3339),
event.State.String())
if event.Error != nil {
fmt.Printf("้่ฏฏ: %v\n", event.Error)
}
// ๅฏไปฅๅจ่ฟ้ๅฎ็ฐๅ่ญฆใๆฅๅฟ่ฎฐๅฝ็ญ้ป่พ
if event.State == ethernet_ip.StateDisconnected {
log.Warn("่ฟๆฅๆญๅผ๏ผๅๅค้่ฟ...")
} else if event.State == ethernet_ip.StateConnected {
log.Info("่ฟๆฅๅทฒๆขๅค")
}
}
conn.AddConnectionListener(listener)
// ็งป้ค็ๅฌๅจ
conn.RemoveConnectionListener(listener)conn.ResetConnectionStats()// ๅ็ฐ็ฝ็ปไธญ็ EIP ่ฎพๅค๏ผ้ป่ฎค่ถ
ๆถ 5 ็ง๏ผ
devices, err := ethernet_ip.DiscoverDevices(time.Second * 5)
if err != nil {
log.Fatal(err)
}
for _, device := range devices {
fmt.Printf("่ฎพๅคๅ็งฐ: %s\n", device.DeviceName)
fmt.Printf("IPๅฐๅ: %s\n", device.IPAddress)
fmt.Printf("MACๅฐๅ: %s\n", device.MacAddress)
fmt.Printf("ไบงๅไปฃ็ : %d\n", device.ProductCode)
fmt.Printf("ๅบๅๅท: %d\n", device.SerialNumber)
fmt.Printf("ไพๅบๅID: %d\n", device.VendorID)
fmt.Printf("็ๆฌ: %d.%d\n", device.RevisionMajor, device.RevisionMinor)
fmt.Println("---")
}// ไฝฟ็จ่ชๅฎไน็ซฏๅฃ่ฟ่ก่ฎพๅคๅ็ฐ
devices, err := ethernet_ip.DiscoverDevicesWithPort(time.Second * 5, 44818)| ๅญๆฎต | ็ฑปๅ | ่ฏดๆ |
|---|---|---|
| IPAddress | net.IP | ่ฎพๅค IP ๅฐๅ |
| MacAddress | string | MAC ๅฐๅ |
| DeviceName | string | ่ฎพๅคๅ็งฐ |
| ProductCode | uint16 | ไบงๅไปฃ็ |
| RevisionMajor | uint8 | ไธป็ๆฌๅท |
| RevisionMinor | uint8 | ๆฌก็ๆฌๅท |
| Status | uint16 | ่ฎพๅค็ถๆ |
| SerialNumber | uint32 | ๅบๅๅท |
| VendorID | uint16 | ไพๅบๅ ID |
// ๅๅปบ TagGroup ๅนถๅฏ็จไบๅกๆง
group := ethernet_ip.NewTagGroup(nil)
group.AtomicWrite = true // ๅฏ็จๅๅญๅๅ
ฅๆจกๅผ
// ๆทปๅ ๅคไธช Tag
group.Add(tag1)
group.Add(tag2)
group.Add(tag3)
// ่ฎพ็ฝฎๆฐๅผ
tag1.SetInt32(100)
tag2.SetString("test")
tag3.SetFloat32(3.14)
// ๆง่กๆน้ๅๅ
ฅ๏ผไบๅกๆง๏ผ
err := group.Write()
if err != nil {
// ๅฆๆไปปไฝไธไธชๅๅ
ฅๅคฑ่ดฅ๏ผๆๆๆ ็ญพ็ changed ็ถๆ้ฝไผๆขๅค
log.Printf("ๅๅ
ฅๅคฑ่ดฅ๏ผๅทฒๅๆป: %v\n", err)
} else {
log.Println("ๆๆๆ ็ญพๅๅ
ฅๆๅ")
}ๅฝ AtomicWrite ๅฏ็จๆถ๏ผTagGroup.Write() ไผ๏ผ
- ๆถ้ๆๆๅพ ๅๅ ฅ็ๆ ็ญพ
- ๅ้ๆน้ๅๅ ฅ่ฏทๆฑ
- ๆฃๆฅๆฏไธชๅๅบ็็ถๆ็
- ๅฆๆไปปไฝไธไธชๅๅ
ฅๅคฑ่ดฅ๏ผๆขๅคๆๆๆ ็ญพ็
changed็ถๆ - ๅชๆๆๆๅๅ ฅ้ฝๆๅ๏ผๆๆดๆฐๆ ็ญพ็ๅผ
ๆฌๅบๆฏๆไธค็ง่ฎฟ้ฎๆจกๅผๆฅไธ PLC ้ไฟก๏ผๆ ๅ CIP ๆจกๅผๅ Logix ๆจกๅผใ
ๆ ๅ CIP๏ผCommon Industrial Protocol๏ผๆจกๅผไฝฟ็จ Symbolic Addressing ๆนๅผ่ฎฟ้ฎๆ ็ญพใ่ฟ็งๆจกๅผ้็จไบๅคงๅคๆฐ Allen-Bradley PLC๏ผๅ ๆฌ ControlLogixใCompactLogix ็ญใ
็น็น๏ผ
- ไฝฟ็จ็ฌฆๅทๅฐๅ๏ผๅฆ
Program:MainProgram.Counter๏ผ - ้่ฟ Symbol Object (Class 0x6B) ่ฎฟ้ฎๆ ็ญพ
- ๆฏๆๅฎๆด็ๆ ็ญพ่ทฏๅพ่งฃๆ
- ้็จไบๆ ๅ CIP ่ฎพๅค
ไฝฟ็จ็คบไพ๏ผ
// ๅๅปบ่ฟๆฅ
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// ๅปบ็ซ่ฟๆฅ
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
// ไฝฟ็จๆ ๅ CIP ๆจกๅผ่ฏปๅๆ ็ญพ
tags, err := conn.AllTags()
if err != nil {
log.Fatal(err)
}
tag := tags["Program:MainProgram.IntTag"]
if err := tag.Read(); err != nil {
log.Fatal(err)
}
fmt.Printf("ๅผ: %d\n", tag.Int32())ๆ ๅ CIP ๆจกๅผ่ฐ็จๆต็จ๏ผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๆ ๅ CIP ๆจกๅผๆต็จ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. AllTags() โ
โ โโ ๆฅ่ฏข Symbol Object (Class 0x6B) โ
โ โโ ่ทๅๆๆๆ ็ญพๅ็งฐๅ็ฑปๅ โ
โ โ
โ 2. InitializeTag(name, tag) โ
โ โโ ๆๅปบ็ฌฆๅท่ทฏๅพ โ
โ โโ ่ฎพ็ฝฎๆ ็ญพ็ฑปๅๅ่ฟๆฅๅผ็จ โ
โ โ
โ 3. tag.Read() โ
โ โโ SendRRData() โ
โ โโ CIP Read Tag Service (0x4C) โ
โ โโ ่ฟๅ Message Router Response โ
โ โโ ่งฃๆๅๅบๆฐๆฎๅฐ tag.value โ
โ โ
โ 4. tag.Write() โ
โ โโ SendRRData() โ
โ โโ CIP Write Tag Service (0x4D) โ
โ โโ ่ฟๅ็ถๆ็ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Logix ๆจกๅผไฝฟ็จ Logix Class 2 ๅฏน่ฑก๏ผClass 0x02๏ผ็ๅฑๆง่ฎฟ้ฎๆนๅผใ่ฟ็งๆจกๅผไธป่ฆ็จไบไธ cpppo ๆๅกๅจๆๆไบ็นๅฎ็ Logix ่ฎพๅค้ไฟกใ
็น็น๏ผ
- ไฝฟ็จๅฑๆง ID ่ฎฟ้ฎ๏ผๅฆๅฑๆง 1 ๅฏนๅบ BoolTag๏ผ
- ้่ฟ Class 2, Instance 1 ่ฎฟ้ฎๆ ็ญพ
- ไฝฟ็จ Get Attribute Single (0x0E) ๆๅก
- ้็จไบ cpppo ๆจกๆๅจๅ้จๅ Logix ่ฎพๅค
ไฝฟ็จ็คบไพ๏ผ
// ๅๅปบ่ฟๆฅ
conn, err := ethernet_ip.NewTCP("127.0.0.1", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// ๅปบ็ซ่ฟๆฅ
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
// ไฝฟ็จ Logix ๆจกๅผ๏ผClass 2 ๅฑๆง่ฎฟ้ฎ๏ผ่ฏปๅๆ ็ญพ
// ๅฑๆง ID 1 = BoolTag, 3 = IntTag, 10 = RealTag
data, err := conn.ReadClass2Attribute(3) // ่ฏปๅ IntTag
if err != nil {
log.Fatal(err)
}
// ่งฃๆ INT ็ฑปๅๆฐๆฎ
intValue := int16(binary.LittleEndian.Uint16(data[:2]))
fmt.Printf("IntTag ๅผ: %d\n", intValue)Logix ๆจกๅผ่ฐ็จๆต็จ๏ผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Logix ๆจกๅผๆต็จ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. ReadClass2Attribute(attrID) โ
โ โโ ๆๅปบ CIP ่ทฏๅพ โ
โ โโ Class 2, Instance 1, Attribute attrID โ
โ โ
โ 2. SendRRData() โ
โ โโ CIP Get Attribute Single (0x0E) โ
โ โโ ่ฟๅ Message Router Response โ
โ โโ ๆๅ ResponseData โ
โ โ
โ 3. ่งฃๆๆฐๆฎ โ
โ โโ ๆ นๆฎๅฑๆง ID ๅฏนๅบ็ๆฐๆฎ็ฑปๅ่งฃๆ โ
โ โโ ่ฟๅๅๅงๅญ่ๆฐ็ปไพไธๅฑๅค็ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| ็นๆง | ๆ ๅ CIP ๆจกๅผ | Logix ๆจกๅผ |
|---|---|---|
| ่ฎฟ้ฎๆนๅผ | Symbolic Addressing | Class 2 ๅฑๆง |
| ๅฐๅๆ ผๅผ | Program:MainProgram.Tag |
ๅฑๆง ID (1-12) |
| ้็จ่ฎพๅค | ๆ ๅ Allen-Bradley PLC | cpppo ๆๅกๅจใ้จๅ Logix |
| ๆๅก็ฑปๅ | Read/Write Tag (0x4C/0x4D) | Get Attribute Single (0x0E) |
| ๆ ็ญพๅ็ฐ | AllTags() ่ชๅจๅ็ฐ |
้้ขๅ ็ฅ้ๅฑๆงๆ ๅฐ |
| UDT ๆฏๆ | โ | โ |
- ็ไบง็ฏๅข๏ผไฝฟ็จ ๆ ๅ CIP ๆจกๅผ๏ผๆฏๆๅฎๆดๅ่ฝ
- ๆต่ฏ็ฏๅข๏ผไฝฟ็จ Logix ๆจกๅผ้ ๅ cpppo ๆจกๆๅจ
- ๅ ผๅฎนๆงๆต่ฏ๏ผไธค็งๆจกๅผ้ฝๅบๆต่ฏ
ๆฌๅบๅทฒๆฏๆไธ cpppo ๆๅกๅจ็้ไฟกใcpppo ๆๅกๅจไฝฟ็จ Logix Class 2 ๅฏน่ฑกๆฅๅญๅจๆ ็ญพ๏ผไธๆ ๅ CIP Symbolic Path ๆ ผๅผไธๅใ
cpppo ๆๅกๅจๅฐๆ ็ญพๆ ๅฐๅฐ Logix Class 2, Instance 1 ็ๅฑๆง๏ผไฝฟ็จ CIP Get Attribute Single (0x0E) ๆๅก่ฟ่ก่ฎฟ้ฎ๏ผ
| ๆ ็ญพๅ | ๅฑๆง ID | ๆฐๆฎ็ฑปๅ |
|---|---|---|
BoolTag |
1 | BOOL |
SintTag |
2 | SINT |
IntTag |
3 | INT |
DintTag |
4 | DINT |
LintTag |
5 | LINT |
UsintTag |
6 | USINT |
UintTag |
7 | UINT |
UdintTag |
8 | UDINT |
UlintTag |
9 | ULINT |
RealTag |
10 | REAL |
LrealTag |
11 | LREAL |
StringTag |
12 | STRING |
ไฝฟ็จ ReadClass2Attribute ๅ WriteClass2Attribute ๆนๆณ็ดๆฅ่ฎฟ้ฎ Class 2 ๅฏน่ฑก็ๅฑๆง๏ผ
package main
import (
"encoding/binary"
"fmt"
"log"
"math"
"github.com/anviod/ethernet-ip"
)
func main() {
// ๅๅปบ่ฟๆฅ
conn, err := ethernet_ip.NewTCP("127.0.0.1", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// ๅปบ็ซ่ฟๆฅ
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
// ไฝฟ็จ Class 2 ๅฑๆง่ฎฟ้ฎๆนๅผ่ฏปๅๆ ็ญพ
// ๅฑๆง ID 1 = BoolTag
data, err := conn.ReadClass2Attribute(1)
if err != nil {
log.Fatal(err)
}
fmt.Printf("BoolTag ๅผ: %v\n", data[0] != 0)
// ๅๅ
ฅ DINT ็ฑปๅๆ ็ญพ (ๅฑๆง ID 4 = DintTag)
if err := conn.WriteClass2Attribute(4, []byte{0x39, 0x30, 0x00, 0x00}); err != nil {
log.Fatal(err)
}
// ่ฏปๅ REAL ็ฑปๅๆ ็ญพ
data, err = conn.ReadClass2Attribute(10)
if err != nil {
log.Fatal(err)
}
floatValue := math.Float32frombits(binary.LittleEndian.Uint32(data[:4]))
fmt.Printf("RealTag ๅผ: %f\n", floatValue)
}่ฟ่ก cpppo ๅ ผๅฎนๆต่ฏ๏ผ
# ๅฏๅจ cpppo ๆๅกๅจ
python test/cpppo/ethernet_ip_server_cpppo.py
# ่ฟ่ก Go ๆต่ฏ
go test -v -run TestProtocolVerifier_Cpppoๆต่ฏ็ปๆ็คบไพ๏ผ
[้ช่ฏ] Session ๆณจๅ
โ Session ๆณจๅๆๅ: 0xC17173CA
[้ช่ฏ] Identity Object
โ ไพๅบๅID: 1
โ ่ฎพๅค็ฑปๅ: 14
โ ไบงๅไปฃ็ : 54
[้ช่ฏ] ๆฐๆฎ็ฑปๅๆฏๆ (cpppo Class 2 ๆนๅผ)
โ BoolTag (BOOL): true
โ SintTag (SINT): 42
โ IntTag (INT): 12345
โ DintTag (DINT): 987654321
โ RealTag (REAL): 3.14159
โ StringTag (STRING): Hello World
========================================
cpppo ๅ
ผๅฎน้ช่ฏ็ปๆๆฑๆป: ้่ฟ=19, ๅคฑ่ดฅ=0
========================================
- cpppo ๆๅกๅจ้่ฆๅ ๅฏๅจๆ่ฝ่ฟ่กๆต่ฏ
- ้ป่ฎค็ซฏๅฃไธบ 44818
- ็กฎไฟ้ฒ็ซๅขๅ ่ฎธ TCP 44818 ็ซฏๅฃ้ไฟก
- ไฝฟ็จ Class 2 ๆนๅผ่ฎฟ้ฎๆถ๏ผๆ ็ญพๅ้่ฆไธ cpppo ๆๅกๅจ้ ็ฝฎ็ๆ ็ญพๅไธ่ด
type Config struct {
TCPPort uint16 // TCP ็ซฏๅฃ๏ผ้ป่ฎค 44818๏ผ
UDPPort uint16 // UDP ็ซฏๅฃ๏ผ้ป่ฎค 44818๏ผ
Slot uint8 // ๆงๅถๅจๆงฝไฝ
TimeTick types.USInt // ่ฟๆฅๆถ้ดๅปๅบฆ๏ผๆฏซ็ง๏ผ
TimeTickOut types.USInt // ่ฟๆฅ่ถ
ๆถ๏ผTimeTick ๅไฝ๏ผ
ConnectTimeout time.Duration // ่ฟๆฅ่ถ
ๆถ๏ผ้ป่ฎค 30 ็ง๏ผ
ReadTimeout time.Duration // ่ฏปๅ่ถ
ๆถ๏ผ้ป่ฎค 10 ็ง๏ผ
WriteTimeout time.Duration // ๅๅ
ฅ่ถ
ๆถ๏ผ้ป่ฎค 10 ็ง๏ผ
OperationTimeout time.Duration // ๆไฝ่ถ
ๆถ๏ผ้ป่ฎค 15 ็ง๏ผ
}่ทๅ้ป่ฎค้ ็ฝฎใ
config := DefaultConfig()
config.ConnectTimeout = time.Second * 60 // ่ชๅฎไน่ฟๆฅ่ถ
ๆถ
conn, err := NewTCP("192.168.1.10", config)ๅๅปบๆฐ็ TCP ่ฟๆฅๅฏน่ฑกใ
conn, err := NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal(err)
}ๅปบ็ซ TCP ่ฟๆฅๅนถๆณจๅไผ่ฏใ
err := conn.Connect()
if err != nil {
log.Fatal(err)
}
defer conn.Close()ๆฃๆฅ่ฟๆฅๆฏๅฆๅทฒๅปบ็ซไธไผ่ฏๅทฒๆณจๅใ
if conn.IsConnected() {
log.Println("่ฟๆฅๅทฒๅปบ็ซ")
}ๅ ณ้ญ่ฟๆฅๅนถๆณจ้ไผ่ฏใ
err := conn.Close()ๆณจๅ EIP ไผ่ฏ๏ผ่ทๅไผ่ฏๅฅๆใ
ๆณจ้ๅฝๅไผ่ฏใ
่ทๅ่ฎพๅค่ฏๅซไฟกๆฏ๏ผ่ฎพๅค็ฑปๅใๅๅใๅบๅๅท็ญ๏ผใ
identity, err := conn.ListIdentity()
fmt.Println(identity)่ทๅ็ฝ็ปๆฅๅฃไฟกๆฏใ
่ทๅ่ฎพๅคๆฏๆ็ๆๅกๅ่กจใ
่ทๅๆๆๅฏ็จ็ Tagใ
tags, err := conn.AllTags()
for name, tag := range tags {
fmt.Printf("Tag: %s, Type: %s\n", name, tag.TypeString())
}ๅๅงๅๆๅฎๅ็งฐ็ Tagใ
var tag Tag
conn.InitializeTag("OP.UDT_Alarm.DINT_065_096", &tag)
err := tag.Read()่ฏปๅ Tag ็ๅฝๅๅผใ
err := tag.Read()
if err != nil {
log.Fatal(err)
}
value := tag.Int32()่ทๅ Tag ็ๅฝๅๅผ๏ผ่ชๅจ้้ ็ฑปๅ๏ผใ
value := tag.GetValue()
switch v := value.(type) {
case int32:
fmt.Println("DINT:", v)
case string:
fmt.Println("STRING:", v)
}่ฎพ็ฝฎ Tag ไธบ 32 ไฝๆดๆฐใ
tag.SetInt32(123)
err := tag.Write()่ฎพ็ฝฎ Tag ไธบๅญ็ฌฆไธฒใ
tag.SetString("hello world")
err := tag.Write()ๅ ถไป Set ๆนๆณ๏ผ
SetInt8(i int8)SetUInt8(i uint8)SetInt16(i int16)SetUInt16(i uint16)SetInt32(i int32)SetUInt32(i uint32)SetInt64(i int64)SetUInt64(i uint64)SetFloat32(f float32)SetFloat64(f float64)
| ๆนๆณ | ่ฟๅ็ฑปๅ | ่ฏดๆ |
|---|---|---|
Bool() |
bool |
่ทๅๅธๅฐๅผ |
Int8() |
int8 |
่ทๅ 8 ไฝๆดๆฐ |
UInt8() |
uint8 |
่ทๅ 8 ไฝๆ ็ฌฆๅทๆดๆฐ |
Int16() |
int16 |
่ทๅ 16 ไฝๆดๆฐ |
UInt16() |
uint16 |
่ทๅ 16 ไฝๆ ็ฌฆๅทๆดๆฐ |
Int32() |
int32 |
่ทๅ 32 ไฝๆดๆฐ |
UInt32() |
uint32 |
่ทๅ 32 ไฝๆ ็ฌฆๅทๆดๆฐ |
Int64() |
int64 |
่ทๅ 64 ไฝๆดๆฐ |
UInt64() |
uint64 |
่ทๅ 64 ไฝๆ ็ฌฆๅทๆดๆฐ |
Float32() |
float32 |
่ทๅ 32 ไฝๆตฎ็นๆฐ |
Float64() |
float64 |
่ทๅ 64 ไฝๆตฎ็นๆฐ |
String() |
string |
่ทๅๅญ็ฌฆไธฒ |
ๅๅปบ Tag ็ปใ
lock := new(sync.Mutex)
group := NewTagGroup(lock)ๆทปๅ Tag ๅฐ็ปใ
tag1 := tags["tag1"]
tag2 := tags["tag2"]
group.Add(tag1)
group.Add(tag2)ๆน้่ฏปๅๆๆ Tagใ
err := group.Read()ๆน้ๅๅ ฅๆๆๅทฒไฟฎๆน็ Tagใ
tag1.SetInt32(100)
tag2.SetString("updated")
err := group.Write()ไป่ฟๆฅๆน้่ฏปๅๅคไธชๆฐๆฎๅ ใ
packets, err := conn.BatchRead(10)
if err != nil {
log.Fatal(err)
}
for _, p := range packets {
// ๅค็ๆฏไธชๆฐๆฎๅ
}ๆน้ๅๅ ฅๅคไธชๆฐๆฎๅ ๅฐ่ฟๆฅใ
packets := []*packet.Packet{packet1, packet2, packet3}
err := conn.BatchWrite(packets)
if err != nil {
log.Fatal(err)
}่ทๅๅฝๅ่ฟๆฅ็ถๆใ
state := conn.GetConnectionState()
fmt.Printf("่ฟๆฅ็ถๆ: %s\n", state.String())
// ่พๅบ: Connected, Disconnected, Connecting, Reconnecting่ทๅ่ฟๆฅ็ป่ฎกไฟกๆฏใ
stats := conn.GetConnectionStats()
fmt.Printf("่ฟๆฅๆฌกๆฐ: %d\n", stats.ConnectCount)
fmt.Printf("ๆญๅผๆฌกๆฐ: %d\n", stats.DisconnectCount)
fmt.Printf("้่ฟๆฌกๆฐ: %d\n", stats.ReconnectCount)
fmt.Printf("ๆป่ฏทๆฑๆฐ: %d\n", stats.TotalRequests)
fmt.Printf("ๆๅ่ฏทๆฑๆฐ: %d\n", stats.SuccessfulRequests)
fmt.Printf("ๅนณๅๅๅบๆถ้ด: %v\n", stats.AvgResponseTime)ๆณจๅ่ฟๆฅ็ถๆๅๅ็ๅฌๅจใ
listener := func(event ConnectionEvent) {
fmt.Printf("็ถๆๅๅ: %s -> %s\n",
event.State.String(),
event.Timestamp.Format(time.RFC3339))
if event.Error != nil {
fmt.Printf("้่ฏฏ: %v\n", event.Error)
}
}
conn.AddConnectionListener(listener)้็ฝฎ่ฟๆฅ็ป่ฎกไฟกๆฏใ
conn.ResetConnectionStats()ๅนฟๆญๅ็ฐ็ฝ็ปไธญ็ EIP ่ฎพๅคใ
devices, err := ethernet_ip.DiscoverDevices(time.Second * 5)
if err != nil {
log.Fatal(err)
}
for _, device := range devices {
fmt.Printf("่ฎพๅคๅ็งฐ: %s\n", device.DeviceName)
fmt.Printf("IPๅฐๅ: %s\n", device.IPAddress)
fmt.Printf("MACๅฐๅ: %s\n", device.MacAddress)
fmt.Printf("ไบงๅไปฃ็ : %d\n", device.ProductCode)
fmt.Printf("ๅบๅๅท: %d\n", device.SerialNumber)
}ๆๅฎ็ซฏๅฃ่ฟ่ก่ฎพๅคๅ็ฐใ
devices, err := ethernet_ip.DiscoverDevicesWithPort(time.Second * 5, 44818)type DiscoveredDevice struct {
IPAddress net.IP // ่ฎพๅค IP ๅฐๅ
MacAddress string // MAC ๅฐๅ
DeviceName string // ่ฎพๅคๅ็งฐ
ProductCode uint16 // ไบงๅไปฃ็
RevisionMajor uint8 // ไธป็ๆฌๅท
RevisionMinor uint8 // ๆฌก็ๆฌๅท
Status uint16 // ่ฎพๅค็ถๆ
SerialNumber uint32 // ๅบๅๅท
VendorID uint16 // ไพๅบๅ ID
}ๅฏ็จๅๅญๅๅ ฅๆจกๅผ๏ผ็กฎไฟๆน้ๅๅ ฅ็ๅๅญๆงใ
group := ethernet_ip.NewTagGroup(nil)
group.AtomicWrite = true // ๅฏ็จไบๅกๆงๅๅ
ฅ
group.Add(tag1)
group.Add(tag2)
tag1.SetInt32(100)
tag2.SetInt32(200)
// ๅฆๆไปปไฝไธไธชๅๅ
ฅๅคฑ่ดฅ๏ผๆๆๆ ็ญพ็ changed ็ถๆ้ฝไผๆขๅค
err := group.Write()ๅๅปบ่ฟๆฅๆฑ ใ
pool, err := NewTCPPool("192.168.1.10", nil, 10)
if err != nil {
log.Fatal(err)
}
defer pool.Close()ไปๆฑ ไธญ่ทๅ่ฟๆฅใ
conn, err := pool.Get()
if err != nil {
log.Fatal(err)
}
defer pool.Put(conn)ๅฝ่ฟ่ฟๆฅๅฐๆฑ ไธญใ
ๅ ณ้ญ่ฟๆฅๆฑ ใ
package main
import (
"log"
"github.com/anviod/ethernet-ip"
)
func main() {
// ๅๅปบ่ฟๆฅ
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal("ๅๅปบ่ฟๆฅๅคฑ่ดฅ:", err)
}
// ๅปบ็ซ่ฟๆฅ
err = conn.Connect()
if err != nil {
log.Fatal("่ฟๆฅๅคฑ่ดฅ:", err)
}
defer conn.Close()
// ่ทๅๆๆ Tag
tags, err := conn.AllTags()
if err != nil {
log.Fatal("่ทๅ Tag ๅ่กจๅคฑ่ดฅ:", err)
}
// ่ฏปๅๅไธช Tag
tag := tags["tagName"]
err = tag.Read()
if err != nil {
log.Fatal("่ฏปๅ Tag ๅคฑ่ดฅ:", err)
}
// ่ทๅๅผ
log.Println("Tag ๅผ:", tag.Int32())
}package main
import (
"log"
"github.com/anviod/ethernet-ip"
)
func main() {
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
// ๅๅงๅ Tag
var tag ethernet_ip.Tag
conn.InitializeTag("Counter", &tag)
// ่ฏปๅ
if err := tag.Read(); err != nil {
log.Fatal(err)
}
log.Printf("ๅฝๅๅผ: %d\n", tag.Int32())
// ๅๅ
ฅ
tag.SetInt32(12345)
if err := tag.Write(); err != nil {
log.Fatal(err)
}
log.Println("ๅๅ
ฅๆๅ")
}package main
import (
"log"
"sync"
"github.com/anviod/ethernet-ip"
)
func main() {
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
tags, err := conn.AllTags()
if err != nil {
log.Fatal(err)
}
// ๅๅปบ Tag ็ป
lock := new(sync.Mutex)
group := ethernet_ip.NewTagGroup(lock)
// ๆทปๅ ๅคไธช Tag
group.Add(tags["tag1"])
group.Add(tags["tag2"])
group.Add(tags["tag3"])
// ๆน้่ฏปๅ
if err := group.Read(); err != nil {
log.Fatal(err)
}
// ่ฎพ็ฝฎๆฐๅผ
tags["tag1"].SetInt32(100)
tags["tag2"].SetInt32(200)
tags["tag3"].SetString("updated")
// ๆน้ๅๅ
ฅ
if err := group.Write(); err != nil {
log.Fatal(err)
}
log.Println("ๆน้ๆไฝๅฎๆ")
}package main
import (
"log"
"github.com/anviod/ethernet-ip"
)
func main() {
// ๅๅปบ่ฟๆฅๆฑ
pool, err := ethernet_ip.NewTCPPool("192.168.1.10", nil, 10)
if err != nil {
log.Fatal(err)
}
defer pool.Close()
// ่ทๅ่ฟๆฅ
conn, err := pool.Get()
if err != nil {
log.Fatal(err)
}
// ไฝฟ็จ่ฟๆฅ
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
tags, err := conn.AllTags()
if err != nil {
log.Fatal(err)
}
log.Printf("่ทๅๅฐ %d ไธช Tag\n", len(tags))
// ๅฝ่ฟ่ฟๆฅ
pool.Put(conn)
}package main
import (
"log"
"github.com/anviod/ethernet-ip"
)
func main() {
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
// ่ทๅ่ฎพๅคไฟกๆฏ
identities, err := conn.ListIdentity()
if err != nil {
log.Fatal(err)
}
log.Printf("่ฎพๅค่ฏๅซ: %+v\n", identities)
// ่ทๅๆฅๅฃไฟกๆฏ
interfaces, err := conn.ListInterface()
if err != nil {
log.Fatal(err)
}
log.Printf("ๆฅๅฃไฟกๆฏ: %+v\n", interfaces)
// ่ทๅๆๅกๅ่กจ
services, err := conn.ListServices()
if err != nil {
log.Fatal(err)
}
log.Printf("ๆๅกๅ่กจ: %+v\n", services)
}package main
import (
"fmt"
"log"
"github.com/anviod/ethernet-ip"
)
func main() {
conn, err := ethernet_ip.NewTCP("192.168.1.10", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if err := conn.Connect(); err != nil {
log.Fatal(err)
}
tags, err := conn.AllTags()
if err != nil {
log.Fatal(err)
}
for name, tag := range tags {
if err := tag.Read(); err != nil {
continue
}
fmt.Printf("Tag: %s\n", name)
fmt.Printf(" Type: %s\n", tag.TypeString())
fmt.Printf(" Value: %v\n", tag.GetValue())
}
}ๆฌ้กน็ฎๅ ๅซๅค็ง็ฑปๅ็ๆต่ฏ๏ผ็กฎไฟไปฃ็ ่ดจ้ๅๅ่ฝๆญฃ็กฎๆง๏ผ
| ๆต่ฏ็ฑปๅ | ๆ่ฟฐ | ๆไปถไฝ็ฝฎ |
|---|---|---|
| ๅๅ ๆต่ฏ | ๆต่ฏๅไธชๅฝๆฐๆๆนๆณ็่กไธบ | *_test.go |
| ้ๆๆต่ฏ | ๆต่ฏ็ปไปถไน้ด็ไบคไบ | test/protocol_verifier_test.go |
| ๅ่ฎฎ้ช่ฏๆต่ฏ | ้ช่ฏ EIP ๅ่ฎฎๅ่งๆง | test/protocol_verifier_test.go |
| ๆง่ฝๆต่ฏ | ๆต่ฏๆง่ฝๆๆ | benchmark/ |
ethernet-ip/
โโโ test/
โโโ protocol_verifier_test.go # ๅ่ฎฎ้ช่ฏ้ๆๆต่ฏ
โโโ access_mode_test.go # ่ฎฟ้ฎๆจกๅผๆต่ฏ๏ผCIP/Logix๏ผ
ๆฏๆๆๆ 12 ็งๆฐๆฎ็ฑปๅ็ๅ็ฌ่ฏปๅ๏ผ
| ็ฑปๅ | ๅๅ ฅๆต่ฏ | ่ฏปๅๆต่ฏ | ้ช่ฏๆนๅผ |
|---|---|---|---|
| BOOL | SetBool() |
Bool() |
ๅธๅฐๆฏ่พ |
| SINT | SetInt8() |
Int8() |
ๆฐๅผๆฏ่พ |
| INT | SetInt16() |
Int16() |
ๆฐๅผๆฏ่พ |
| DINT | SetInt32() |
Int32() |
ๆฐๅผๆฏ่พ |
| LINT | SetInt64() |
Int64() |
ๆฐๅผๆฏ่พ |
| USINT | SetUInt8() |
UInt8() |
ๆฐๅผๆฏ่พ |
| UINT | SetUInt16() |
UInt16() |
ๆฐๅผๆฏ่พ |
| UDINT | SetUInt32() |
UInt32() |
ๆฐๅผๆฏ่พ |
| ULINT | SetUInt64() |
UInt64() |
ๆฐๅผๆฏ่พ |
| REAL | SetFloat32() |
Float32() |
็ฒพๅบฆๆฏ่พ |
| LREAL | SetFloat64() |
Float64() |
็ฒพๅบฆๆฏ่พ |
| STRING | SetString() |
String() |
ๅญ็ฌฆไธฒๆฏ่พ |
ๆต่ฏ TagGroup ็ๆน้่ฏปๅๅ่ฝ๏ผ
// ๆน้่ฏปๅๆต่ฏ
group := ethernet_ip.NewTagGroup(nil)
group.Add(tag1)
group.Add(tag2)
group.Read() // ๆน้่ฏปๅ
// ๆน้ๅๅ
ฅๆต่ฏ
tag1.SetInt32(100)
tag2.SetFloat32(3.14)
group.Write() // ๆน้ๅๅ
ฅๆต่ฏไธค็ง่ฎฟ้ฎๆจกๅผ๏ผ
| ๆจกๅผ | ๆต่ฏๅฝๆฐ | ่ฎฟ้ฎๆนๅผ |
|---|---|---|
| ๆ ๅ CIP ๆจกๅผ | TestAccessMode_CIPMode |
Symbolic Addressing |
| Logix ๆจกๅผ | TestAccessMode_LogixModeAttributeMapping |
Class 2 ๅฑๆง |
go test ./...# ่ฟ่กๅๅ
ๆต่ฏ
go test -v -run "TestTag" ./...
# ่ฟ่กๅ่ฎฎ้ช่ฏๆต่ฏ
go test -v -run "TestProtocolVerifier" ./test/...
# ่ฟ่กๆง่ฝๆต่ฏ
go test -bench=. ./benchmark/...# ๅฏๅจ cpppo ๆๅกๅจ
python test/cpppo/ethernet_ip_server_cpppo.py
# ๅจๅฆไธไธช็ป็ซฏ่ฟ่กๆต่ฏ
go test -v -run "TestProtocolVerifier_Cpppo" ./test/...โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅๅ
ๆต่ฏๆต็จ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. ๅๅงๅๆต่ฏ็ฏๅข โ
โ โโ ๅๅปบ Tag ๅฏน่ฑก โ
โ โโ ่ฎพ็ฝฎๆต่ฏๆฐๆฎ โ
โ โ
โ 2. ๆง่กๆต่ฏๆนๆณ โ
โ โโ ่ฐ็จ่ขซๆตๅฝๆฐ/ๆนๆณ โ
โ โโ ๆ่ท่ฟๅๅผ โ
โ โ
โ 3. ้ช่ฏ็ปๆ โ
โ โโ ไฝฟ็จ t.Errorf() / t.Fatalf() โ
โ โโ ่พๅบๆต่ฏๅคฑ่ดฅไฟกๆฏ โ
โ โ
โ 4. ๆธ
็่ตๆบ โ
โ โโ ไฝฟ็จ defer ้ๆพ่ตๆบ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ้ๆๆต่ฏๆต็จ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. ๅปบ็ซ่ฟๆฅ โ
โ โโ NewTCP() ๅๅปบ่ฟๆฅๅฏน่ฑก โ
โ โโ Connect() ๅปบ็ซ TCP ่ฟๆฅ โ
โ โโ RegisterSession() ๆณจๅไผ่ฏ โ
โ โ
โ 2. ๆง่กๆต่ฏ็จไพ โ
โ โโ Session ้ช่ฏ โ
โ โโ Identity ๆฅ่ฏข โ
โ โโ ๆฐๆฎ็ฑปๅ่ฏปๅ้ช่ฏ โ
โ โโ Tag ๅ็ฌ่ฏปๅ โ
โ โโ TagGroup ๆน้ๆไฝ โ
โ โโ ้่ฏฏๅค็ๆต่ฏ โ
โ โ
โ 3. ๆถ้็ปๆ โ
โ โโ ็ป่ฎก้่ฟ/ๅคฑ่ดฅๆฐ้ โ
โ โโ ่พๅบๆต่ฏๆฅๅ โ
โ โ
โ 4. ๆธ
็่ฟๆฅ โ
โ โโ Close() ๅ
ณ้ญ่ฟๆฅ โ
โ โโ UnRegisterSession() ๆณจ้ไผ่ฏ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅ่ฎฎ้ช่ฏๆต่ฏๆต็จ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. ่ฟๆฅๅฐๆต่ฏ่ฎพๅค โ
โ โโ ่ฟๆฅๅฐ cpppo ๆจกๆๅจๆ็ๅฎ PLC โ
โ โ
โ 2. ้ช่ฏๅ่ฎฎๅ่งๆง โ
โ โโ EIP TCP ๅ่ฎฎๆกๆ โ
โ โโ CIP ่ทฏๅพๆๅปบ โ
โ โโ Message Router ๆๅก โ
โ โโ Tag ่ฏปๅๆๅก (0x4C/0x4D) โ
โ โโ Class 2 ๅฑๆง่ฎฟ้ฎ (0x0E) โ
โ โ
โ 3. ้ช่ฏๆฐๆฎๅฎๆดๆง โ
โ โโ ๅญ่ๅบ่ฝฌๆข โ
โ โโ ็ผๅฒๅบๆไฝ โ
โ โโ ๆฐๆฎ็ผ็ /่งฃ็ โ
โ โ
โ 4. ็ๆๆต่ฏๆฅๅ โ
โ โโ ่พๅบ JSON/Markdown ๆ ผๅผๆฅๅ โ
โ โโ ไฟๅญๅฐ doc/ ็ฎๅฝ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
=== RUN TestTag_SetInt32
--- PASS: TestTag_SetInt32 (0.00s)
=== RUN TestTag_GetInt16
--- PASS: TestTag_GetInt16 (0.00s)
=== RUN TestTag_GetString
--- PASS: TestTag_GetString (0.00s)
=== RUN TestTag_Bool
--- PASS: TestTag_Bool (0.00s)
PASS
ok github.com/anviod/ethernet-ip 0.001s
[้ช่ฏ] Session ๆณจๅ
โ Session ๆณจๅๆๅ
[้ช่ฏ] Identity Object
โ ไพๅบๅID: 1
โ ่ฎพๅค็ฑปๅ: 14
โ ไบงๅไปฃ็ : 54
โ ไบงๅๅ็งฐ: cpppo
โ ไบงๅๅบๅๅท: 0x12345678
[้ช่ฏ] ๆฐๆฎ็ฑปๅๆฏๆ (cpppo Class 2 ๆนๅผ)
โ BoolTag (BOOL): true
โ SintTag (SINT): 42
โ IntTag (INT): 12345
โ DintTag (DINT): 987654321
โ RealTag (REAL): 3.14159
โ StringTag (STRING): Hello World
========================================
้ช่ฏ็ปๆๆฑๆป: ้่ฟ=19, ๅคฑ่ดฅ=0
========================================
ๆต่ฏๅฎๆๅไผ็ๆๆง่ฝๆฅๅๅฐ doc/ ็ฎๅฝ๏ผ
# ็ๆๆง่ฝๆฅๅ
go test -bench=. -benchmem ./benchmark/... > doc/BENCHMARK_RESULT.mdๆฌๅบๅทฒ่ฟ่กๅค้กนๆง่ฝไผๅ๏ผ
- ็ผๅฒๅบๆฑ ๅ - ไฝฟ็จ
sync.Poolๅค็จ็ผๅฒๅบ๏ผๅๅฐ GC ๅๅ - ้ๆบๆฐ็ๆๅจไผๅ - ้ขๅๅงๅ็งๅญ๏ผ้ฟๅ ้ๅคๅๅงๅๅผ้
- TCP ็ผๅฒๅบๅค็จ - ่ฟๆฅ็บงๅซ็่ฏปๅ็ผๅฒๅบๅค็จ
- ้่ฏฏ็ญ่ทฏๆบๅถ - ๆฉๆ้่ฏฏ่ฟๅ๏ผๅๅฐๆ ๆๆไฝ
- ้ขๅ้
ๅฎน้ -
NewWithCapacity()ๅๅฐ้ๆฐๅ้
| ๆไฝ | ๅๅ้ | ๅ ๅญๅ้ |
|---|---|---|
| BufferPool_Reuse | ~8000ไธ ops/s | 2 B/op |
| Tag ่ฏปๅ | ~300ไธ ops/s | varies |
| Tag ๅๅ ฅ | ~200ไธ ops/s | varies |
่ฏฆ็ปๆง่ฝๆต่ฏๆฅๅ่ฏทๅ่ doc/PERFORMANCE_OPTIMIZATION_CN.md
ๆฐๅขๅ่ฝ
- ๆฐๅข STRING ๅๅ ฅไผๅ - ็ฎๅๅญ็ฌฆไธฒๅๅ ฅ้ป่พ๏ผๅๆฌก่ฏทๆฑๅฎๆ
- ๆฐๅข ่ถ ๆถ้ ็ฝฎ - ๆฏๆ่ฟๆฅ่ถ ๆถใ่ฏปๅ่ถ ๆถใๅๅ ฅ่ถ ๆถใๆไฝ่ถ ๆถ
- ๆฐๅข ๆง่ฝๅบๅๆต่ฏ - ๆทปๅ ๅฎๆด็ๆง่ฝๆต่ฏๅฅไปถ
- ๆฐๅข ไบๅกๆงๆฏๆ - TagGroup ๅๅญๅๅ ฅ๏ผๅคฑ่ดฅ่ชๅจๅๆป
- ๆฐๅข ่ฏๆญ็ๆง - ่ฟๆฅ็ถๆ็ๆงใ็ป่ฎกๆๆ ๆถ้ใไบไปถ็ๅฌ
- ๆฐๅข UDP ๅนฟๆญๅ็ฐ - ่ฎพๅค่ชๅจๅ็ฐๅ่ฝ
- ๆฐๅข ForwardClose - ่ฟๆฅๅ ณ้ญๆนๆณ๏ผ้ฟๅ ่ตๆบๆณๆผ
- ๆฐๅข ๆๆฐ้้ฟ้่ฟ - ไผๅ้่ฟๆบๅถ๏ผ้ฟๅ ๆๅกๅจๅๅ
Bug ไฟฎๅค
- ไฟฎๅคๅญ็ฌฆไธฒๅๅ ฅ้่ฆไธคๆฌก่ฏทๆฑ็้ฎ้ข
- ไฟฎๅค้่ฟ้ด้ไธบ 0 ็้ฎ้ข
ๆๆกฃๆดๆฐ
- ๆดๆฐๆถๆ็ฎๅฝ็ปๆ
- ๆทปๅ ๆฐๅ่ฝ API ๆๆกฃ
- ๆดๆฐๅ ผๅฎนๆงๅฎกๆฅๆฅๅ
Bug ไฟฎๅค
- ไฟฎๅค TCP ่ฟๆฅๅผๅธธๆญๅผๅ็้่ฟ้ป่พ
- ไฟฎๅค ReadFromFile/WriteToFile ๆนๆณๆชๅฎ็ฐ็ๅ ไฝ้่ฏฏๅค็
- ไฟฎๅค BatchRead/BatchWrite ๆนๆณๆๆกฃ็ผบๅคฑ
ๆฐๅขๅ่ฝ
- ๆฐๅข
IsConnected()ๆนๆณ๏ผ็จไบๆฃๆฅ่ฟๆฅ็ถๆ - ๆฐๅข้่ฟๆบๅถ๏ผๆๅค้่ฏ 3 ๆฌก๏ผ
- ๆฐๅข
BatchRead()ๅBatchWrite()ๆน้ๆฐๆฎๅ ๆไฝๆนๆณ - ๅฎๅๆๆกฃๆณจ้๏ผ่กฅๅ doc.go ๅฎๆด API ๆๆกฃ
ๆง่ฝไผๅ
- ไผๅ TCP ็ผๅฒๅบๅค็จ็ญ็ฅ
- ไผๅ่ฟๆฅๆฑ ่ทๅ/ๅฝ่ฟ้ป่พ
Bug ไฟฎๅค
- ไฟฎๅค NOP ๅฝไปค็ฉบๆฐๆฎๅฏผ่ด cpppo ็ถๆๆบ้่ฏฏ
- ไฟฎๅค Tag.Write() ็ผๅฒๅบๅคๅถ้ฎ้ข (
copyโappend) - ไฟฎๅค
readParseroffset ่ฎก็ฎ้่ฏฏ๏ผๆฉๅฑ็ฑปๅ 0x2a0 ๅบๆฏ๏ผ - ็งป้ค Write() ๅฝๆฐๅไฝ็ nil ๆฃๆฅ
- ๆทปๅ offset ่ดๅผ่พน็ๆฃๆฅ๏ผ้ฟๅ ๅ็่ถ็ panic
ๆฐๅขๅ่ฝ
- ๆฐๅข Tag ๅๅ ๆต่ฏ๏ผ14 ไธชๆต่ฏๅฝๆฐ๏ผ
- ๆฐๅขๆง่ฝๆต่ฏๅฅไปถ๏ผ็ๆ JSON/Markdown ๆฅๅ๏ผ
Bug ไฟฎๅค
- ไฟฎๅค TagGroup ๆน้ๅๅ ฅๅคฑ่ดฅ้ฎ้ข
ๆฐๅขๅ่ฝ
- ๆทปๅ cpppo ๆๅกๅจๅ ผๅฎนๆงๆฏๆ๏ผLogix Class 2 ๅฏน่ฑกๆ ็ญพ่ฎฟ้ฎ๏ผ
- ๆฐๅข
ReadClass2Attributeๆนๆณ
ๆฐๅขๅ่ฝ
- ๆทปๅ ่ฟๆฅๆฑ ๆฏๆ๏ผEIPTCPPool๏ผ
- ๆทปๅ ็ผๅฒๅบๆฑ ๅไผๅ
- ๆฏๆ UDT๏ผ็จๆทๅฎไน็ฑปๅ๏ผ
ๅๅง็ๆฌ
- ๅบ็ก TCP ่ฟๆฅ็ฎก็
- Tag ่ฏปๅๆไฝ
- ๆฏๆๅบๆฌๆฐๆฎ็ฑปๅ๏ผBOOL, INT, DINT, REAL, STRING ็ญ๏ผ
- ๆถๆฏ่ทฏ็ฑๅจๅฎ็ฐ
ๆฌ้กน็ฎ้็จ WTFPL ่ฎธๅฏ่ฏใ
ๆฌข่ฟๆไบค Issue ๅ Pull Request๏ผ