นี่คือ gensio (ออกเสียงว่า gen'-see-oh) ซึ่งเป็นเฟรมเวิร์กสำหรับการให้มุมมองที่สอดคล้องกันของประเภท I/O สตรีม (และแพ็กเก็ต) ต่างๆ คุณสร้างวัตถุ Gensio (หรือ Gensio) และคุณสามารถใช้ Gensio นั้นได้โดยไม่ต้องรู้มากเกินไปเกี่ยวกับสิ่งที่เกิดขึ้นข้างใต้ คุณสามารถซ้อน Gensio ทับอีกอันหนึ่งเพื่อเพิ่มฟังก์ชันโปรโตคอลได้ ตัวอย่างเช่น คุณสามารถสร้าง TCP gensio, สแต็ก SSL ที่ด้านบน และสแต็ก Telnet ที่ด้านบนได้ รองรับ I/O เครือข่ายและพอร์ตอนุกรมจำนวนหนึ่ง นอกจากนี้ยังรองรับอินเทอร์เฟซเสียง อัจฉริยะที่ซ้อนกันบนอัจฉริยะอื่นๆ เรียกว่าตัวกรอง
คุณสามารถทำสิ่งเดียวกันกับพอร์ตรับ คุณสามารถตั้งค่าตัวรับ Gensio เพื่อยอมรับการเชื่อมต่อในสแต็กได้ ในตัวอย่างก่อนหน้านี้ คุณสามารถตั้งค่า TCP ให้ฟังบนพอร์ตเฉพาะและซ้อน SSL และ Telnet ไว้ด้านบนโดยอัตโนมัติเมื่อมีการเชื่อมต่อเข้ามา และคุณจะไม่ได้รับแจ้งจนกว่าทุกอย่างจะพร้อม
gensio ทำงานบน Linux, BSD, MacOS และ Windows บน Windows จะให้อินเทอร์เฟซที่ขับเคลื่อนด้วยเหตุการณ์ที่มีความสามารถแบบเธรดเดียว (แต่มีความสามารถแบบมัลติเธรดด้วย) (พร้อมอินเทอร์เฟซที่บล็อกได้) เพื่อลดความซับซ้อนในการเขียนโปรแกรมด้วย I/O จำนวนมาก ช่วยให้การเขียนโค้ดที่ขับเคลื่อนด้วย I/O แบบพกพาเป็นเรื่องง่าย
คุณลักษณะที่สำคัญ มาก ของ gensio คือทำให้การสร้างการเชื่อมต่อที่เข้ารหัสและรับรองความถูกต้องง่ายกว่าการไม่มีเลย นอกเหนือจากการจัดการคีย์ขั้นพื้นฐานแล้ว จริงๆ แล้วก็ไม่ได้ยากกว่า TCP หรืออย่างอื่นเลย โดยให้ความยืดหยุ่นเพิ่มเติมในการควบคุมกระบวนการตรวจสอบความถูกต้อง หากจำเป็น มันใช้งานง่ายมาก
โปรดทราบว่าหน้า man page gensio(5) มีรายละเอียดเพิ่มเติมเกี่ยวกับประเภท Gensio แต่ละรายการ
สำหรับคำแนะนำในการสร้างสิ่งนี้จากแหล่งที่มา โปรดดูส่วน "การสร้าง" ในตอนท้าย
มีเครื่องมือสองสามอย่างที่ใช้ gensios ทั้งเป็นตัวอย่างและสำหรับการทดลองใช้ เหล่านี้คือ:
daemon ที่มีลักษณะคล้าย sshd ที่ใช้ certauth, ssl และ SCTP หรือ TCP gensios สำหรับการเชื่อมต่อ ใช้การรับรองความถูกต้อง PAM มาตรฐานและใช้ ptys ดู gtlsshd(8) สำหรับรายละเอียด
มีรายการใน FAQ.rst ชื่อ "วิธีเรียกใช้ gtlsshd บน Windows" โปรดดูรายละเอียดเพิ่มเติมที่ส่วนการสร้างบน Windows ด้านล่าง เนื่องจากมีเรื่องยุ่งยากบางประการที่คุณต้องจัดการ
อัจฉริยะต่อไปนี้มีอยู่ในห้องสมุด:
ตัวรับ Gensio ที่ใช้สตริงสแต็ก Gensio เป็นพารามิเตอร์ สิ่งนี้ช่วยให้คุณใช้ gensio เป็นตัวรับได้ เมื่อ conacc เริ่มต้นขึ้น gensio จะเปิดขึ้น และเมื่อ gensio เปิดขึ้นจะรายงานลูกใหม่ให้กับผู้รับ เมื่อลูกปิดมันจะพยายามเปิดลูกอีกครั้งและทำตามขั้นตอนอีกครั้ง (เว้นแต่ว่าการยอมรับจะถูกปิดใช้งานใน conacc)
ทำไมคุณถึงต้องการใช้สิ่งนี้? พูดใน ser2net คุณต้องการเชื่อมต่อพอร์ตอนุกรมหนึ่งพอร์ตเข้ากับอีกพอร์ตหนึ่ง คุณสามารถมีการเชื่อมต่อเช่น:
connection : &con0
accepter : conacc,serialdev,/dev/ttyS1,115200
connector : serialdev,/dev/ttyS2,115200
และมันจะเชื่อมต่อ /dev/ttyS1 กับ /dev/ttyS2 หากไม่มี conacc คุณจะไม่สามารถใช้ serialdev เป็นตัวรับได้ นอกจากนี้ยังช่วยให้คุณใช้ gtlsshd บนพอร์ตอนุกรมได้หากคุณต้องการการเข้าสู่ระบบที่ผ่านการตรวจสอบสิทธิ์แบบเข้ารหัสผ่านพอร์ตอนุกรม หากคุณรัน gtlsshd ด้วยสิ่งต่อไปนี้:
gtlsshd --notcp --nosctp --oneshot --nodaemon --other_acc
' conacc,relpkt(mode=server),msgdelim,/dev/ttyUSB1,115200n81 '
คุณสามารถเชื่อมต่อกับ:
gtlssh --transport ' relpkt,msgdelim,/dev/ttyUSB2,115200n81 ' USB2
สิ่งนี้จะสร้างการขนส่งแพ็กเก็ตที่เชื่อถือได้ผ่านพอร์ตอนุกรม จำเป็นต้องใช้ mode=server เพื่อให้ relpkt ทำงานเป็นเซิร์ฟเวอร์ เนื่องจากโดยปกติแล้วจะรันเป็นไคลเอ็นต์เนื่องจากไม่ได้เริ่มทำงานในฐานะตัวรับ ssl gensio (ซึ่งทำงานผ่านการขนส่ง) ต้องการการสื่อสารที่เชื่อถือได้ ดังนั้นจึงจะไม่ทำงานผ่านพอร์ตอนุกรมโดยตรง
ใช่ มันดูเหมือนตัวอักษรที่สับสนวุ่นวาย
Gensio ตัวกรองที่อยู่ด้านบนของ Gensio เสียง และใช้โมเด็ม Audio Frequency Shift Keying เช่นเดียวกับที่ใช้ในวิทยุสมัครเล่น AX.25
โปรโตคอลวิทยุสมัครเล่นสำหรับวิทยุแพ็คเก็ต หากต้องการใช้สิ่งนี้อย่างเต็มที่ คุณจะต้องเขียนโค้ด เนื่องจากมันใช้ช่องทางและข้อมูล oob สำหรับข้อมูลที่ไม่มีหมายเลข แต่คุณสามารถทำสิ่งพื้นฐานได้ด้วย gensiot หากคุณต้องการเพียงช่องทางการสื่อสารเดียว ตัวอย่างเช่น หากคุณต้องการสนทนากับใครสักคนทางวิทยุ และพอร์ต kiss อยู่ที่ 8001 บนทั้งสองเครื่อง บนเครื่องที่ตอบรับ คุณสามารถเรียกใช้:
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),kiss,conacc,tcp,localhost,8001 '
ซึ่งจะเชื่อมต่อกับ TNC และรอการเชื่อมต่อตามที่อยู่ AE5KM-1 จากนั้นคุณสามารถวิ่งได้:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"),kiss,tcp,localhost,8001 '
บนเครื่องอื่น สิ่งนี้จะเชื่อมต่อกับเครื่องอื่นบน TNC 0 ด้วยที่อยู่ที่ระบุ จากนั้นสิ่งที่คุณพิมพ์รายการหนึ่งจะปรากฏบนอีกรายการหนึ่งทีละบรรทัด พิมพ์ "Ctrl-D" เพื่อออก ส่วน 'stdio(self)' จะปิดโหมด Raw ดังนั้นจึงเป็นทีละบรรทัดและคุณจะได้รับเสียงสะท้อนในเครื่อง มิฉะนั้นอักขระทุกตัวที่คุณพิมพ์จะส่งแพ็กเก็ตและคุณจะไม่เห็นว่าคุณกำลังพิมพ์อะไร
หากต้องการเชื่อมต่อกับระบบ BBS N5COR-11 AX.25 คุณจะต้องทำดังนี้
gensiot -i ' xlt(nlcr),stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,N5COR-11,AE5KM-2"),kiss,tcp,localhost,8001 '
ระบบ BBS ส่วนใหญ่ใช้ CR ไม่ใช่ NL สำหรับบรรทัดใหม่ ดังนั้นจึงใช้ xlt gensio เพื่อแปลอักขระที่เข้ามาเหล่านี้
แน่นอนว่านี่คือ gensio คุณสามารถใส่ gensio ใดๆ ที่ใช้งานได้ไว้ข้างใต้ ax25 ที่คุณต้องการได้ ดังนั้นหากคุณต้องการเล่นหรือทดสอบโดยไม่มีวิทยุ คุณสามารถทำ ax25 บน UDP multicast ได้ นี่คือด้านผู้รับ:
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),conacc, '
' udp(mcast="ipv4,224.0.0.20",laddr="ipv4,1234",nocon), '
' ipv4,224.0.0.20,1234 '
และนี่คือด้านตัวเชื่อมต่อ:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"), '
' udp(mcast="ipv4,224.0.0.20",laddr="ipv4,1234",nocon), '
' ipv4,224.0.0.20,1234 '
ไม่จำเป็นต้องใช้ kiss เนื่องจาก UDP เป็นสื่อที่เน้นแพ็คเก็ตอยู่แล้ว หรือคุณสามารถใช้โปรแกรม greflector เพื่อสร้างสถานการณ์วิทยุจำลองได้ บนเครื่อง "radiopi2" ให้รัน:
greflector kiss,tcp,1234
ซึ่งจะสร้างโปรแกรมที่จะสะท้อนอินพุตที่ได้รับทั้งหมดไปยังการเชื่อมต่ออื่น ๆ ทั้งหมด จากนั้นในด้านตัวรับ:
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),kiss,conacc,tcp,radiopi2,1234 '
และด้านเชื่อมต่อ:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"),kiss,tcp,radiopi2,1234 '
รหัสทดสอบใช้ตัวสะท้อนแสงสำหรับการทดสอบบางอย่าง เนื่องจากสะดวกในการใช้งานมาก
ทั้งหมดนี้ได้รับการบันทึกไว้โดยละเอียดใน gensio(5) สิ่งเหล่านี้ทั้งหมดมีอยู่ในฐานะตัวรับหรือการเชื่อมต่ออัจฉริยะ เว้นแต่จะระบุไว้เป็นอย่างอื่น
คุณสามารถสร้างอัจฉริยะของคุณเองและลงทะเบียนกับห้องสมุดและนำมารวมกับอัจฉริยะอื่นๆ ได้
วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการขโมยโค้ดจาก Gensio ที่ทำสิ่งที่คุณต้องการ จากนั้นแก้ไขเพื่อสร้าง Gensio ของคุณเอง น่าเสียดายที่ไม่มีเอกสารที่ดีเกี่ยวกับวิธีการทำเช่นนี้
ไฟล์ include include/gensio/gensio_class.h มีอินเทอร์เฟซระหว่างไลบรารี gensio หลักและ gensio การเรียก gensio ทั้งหมดมาผ่านฟังก์ชันเดียวพร้อมตัวเลขเพื่อระบุฟังก์ชันที่ต้องการ คุณต้องแมปสิ่งเหล่านี้กับการดำเนินการจริง สิ่งนี้ค่อนข้างเจ็บปวด แต่ทำให้ความเข้ากันได้ของการส่งต่อและย้อนหลังง่ายขึ้นมาก
การสร้างอัจฉริยะของคุณเองด้วยวิธีนี้ค่อนข้างซับซ้อน สถานะของเครื่องจักรสำหรับสิ่งนี้อาจซับซ้อนอย่างน่าประหลาดใจ การล้างข้อมูลเป็นส่วนที่ยากที่สุด คุณต้องตรวจสอบให้แน่ใจว่าคุณขาดการติดต่อกลับทั้งหมด และไม่มีการเรียกตัวจับเวลากลับมาในสภาพการแข่งขันเมื่อปิดเครื่อง เฉพาะ gensios ที่ง่ายที่สุด (echo, dummy), gensios แปลก ๆ (conadd, Keepopen, stdio) และ gensios ที่มีช่องทาง (mux, ax25) เท่านั้นที่ใช้อินเทอร์เฟซโดยตรง ทุกอย่างอื่นใช้ include/gensio/gensio_base.h gensio_base จัดเตรียมเครื่องสถานะพื้นฐานสำหรับ gensio มีส่วนกรอง (ซึ่งเป็นทางเลือก) และส่วนระดับต่ำ (ll) ซึ่งไม่มี
อินเทอร์เฟซตัวกรองมีข้อมูลวิ่งผ่านเพื่อการประมวลผล สิ่งนี้ใช้สำหรับสิ่งต่าง ๆ เช่น ssl, certauth, ratelimit ฯลฯ gensios ตัวกรองจะใช้สิ่งนี้ ทั้งหมดนี้ใช้ gensio_ll_gensio (สำหรับการซ้อน gensio ไว้บน gensio อื่น) สำหรับ ll
Terminal gensios แต่ละตัวจะมี ll เป็นของตัวเอง และโดยทั่วไปจะไม่มีตัวกรอง สำหรับ lls ที่ใช้ file descriptor (fd) จะใช้ gensio_ll_fd นอกจากนี้ยังมี ll สำหรับ IPMI serial-over-lan (ipmisol) และเสียง gensios เทอร์มินัลส่วนใหญ่ (tcp, udp, sctp, พอร์ตอนุกรม, pty) ใช้ fd ll อย่างเห็นได้ชัด
เมื่อคุณมี gensio แล้ว คุณสามารถคอมไพล์มันเป็นโมดูลและติดมันไว้ใน $(moduleinstalldir)/<version> จากนั้น gensio ก็จะหยิบมันขึ้นมาและใช้มัน คุณยังสามารถลิงก์เข้ากับแอปพลิเคชันของคุณและทำฟังก์ชัน init จากแอปพลิเคชันของคุณได้
มีการพูดคุยถึง mdns gensio แล้ว แต่ไลบรารี gensio มีอินเทอร์เฟซ mDNS ที่ใช้งานง่าย ไฟล์รวมของมันอยู่ใน gensio_mdns.h และคุณสามารถใช้ man page ของ gensio_mdns(3) เพื่อรับข้อมูลเพิ่มเติมได้
หากต้องการเชื่อมต่อ mdns โดยใช้ gensiot สมมติว่าคุณได้ตั้งค่า ser2net โดยเปิดใช้งาน mdns เช่น:
connection : &my-port
accepter : telnet(rfc2217),tcp,3001
connector : serialdev,/dev/ttyUSB1,115200N81
options :
mdns : true
จากนั้นคุณสามารถเชื่อมต่อกับมันด้วย gensiot:
gensiot ' mdns,my-port '
gensiot จะค้นหาเซิร์ฟเวอร์ พอร์ต และดูว่าเปิดใช้งาน telnet และ rfc2217 แล้วทำการเชื่อมต่อหรือไม่
นอกจากนี้ยังมีเครื่องมือ gmdns ที่ให้คุณสืบค้นและโฆษณาได้ และ gtlssh ก็สามารถทำการสืบค้น mDNS เพื่อค้นหาบริการต่างๆ ได้ หากคุณมีการเข้าสู่ระบบรับรองความถูกต้องที่ปลอดภัยสำหรับ ser2net และคุณเปิดใช้งาน mdns บน ser2net เช่น:
connection : &access-console
accepter : telnet(rfc2217),mux,certauth(),ssl,tcp,3001
connector : serialdev,/dev/ttyUSBaccess,115200N81
options :
mdns : true
มันทำให้การตั้งค่าสะดวกมาก เพราะคุณสามารถทำได้:
gtlssh -m access-console
ถูกต้อง คุณสามารถใช้ชื่อการเชื่อมต่อได้โดยตรง โดยไม่จำเป็นต้องทราบโฮสต์ ไม่ว่าจะเปิดใช้งาน telnet หรือ rfc2217 หรือไม่ หรือพอร์ตคืออะไร คุณยังคงต้องตั้งค่าคีย์และอื่นๆ บนเซิร์ฟเวอร์ ser2net ตามคำแนะนำเหล่านั้น
gensio มีอินเทอร์เฟซเชิงวัตถุที่ขับเคลื่อนด้วยเหตุการณ์ อินเทอร์เฟซแบบซิงโครนัสก็มีให้เช่นกัน คุณจัดการกับวัตถุหลักสองประการใน gensio: gensio และตัวรับ gensio gensio มีอินเทอร์เฟซการสื่อสารที่คุณสามารถเชื่อมต่อ ยกเลิกการเชื่อมต่อ เขียน รับ ฯลฯ
ตัวรับ gensio ช่วยให้คุณรับการเชื่อมต่อขาเข้า หากมีการเชื่อมต่อเข้ามา จะทำให้คุณมีความอัจฉริยะ
อินเทอร์เฟซเป็นไปตามเหตุการณ์ เนื่องจากโดยส่วนใหญ่แล้วไม่มีการบล็อกโดยสิ้นเชิง หากคุณเปิด gensio คุณจะโทรกลับซึ่งจะถูกเรียกเมื่อการเชื่อมต่อหมดลงหรือการเชื่อมต่อล้มเหลว เหมือนกันครับปิดครับ. การเขียนจะส่งคืนจำนวนไบต์ที่ยอมรับ แต่อาจไม่ต้องใช้ไบต์ทั้งหมด (หรือแม้แต่ไบต์ใดๆ ก็ตาม) และผู้เรียกจะต้องคำนึงถึงสิ่งนั้น
อินเทอร์เฟซแบบเปิดและปิดมีอินเทอร์เฟซการบล็อกรองเพื่อความสะดวก เหล่านี้ลงท้ายด้วย _s นี่เป็นเพื่อความสะดวก แต่ไม่จำเป็น และการใช้สิ่งเหล่านี้ต้องระมัดระวังเพราะคุณไม่สามารถใช้งานได้จริงจากการโทรกลับ
การพูดถึงการโทรกลับ ข้อมูลและข้อมูลที่มาจาก gensio ถึงผู้ใช้นั้นทำได้ด้วยการเรียกกลับด้วยฟังก์ชัน อ่านข้อมูล และเมื่อ gensio พร้อมสำหรับการเขียนข้อมูลจะกลับมาในการเรียกกลับ อินเทอร์เฟซที่คล้ายกันใช้สำหรับการโทรจากผู้ใช้ไปยังเลเยอร์ gensio แต่จะถูกซ่อนไม่ให้ผู้ใช้เห็น อินเทอร์เฟซประเภทนี้สามารถขยายได้ง่าย สามารถเพิ่มการดำเนินการใหม่ ๆ ได้อย่างง่ายดายโดยไม่ทำให้อินเทอร์เฟซเก่าเสียหาย
ไลบรารีมีหลายวิธีในการสร้างตัวรับ gensio หรือ gensio วิธีหลักคือ str_to_gensio() และ str_to_gensio_accepter() สิ่งเหล่านี้เป็นวิธีในการระบุสแต็กของ gensios หรือตัวรับเป็นสตริงและบิลด์ โดยทั่วไป คุณควรใช้อินเทอร์เฟซนี้หากทำได้
โดยทั่วไป อินเทอร์เฟซที่ไม่คำนึงถึงประสิทธิภาพการทำงานจะขึ้นอยู่กับสตริง คุณจะเห็นสิ่งนี้ใน gensio_control และในข้อมูลเสริมในส่วนต่อประสานการอ่านและเขียนเพื่อควบคุมลักษณะบางอย่างของการเขียน
ห้องสมุดยังมีวิธีตั้งค่าอัจฉริยะของคุณด้วยการสร้างแต่ละอันแยกกัน ในบางสถานการณ์อาจจำเป็น แต่จะจำกัดความสามารถในการใช้คุณสมบัติใหม่ของไลบรารี gensio เมื่อมีการขยายออกไป
หาก gensio รองรับหลายสตรีม (เช่น SCTP) หมายเลขสตรีมจะถูกส่งผ่านใน auxdata ด้วย "stream=n" สตรีมไม่ได้ถูกควบคุมการไหลเป็นรายบุคคล
ในทางกลับกัน ช่องสัญญาณเป็นกระแสข้อมูลที่แยกจากกันผ่านการเชื่อมต่อเดียวกัน ช่องสัญญาณจะแสดงเป็นอัจฉริยะที่แยกจากกัน และสามารถควบคุมการไหลแยกกันได้
มีไฟล์รวมบางไฟล์ที่คุณอาจต้องจัดการเมื่อใช้ gensios:
สิ่งเหล่านี้ส่วนใหญ่จะมีการบันทึกไว้ใน man page
สำหรับการสร้างอัจฉริยะของคุณเอง ไฟล์รวมต่อไปนี้จะพร้อมให้คุณใช้งาน:
แต่ละไฟล์รวมมีเอกสารจำนวนมากเกี่ยวกับการเรียกและตัวจัดการแต่ละรายการ
gensio มีชุดข้อผิดพลาดของตัวเองเพื่อสรุปข้อผิดพลาดของระบบปฏิบัติการ (ชื่อ GE_xxx) และให้ความยืดหยุ่นมากขึ้นในการรายงานข้อผิดพลาด สิ่งเหล่านี้อยู่ในไฟล์รวม gensio_err.h (รวมโดยอัตโนมัติจาก gensio.h) และอาจแปลจากตัวเลขเป็นสตริงที่มีความหมายด้วย gensio_err_to_str() ศูนย์ถูกกำหนดให้ไม่ใช่ข้อผิดพลาด
หากเกิดข้อผิดพลาดของระบบปฏิบัติการที่ไม่รู้จัก ระบบจะส่งคืน GE_OSERR และบันทึกจะถูกรายงานผ่านอินเทอร์เฟซบันทึกของตัวจัดการ OS
สิ่งที่น่ารำคาญเล็กน้อยเกี่ยวกับ gensio คือคุณต้องจัดเตรียมตัวจัดการ OS (struct gensio_os_funcs) เพื่อจัดการฟังก์ชันประเภท OS เช่น การจัดสรรหน่วยความจำ mutexes ความสามารถในการจัดการตัวอธิบายไฟล์ ตัวจับเวลาและเวลา และอื่นๆ อีกสองสามอย่าง
ไลบรารีมีตัวจัดการระบบปฏิบัติการหลายตัว คุณสามารถเรียก gensio_alloc_os_funcs() เพื่อจัดสรรค่าเริ่มต้นสำหรับระบบของคุณ (POSIX หรือ Windows) คุณสามารถดูหน้าคนนั้นเพื่อดูรายละเอียดเพิ่มเติม โดยทั่วไปนี่จะเป็นตัวเลือกที่มีประสิทธิภาพดีที่สุดที่คุณมีสำหรับระบบของคุณ
สำหรับระบบ POSIX ตัวจัดการ OS สำหรับ glib และ TCL พร้อมใช้งาน โดยจัดสรรด้วย gensio_glib_funcs_alloc() และ gensio_tcl_funcs_alloc() สิ่งเหล่านี้ทำงานได้ไม่ดีนัก โดยเฉพาะจากมุมมองของประสิทธิภาพ API สำหรับ glib และ TCL ไม่ได้รับการออกแบบมาอย่างดีสำหรับสิ่งที่ gensio ทำ TCL สามารถรองรับการทำงานแบบเธรดเดียวเท่านั้น การดำเนินการแบบมัลติเธรด glib จะมีเพียงเธรดเดียวในแต่ละครั้งที่กำลังรอ I/O แต่พวกเขาใช้งานได้และทำการทดสอบร่วมกับพวกเขา สิ่งเหล่านี้ไม่มีให้บริการบน Windows เนื่องจากนามธรรมที่ไม่ดีเกี่ยวกับ glib และเนื่องจาก TCL ขาดแรงจูงใจ
แต่ถ้าคุณใช้อย่างอื่น เช่น X Windows ฯลฯ ที่มี event loop ของตัวเอง คุณอาจต้องปรับให้เข้ากับความต้องการของคุณ แต่ข้อดีคือคุณสามารถทำเช่นนี้ได้ และรวม Gensio เข้ากับอะไรก็ได้เกือบหมด
นอกจากนี้ยังมีอินเทอร์เฟซตัวรอที่ให้วิธีที่สะดวกในการรอให้สิ่งต่าง ๆ เกิดขึ้นขณะรันลูปเหตุการณ์ นี่คือวิธีที่คุณเข้าสู่ลูปเหตุการณ์โดยทั่วไป เนื่องจากเป็นวิธีที่สะดวกในการส่งสัญญาณเมื่อคุณทำเสร็จแล้วและจำเป็นต้องออกจากลูป
เอกสารประกอบสำหรับสิ่งนี้อยู่ใน:
รวม/gensio/gensio_os_funcs.h
ไลบรารี gensio รองรับเธรดอย่างสมบูรณ์และปลอดภัยสำหรับเธรดโดยสมบูรณ์ อย่างไรก็ตาม จะใช้สัญญาณบนระบบ POSIX และ COM บนระบบ Windows ดังนั้นจึงจำเป็นต้องมีการตั้งค่าบางอย่าง
เธรด "main" ควรเรียก gensio_os_proc_setup() เมื่อเริ่มต้นระบบ และเรียก gensio_os_proc_cleanup() เมื่อเสร็จสมบูรณ์ สิ่งนี้จะตั้งค่าสัญญาณและตัวจัดการสัญญาณ เธรดที่จัดเก็บในเครื่อง Windows และสิ่งต่าง ๆ
คุณสามารถวางไข่เธรดใหม่จากเธรดที่ตั้งค่าไว้แล้วโดยใช้ gensio_os_new_thread() สิ่งนี้จะให้เธรด OS พื้นฐานแก่คุณและได้รับการกำหนดค่าอย่างเหมาะสมสำหรับ gensio
หากคุณมีเธรดที่สร้างขึ้นโดยวิธีอื่นที่คุณต้องการใช้ใน gensio ตราบใดที่เธรดนั้นสร้างเธรดอื่นและไม่ทำหน้าที่บล็อกใด ๆ (การรอใด ๆ การประมวลผลเบื้องหลัง ฟังก์ชันที่ลงท้ายด้วย _s เช่น read_s ฯลฯ) คุณไม่จำเป็นต้องตั้งค่ามัน ด้วยวิธีนี้ เธรดภายนอกบางเธรดสามารถเขียนข้อมูล ปลุกเธรดอื่น หรือทำสิ่งต่างๆ เช่นนั้นได้
หากเธรดภายนอกจำเป็นต้องทำสิ่งเหล่านั้น ควรเรียก gensio_os_thread_setup()
ตามที่กล่าวไว้ในส่วนเธรด ไลบรารี gensio บน Unix จะใช้สัญญาณสำหรับการปลุกระหว่างเธรด ฉันดูอย่างหนักและไม่มีทางอื่นใดที่จะทำเช่นนี้ได้อย่างหมดจด แต่ Windows ก็มีสิ่งคล้ายสัญญาณอยู่สองสามอย่างเช่นกัน และสิ่งเหล่านี้ก็มีอยู่ใน gensio เช่นกัน
หากคุณใช้ gensio_alloc_os_funcs() คุณจะได้รับ OS func โดยใช้สัญญาณที่ส่งผ่านสำหรับ IPC คุณสามารถส่งผ่านเป็น GENSIO_OS_FUNCS_DEFAULT_THREAD_SIGNAL สำหรับสัญญาณได้หากคุณต้องการค่าเริ่มต้นซึ่งก็คือ SIGUSR1 สัญญาณที่คุณใช้จะถูกบล็อกและถูกควบคุมโดย gensio คุณไม่สามารถใช้งานได้
gensio ยังมีการจัดการทั่วไปสำหรับสัญญาณบางอย่างอีกด้วย บน Unix มันจะจัดการ SIGHUP ผ่านฟังก์ชัน gensio_os_proc_register_reload_handler()
บน Windows และ Unix คุณสามารถใช้ gensio_os_proce_register_term_handler() ซึ่งจะจัดการคำขอยุติ (SIGINT, SIGTERM, SIGQUIT บน Unix) และ gensio_os_proc_register_winsize_handler() (SIGWINCH บน Unix) สิ่งเหล่านี้เข้ามาทาง Windows ได้อย่างไรนั้นเลอะเทอะเล็กน้อย แต่ผู้ใช้จะมองไม่เห็น
การเรียกกลับทั้งหมดจากการรอของรูทีนการรอ ไม่ใช่ จากตัวจัดการสัญญาณ นั่นจะทำให้ชีวิตของคุณง่ายขึ้นมาก
คุณสามารถดู man page เพื่อดูรายละเอียดเพิ่มเติมเกี่ยวกับสิ่งเหล่านี้ได้
หากต้องการสร้าง gensio วิธีทั่วไปในการทำเช่นนี้คือการเรียก str_to_gensio()
ด้วยสตริงที่มีรูปแบบถูกต้อง สตริงมีรูปแบบดังนี้:
<ประเภท>[([<ตัวเลือก>[,<ตัวเลือก[...]]])][,<ประเภท>...][,<สิ้นสุดตัวเลือก>[,<สิ้นสุดตัวเลือก>]]
end option
มีไว้สำหรับเทอร์มินัลอัจฉริยะหรือที่อยู่ด้านล่างสุดของสแต็ก ตัวอย่างเช่น tcp,localhost,3001
จะสร้าง gensio ที่เชื่อมต่อกับพอร์ต 3001 บน localhost สำหรับพอร์ตอนุกรม ตัวอย่างคือ serialdev,/dev/ttyS0,9600N81
จะสร้างการเชื่อมต่อกับพอร์ตอนุกรม /dev/ttyS0
ซึ่งจะทำให้คุณสามารถซ้อนเลเยอร์ Gensio ไว้บนเลเยอร์ Gensio ได้ ตัวอย่างเช่น หากต้องการวางเลเยอร์เทลเน็ตไว้ด้านบนของการเชื่อมต่อ TCP:
telnet,tcp,localhost,3001
สมมติว่าคุณต้องการเปิดใช้งาน RFC2217 บนการเชื่อมต่อเทลเน็ตของคุณ คุณสามารถเพิ่มตัวเลือกในการทำเช่นนั้นได้:
telnet(rfc2217=true),tcp,localhost,3001
เมื่อคุณสร้าง gensio คุณจะต้องให้ข้อมูลผู้ใช้โทรกลับ เมื่อเหตุการณ์เกิดขึ้นใน gensio การโทรกลับจะถูกเรียกเพื่อให้ผู้ใช้สามารถจัดการได้
ตัวรับ gensio นั้นคล้ายคลึงกับ gensio ที่เชื่อมต่อกัน แต่มี str_to_gensio_accepter()
แทน รูปแบบก็เหมือนกัน ตัวอย่างเช่น:
telnet(rfc2217=true),tcp,3001
จะสร้างตัวรับ TCP โดยมี telnet อยู่ด้านบน สำหรับตัวรับ โดยทั่วไปคุณไม่จำเป็นต้องระบุชื่อโฮสต์หากคุณต้องการเชื่อมโยงกับอินเทอร์เฟซทั้งหมดบนเครื่องท้องถิ่น
เมื่อคุณสร้าง gensio แล้ว gensio ยังไม่เปิดหรือดำเนินการ หากต้องการใช้งานคุณต้องเปิดมัน หากต้องการเปิด ให้ทำดังนี้
struct gensio * io ;
int rv ;
rv = str_to_gensio ( "tcp,localhost,3001" , oshnd ,
tcpcb , mydata , & io );
if ( rv ) { handle error }
rv = gensio_open ( io , tcp_open_done , mydata );
if ( rv ) { handle error }
โปรดทราบว่าเมื่อ gensio_open()
กลับมา gensio จะไม่เปิด คุณต้องรอจนกว่าจะมีการเรียกกลับ ( tcp_open_done()
ในกรณีนี้) หลังจากนั้นคุณก็สามารถใช้งานได้
เมื่อเปิด gensio คุณจะไม่ได้รับข้อมูลใดๆ ในทันทีเนื่องจากการรับปิดอยู่ คุณต้องเรียก gensio_set_read_callback_enable()
เพื่อเปิดและปิดว่าการโทรกลับ ( tcpcb
ในกรณีนี้) จะถูกเรียกเมื่อได้รับข้อมูลหรือไม่
เมื่อตัวจัดการการอ่านถูกเรียก บัฟเฟอร์และความยาวจะถูกส่งผ่านไป คุณไม่จำเป็นต้องจัดการข้อมูลทั้งหมดหากทำไม่ได้ คุณ ต้อง อัปเดต buflen ด้วยจำนวนไบต์ที่คุณจัดการจริง หากคุณไม่จัดการข้อมูล ข้อมูลที่ไม่ได้จัดการจะถูกบัฟเฟอร์ไว้ใน Gensio เพื่อใช้ในภายหลัง ไม่ใช่ว่าถ้าคุณไม่จัดการข้อมูลทั้งหมด คุณควรปิดการเปิดใช้งานการอ่าน ไม่เช่นนั้นเหตุการณ์จะถูกเรียกอีกครั้งทันที
หากมีสิ่งผิดปกติเกิดขึ้นกับการเชื่อมต่อ ตัวจัดการการอ่านจะถูกเรียกพร้อมกับชุดข้อผิดพลาด buf
และ buflen
จะเป็นโมฆะในกรณีนี้
สำหรับการเขียน คุณสามารถเรียก gensio_write()
เพื่อเขียนข้อมูลได้ คุณสามารถใช้ gensio_write()
ได้ตลอดเวลาบน gensio แบบเปิด gensio_write()
อาจไม่ได้ใช้ข้อมูลทั้งหมดที่คุณเขียนลงไป พารามิเตอร์ count
ส่งกลับจำนวนไบต์ที่ใช้จริงในการเรียกการเขียน
คุณสามารถออกแบบโค้ดของคุณให้เรียก gensio_set_write_callback_enable()
เมื่อคุณมีข้อมูลที่จะส่ง และ gensio จะเรียก callback ที่พร้อมเขียน และคุณสามารถเขียนจากการโทรกลับได้ โดยทั่วไปวิธีนี้ง่ายกว่า แต่การเปิดใช้งานและปิดใช้งานการเรียกกลับการเขียนจะเพิ่มค่าใช้จ่ายบางส่วน
วิธีที่มีประสิทธิภาพมากกว่าคือเขียนข้อมูลทุกครั้งที่คุณต้องการและปิดใช้งานการเขียนกลับ หากการดำเนินการเขียนส่งคืนน้อยกว่าคำขอทั้งหมด ปลายอีกด้านหนึ่งจะมีการควบคุมโฟลว์ และคุณควรเปิดใช้งานการเรียกกลับการเขียนและรอจนกว่าจะมีการเรียกก่อนที่จะส่งข้อมูลเพิ่มเติม
ในการเรียกกลับ คุณสามารถรับข้อมูลผู้ใช้ที่คุณส่งผ่านไปยังการเรียก create ด้วย gensio_get_user_data()
โปรดทราบว่าหากคุณเปิดแล้วปิด gensio ทันที ก็เป็นเรื่องปกติ แม้ว่าจะไม่มีการเรียกการโทรกลับแบบเปิดก็ตาม การโทรกลับแบบเปิดอาจจะหรืออาจจะไม่ถูกเรียกในกรณีนี้ ดังนั้นจึงอาจเป็นเรื่องยากในการจัดการอย่างถูกต้อง
คุณสามารถทำ I/O แบบซิงโครนัสพื้นฐานด้วย gensios ได้ สิ่งนี้มีประโยชน์ในบางสถานการณ์ที่คุณต้องอ่านบางอย่างในบรรทัด โดยโทร:
err = gensio_set_sync ( io );
gensio ที่กำหนดจะหยุดส่งกิจกรรมการอ่านและเขียน กิจกรรมอื่น ๆ จะ ถูกส่ง จากนั้นคุณก็สามารถทำได้:
err = gensio_read_s ( io , & count , data , datalen , & timeout );
err = gensio_write_s ( io , & count , data , datalen , & timeout );
การนับถูกกำหนดเป็นจำนวนไบต์ที่อ่าน/เขียนจริง อาจเป็นโมฆะหากคุณไม่สนใจ (แม้ว่าจะอ่านไม่สมเหตุสมผลก็ตาม)
การหมดเวลาอาจเป็นโมฆะ หากเป็นเช่นนั้น ให้รอตลอดไป หากคุณตั้งค่าการหมดเวลา ระบบจะอัปเดตตามระยะเวลาที่เหลือ
โปรดทราบว่าสัญญาณจะทำให้สัญญาณเหล่านี้กลับมาทันที แต่ไม่มีการรายงานข้อผิดพลาด
การอ่านจะบล็อกจนกว่าข้อมูลบางส่วนจะเข้ามาและส่งคืนข้อมูลนั้น มันไม่รอจนกว่าบัฟเฟอร์จะเต็ม การหมดเวลาคือช่วงเวลา การอ่านจะรอระยะเวลาดังกล่าวเพื่อให้การอ่านเสร็จสิ้นและส่งคืน การหมดเวลาไม่ใช่ข้อผิดพลาด การนับจะถูกตั้งค่าเป็นศูนย์
เขียนบล็อกจนกว่าจะเขียนบัฟเฟอร์ทั้งหมดหรือเกิดการหมดเวลา ขอย้ำอีกครั้งว่าการหมดเวลาไม่ใช่ข้อผิดพลาด จำนวนไบต์ทั้งหมดที่เขียนจริงจะถูกส่งกลับด้วยการนับ
เมื่อคุณทำซิงโครนัส I/O ด้วย gensio เสร็จแล้ว ให้โทร:
err = gensio_clear_sync ( io );
และการจัดส่งผ่านอินเทอร์เฟซกิจกรรมจะยังคงดำเนินต่อไปเช่นเดิม คุณต้องไม่อยู่ในการโทรอ่านหรือเขียนแบบซิงโครนัสเมื่อเรียกใช้สิ่งนี้ ผลลัพธ์จะไม่ถูกกำหนด
โปรดทราบว่า I/O อื่นๆ บน Gensios อื่นๆ จะยังคงเกิดขึ้นเมื่อรอ I/O แบบซิงโครนัส
ขณะนี้ยังไม่มีวิธีที่จะรอ Gensios หลายเครื่องที่มี I/O แบบซิงโครนัส หากคุณกำลังทำเช่นนั้น คุณควรใช้ I/O ที่ขับเคลื่อนด้วยเหตุการณ์จริงๆ มันมีประสิทธิภาพมากกว่า และท้ายที่สุดคุณก็จะทำแบบเดียวกันอยู่ดี
เช่นเดียวกับ gensio ตัวรับ gensio จะไม่ทำงานเมื่อคุณสร้างมันขึ้นมา คุณต้องเรียก gensio_acc_startup()
เพื่อเปิดใช้งาน:
struct gensio_accepter * acc ;
int rv ;
rv = str_to_gensio_accepter ( "tcp,3001" , oshnd ,
tcpacccb , mydata , & acc );
if ( rv ) { handle error }
rv = gensio_startup ( acc );
if ( rv ) { handle error }
โปรดทราบว่าไม่มีการเรียกกลับไปยังการเรียกเริ่มต้นเพื่อให้ทราบเมื่อเปิดใช้งาน เนื่องจากไม่จำเป็นต้องรู้จริงๆ เนื่องจากคุณไม่สามารถเขียนลงไปได้ แต่จะเป็นเพียงการเรียกกลับเท่านั้น
แม้ว่าคุณจะเริ่มต้น Accepter แล้ว มันก็จะไม่ทำอะไรจนกว่าคุณจะเรียก gensio_acc_set_accept_callback_enable()
เพื่อเปิดใช้งานการโทรกลับนั้น
เมื่อมีการเรียกการโทรกลับ จะทำให้คุณได้รับ gensio ในพารามิเตอร์ data
ที่เปิดอยู่แล้วโดยปิดใช้งานการอ่าน เกนซิโอที่ได้รับจากตัวรับเกนซิโออาจมีข้อจำกัดบางประการ ตัวอย่างเช่น คุณอาจไม่สามารถปิดแล้วเปิดใหม่ได้
ตัวรับ gensio สามารถยอมรับแบบซิงโครนัสได้โดยใช้ gensio_acc_set_sync()
และ gensio_acc_accept_s
ดูหน้าคู่มือสำหรับรายละเอียดเหล่านั้น
struct gensio_os_funcs
มีการโทรกลับ vlog สำหรับจัดการบันทึก gensio ภายใน สิ่งเหล่านี้เรียกว่าเมื่อมีบางสิ่งที่สำคัญเกิดขึ้น แต่ gensio ไม่มีทางที่จะรายงานข้อผิดพลาดได้ นอกจากนี้ยังอาจเรียกว่าช่วยให้วินิจฉัยปัญหาได้ง่ายขึ้นเมื่อมีข้อผิดพลาดเกิดขึ้น
คลาสตัวรับ gensio และ gensio แต่ละคลาสมีคลาสย่อยสำหรับจัดการ I/O แบบอนุกรม และการตั้งค่าพารามิเตอร์ทั้งหมดที่เกี่ยวข้องกับพอร์ตอนุกรม
คุณสามารถค้นพบได้ว่า gensio (หรือลูกๆ ของมัน) เป็นพอร์ตอนุกรมหรือไม่โดยการเรียก gensio_to_sergensio()
หากค่านั้นคืนค่า NULL แสดงว่าไม่ใช่ sergensio และไม่มีลูกใดที่เป็น sergensios หากส่งคืนค่าที่ไม่ใช่ NULL ก็จะส่งคืนวัตถุ sergensio เพื่อให้คุณใช้ โปรดทราบว่า gensio ที่ส่งคืนโดย sergensio_to_gensio()
จะเป็นอันที่ส่งผ่านไปยัง gensio_to_sergensio()
ไม่จำเป็นต้องเป็น gensio ที่ sergensio เกี่ยวข้องโดยตรง
Sergensio อาจเป็นไคลเอ็นต์ ซึ่งหมายความว่าสามารถตั้งค่าการตั้งค่าซีเรียลได้ หรืออาจเป็นเซิร์ฟเวอร์ ซึ่งหมายความว่าจะได้รับการตั้งค่าซีเรียลจากปลายอีกด้านหนึ่งของการเชื่อมต่อ
sergensios ส่วนใหญ่เป็นไคลเอนต์เท่านั้น: serialdev (พอร์ตอนุกรมปกติ), ipmisol และตัวรับ stdio ปัจจุบันมีเพียง telnet เท่านั้นที่มีความสามารถทั้งไคลเอ็นต์และเซิร์ฟเวอร์
หมายเหตุ: อินเทอร์เฟซหลามที่อธิบายไว้ที่นี่เลิกใช้แล้ว ใช้อันหนึ่งใน c++/swig/pygensio ทันที
คุณสามารถเข้าถึงอินเทอร์เฟซ gensio ทั้งหมดได้ผ่านทาง python แม้ว่าจะแตกต่างจากอินเทอร์เฟซ C เล็กน้อยก็ตาม
เนื่องจาก python เป็นแบบเชิงอ็อบเจ็กต์อย่างสมบูรณ์ ตัวรับ gensios และ gensio จึงเป็นอ็อบเจ็กต์ระดับเฟิร์สคลาส พร้อมด้วย gensio_os_funcs, sergensios และ waiters
นี่เป็นโปรแกรมขนาดเล็ก:
import gensio
class Logger :
def gensio_log ( self , level , log ):
print ( "***%s log: %s" % ( level , log ))
class GHandler :
def __init__ ( self , o , to_write ):
self . to_write = to_write
self . waiter = gensio . waiter ( o )
self . readlen = len ( to_write )
def read_callback ( self , io , err , buf , auxdata ):
if err :
print ( "Got error: " + err )
return 0
print ( "Got data: " + buf );
self . readlen -= len ( buf )
if self . readlen == 0 :
io . read_cb_enable ( False )
self . waiter . wake ()
return len ( buf )
def write_callback ( self , io ):
print ( "Write ready!" )
if self . to_write :
written = io . write ( self . to_write , None )
if ( written >= len ( self . to_write )):
self . to_write = None
io . write_cb_enable ( False )
else :
self . to_write = self . to_write [ written :]
else :
io . write_cb_enable ( False )
def open_done ( self , io , err ):
if err :
print ( "Open error: " + err );
self . waiter . wake ()
else :
print ( "Opened!" )
io . read_cb_enable ( True )
io . write_cb_enable ( True )
def wait ( self ):
self . waiter . wait_timeout ( 1 , 2000 )
o = gensio . alloc_gensio_selector ( Logger ())
h = GHandler ( o , "This is a test" )
g = gensio . gensio ( o , "telnet,tcp,localhost,2002" , h )
g . open ( h )
h . wait ()
อินเทอร์เฟซเป็นการแปลโดยตรงจากอินเทอร์เฟซ C การแสดงอินเทอร์เฟซของหลามอยู่ใน swig/python/gensiodoc.py คุณสามารถดูได้จากเอกสารประกอบ
อินเทอร์เฟซ C++ ได้รับการบันทึกไว้ใน c++/README.rst
อินเทอร์เฟซ pygensio ใหม่เป็นการใช้งานที่สะอาดยิ่งขึ้นโดยใช้ swig Director แทนการโทรกลับด้วยรหัสด้วยมือใน Python ดู README.rst ใน c++/swig/pygensio นอกจากนี้ยังมี glib และ tcl OS_Funcs ในไดเร็กทอรี glib และ tcl
อินเทอร์เฟซ C++ เต็มรูปแบบพร้อมใช้งานสำหรับโปรแกรม Go ผ่านทาง swig และ swig Director ดู c++/swig/go/README.rst สำหรับรายละเอียด
นี่เป็นระบบออโต้คอนฟปกติ ไม่มีอะไรพิเศษ โปรดทราบว่าหากคุณได้รับสิ่งนี้โดยตรงจาก git คุณจะไม่รวมโครงสร้างพื้นฐานของบิลด์ด้วย มีสคริปต์ชื่อ "reconf" ในไดเร็กทอรีหลักที่จะสร้างสคริปต์ให้กับคุณ
หากคุณไม่ทราบเกี่ยวกับ autoconf ไฟล์ INSTALL ก็มีข้อมูลบางอย่าง หรือไม่ก็ Google
หากต้องการสร้าง Gensio อย่างสมบูรณ์ คุณต้องมีสิ่งต่อไปนี้:
ต่อไปนี้จะตั้งค่าทุกอย่างยกเว้น openipmi บน Ubuntu 20.04:
- sudo apt ติดตั้ง gcc g++ git swig python3-dev libssl-dev pkg-config
- libavahi-client-dev avahi-daemon libtool autoconf อัตโนมัติทำให้ libsctp-dev libpam-dev libwrap0-dev libglib2.0-dev tcl-dev libasound2-dev libudev-dev
บน Redhat libwrap หายไป ดังนั้นคุณจะไม่ได้ใช้สิ่งนั้น และ swig ดูเหมือนจะไม่พร้อมใช้งาน ดังนั้นคุณจะต้องสร้างสิ่งนั้นด้วยตัวเองอย่างน้อยก็ go และรองรับ python นี่คือคำสั่งสำหรับระบบที่คล้ายกับ Redhat:
- sudo yum ติดตั้ง gcc gcc-c++ git python3-devel swig openssl-devel
- pkg-config avahi-devel libtool autoconf autoconf ทำให้ lksctp-tools-devel-devel-devel glib2-devel-devel-devel devel alsa-lib-devel devel-devel
คุณอาจต้องทำสิ่งต่อไปนี้เพื่อเปิดใช้งานการเข้าถึงแพ็คเกจการพัฒนา:
sudo dnf config-manager-Devel ที่เปิดใช้งานชุด
และรับโมดูลเคอร์เนล SCTP คุณอาจต้องทำ:
sudo yum ติดตั้งเคอร์เนลโมดูล-extra
ในการใช้ภาษา Go คุณต้องได้รับ Swig 4.1.0 หรือมากกว่า คุณอาจต้องดึงรุ่นเลือดออกจาก Git และใช้มัน
การจัดการการกำหนดค่าการติดตั้ง Python เป็นความเจ็บปวดเล็กน้อย โดยค่าเริ่มต้นสคริปต์บิลด์จะวางไว้ทุกที่ที่โปรแกรม Python คาดว่าจะมีโปรแกรม Python ที่ติดตั้ง โดยทั่วไปผู้ใช้ปกติไม่มีการเข้าถึงไดเรกทอรีนั้น
ในการแทนที่สิ่งนี้คุณสามารถใช้ตัวเลือกการกำหนดค่า-pythoninstall และ---with-pythoninstalllib ตัวเลือกการกำหนดค่าหรือคุณสามารถตั้งค่าตัวแปรสภาพแวดล้อม pythoninstalldir และ pythoninstalllibdir ไปยังที่ที่คุณต้องการให้ห้องสมุดและโมดูลไป
โปรดทราบว่าคุณอาจต้องตั้งค่า--with-uucp-locking ไปยัง lockdir ของคุณ (ในระบบเก่าคือ/var/lock ซึ่งเป็นค่าเริ่มต้นในที่ใหม่กว่าอาจเป็น/run/lock/lockdev คุณอาจต้องเป็น สมาชิกของ Dialout และกลุ่มล็อคเพื่อให้สามารถเปิดอุปกรณ์อนุกรมและ/หรือล็อคได้
การสนับสนุนภาษาไปต้องติดตั้งและอยู่ในเส้นทาง
ในขณะที่ฉันยังคงเพิ่ม Gensios ในห้องสมุดเช่น crypto, MDNS, เสียง, IPMI, SCTP ฯลฯ จำนวนการพึ่งพาในห้องสมุดไม่สามารถควบคุมได้ เหตุใดคุณจึงควรโหลด libasound หรือ libopenipmi ถ้าคุณไม่ต้องการ นอกจากนี้แม้ว่าไลบรารีรองรับการเพิ่ม gensios ของคุณเองผ่าน API โปรแกรม แต่ก็ไม่มีวิธีมาตรฐานในการเพิ่มพวกเขาสำหรับระบบเพื่อให้คุณสามารถเขียน Gensio ของคุณเองและให้ทุกคนในระบบใช้มัน
ห้องสมุด Gensio รองรับการโหลด Gensios แบบไดนามิกหรือสร้างขึ้นในห้องสมุด โดยค่าเริ่มต้นหากคุณสร้างไลบรารีที่ใช้ร่วมกัน Gensios ทั้งหมดจะถูกรวบรวมเป็นโมดูลสำหรับการโหลดแบบไดนามิกและติดตั้งในสถานที่ที่ทำให้เป็นไปได้ หากคุณไม่ได้สร้างห้องสมุดที่ใช้ร่วมกัน Gensios ทั้งหมดจะถูกสร้างขึ้นในห้องสมุด แต่คุณสามารถแทนที่พฤติกรรมนี้
ในการตั้งค่า Gensios ทั้งหมดที่จะสร้างขึ้นในไลบรารีคุณสามารถเพิ่ม "--with-all-gensios = ใช่" บนบรรทัดคำสั่ง configure และมันจะสร้างพวกเขาในไลบรารี
นอกจากนี้คุณยังสามารถตั้งค่าให้เป็นแบบไดนามิกทั้งหมดได้โดยการเพิ่ม "--with-all-gensios = dynamic" แต่นี่เป็นค่าเริ่มต้น
นอกจากนี้คุณยังสามารถปิดใช้งาน Gensios ทั้งหมดได้โดยค่าเริ่มต้นโดยระบุ "--with-all-gensios = no" จากนั้นจะไม่มีการสร้าง Gensios โดยค่าเริ่มต้น สิ่งนี้มีประโยชน์หากคุณต้องการเพียงไม่กี่ gensios คุณสามารถปิดพวกเขาทั้งหมดออกแล้วเปิดใช้งานแล้วสิ่งที่คุณต้องการ
ในการตั้งค่าวิธีการสร้าง gensios แต่ละตัวคุณจะทำ "--with- <gensio> = x" โดยที่ x คือ "ไม่ (ไม่สร้าง), ใช่ (สร้างเป็นไลบรารี) หรือไดนามิก (โหลดแบบไดนามิกแบบไดนามิก) ตัวอย่างเช่น หากคุณต้องการสร้าง TCP Gensio ลงในไลบรารีและสร้างแบบไดนามิกที่เหลือคุณสามารถตั้งค่าสำหรับ Gensios แบบไดนามิกทั้งหมดแล้วเพิ่ม "--with-net = ใช่"
โมดูลเหล่านี้จะถูกนำไปใช้โดยค่าเริ่มต้น
โปรดทราบว่าการโหลดแบบไดนามิกนั้นมีอยู่เสมอแม้ว่าคุณจะสร้าง Gensios ทั้งหมดในไลบรารี ดังนั้นคุณยังสามารถเพิ่ม gensios ของคุณเองโดยเพิ่มลงในไดเรกทอรีที่เหมาะสม
Gensios จะถูกโหลดก่อนจากตัวแปรสภาพแวดล้อม LD_LIBRARY_PATH จากนั้นจาก gensio_library_path จากนั้นจากตำแหน่งเริ่มต้น
macOS เป็น * nix ประเภทสร้างค่อนข้างสะอาดด้วย homebrew (https://brew.sh) แน่นอนคุณต้องติดตั้งไลบรารีทั้งหมดที่คุณต้องการ ทุกอย่างส่วนใหญ่ใช้งานได้โดยมีข้อยกเว้นดังต่อไปนี้:
* CM108GPIO * SCTP * การล็อค UUCP
รหัส DNSSD ในตัวใช้สำหรับ MDNS ดังนั้นจึงไม่จำเป็นต้องใช้ Avahi
การล็อคฝูงสำหรับพอร์ตอนุกรมจึงไม่จำเป็นต้องล็อค UUCP จริงๆ
Openipmi ควรใช้งานได้ แต่ไม่สามารถใช้งานได้ใน Homebrew ดังนั้นคุณจะต้องสร้างมันขึ้นมาเอง
ติดตั้งซอฟต์แวร์ที่จำเป็น:
- PKG ติดตั้ง gcc portaudio autoconf automake libtool mdnsresponder swig
- ไป Python3 gmake
คุณต้องใช้ GMake เพื่อรวบรวมด้วยเหตุผลบางอย่างที่มาตรฐาน Make บน BSD ไม่ยอมรับตัวแปร "C ++" ในรายการข้อกำหนด ต่อไปนี้ไม่ทำงานและไม่ได้รวบรวม:
* SCTP * ipmisol * CM108GPIO
เพิ่มสิ่งต่อไปนี้เป็น /etc/rc.conf:
mdnsd_enable = ใช่
และรีบูตหรือเริ่มบริการ
Pty Gensio ล้มเหลว Oomtest (Oomtest 14) ดูเหมือนว่าจะมีบางอย่างกับ BSD Ptys ฉันเห็นอักขระ 07 ที่แทรกเข้าไปในสตรีมข้อมูลในกรณี แม้ว่าฉันไม่ได้ใช้เวลามากเกินไป แต่เนื่องจากสิ่งนี้ได้รับการทดสอบอย่างหนักบน Linux และ MacOS ฉันไม่คิดว่าปัญหาจะอยู่ในรหัส Gensio
ห้องสมุด Gensio สามารถสร้างได้ภายใต้ Windows โดยใช้ MingW64 สิ่งต่อไปนี้ไม่ได้ผล:
* SCTP * แพม * libwrap * ipmisol
คุณไม่จำเป็นต้องติดตั้ง ALSA โดยใช้อินเทอร์เฟซเสียง Windows สำหรับเสียง
CM108GPIO ใช้อินเทอร์เฟซ Windows ดั้งเดิมดังนั้นจึงไม่จำเป็นต้องใช้ UDEV
ใช้อินเทอร์เฟซ MDNS ในตัวของ Windows ดังนั้นคุณไม่จำเป็นต้องใช้ Avahi หรือ DNSSD คุณจะต้องติดตั้งไลบรารี PCRE หากคุณต้องการนิพจน์ทั่วไป
คุณต้องได้รับ MSYS2 จาก https://msys2.org จากนั้นติดตั้ง autoconf, automake, libtool, git, make และ swig เป็นเครื่องมือโฮสต์:
Pacman -s autoconf automake libtool git make swig
คุณต้องติดตั้งรุ่น MINGW-W64-X86_64-XXX ของไลบรารีทั้งหมดหรือ MINGW-W64-I686-XXX เวอร์ชันของไลบรารีทั้งหมด 32 บิตไม่ได้ทดสอบอย่างดี:
Pacman -s mingw-w64-x86_64-gcc MINGW-W64-X86_64-PYTHON3 MINGW-W64-X86_64-PCRE mingw-w64-x86_64-openssl
สำหรับ MingW64 หรือสำหรับ UCRT64:
Pacman -s MingW-W64-UCRT-X86_64-GCC MINGW-W64-UCRT-X86_64-PYTHON3 MINGW-W64-UCRT-X86_64-PCRE MINGW-W64-UCRT-X86_64-OPENSSL
สำหรับ GO ให้ติดตั้งไปจาก https://go.dev และออกจากระบบและลงชื่อเข้าใช้มันควรจะอยู่ในเส้นทาง แต่ถ้าไม่ใช่คุณจะต้องเพิ่มลงในเส้นทาง ฉันไม่ได้ไปทำงานกับ MingW32 แต่ฉันไม่ได้ลอง GO เวอร์ชัน 32 บิต
สำหรับ GTLSSHD - -Sysconfdir ไม่มีความหมายบน Windows แทน sysconf dir นั้นสัมพันธ์กับแพตช์ของการดำเนินการใน ../etc/gtlssh ดังนั้นถ้า gtlsshd อยู่ใน:
C:/ไฟล์โปรแกรม/gensio/bin/gtlsshd
sysconfdir จะเป็น:
C:/ไฟล์โปรแกรม/gensio/etc/gtlssh
สำหรับการติดตั้งมาตรฐานคุณสามารถเรียกใช้:
../configure --sbindir =/gensio/bin -libexecdir =/gensio/bin --mandir =/gensio/man-includedir =/gensio/include -with-pythoninstall =/gensio/python3-prefix =/gensio
และเมื่อคุณเรียกใช้ "ทำให้การติดตั้ง destdir = ... " และคุณตั้งค่า destdir ให้เป็นที่ที่คุณต้องการให้มันไปเช่น "c:/ไฟล์โปรแกรม" จากนั้นคุณสามารถเพิ่มสิ่งนั้นลงในเส้นทางโดยใช้แผงควบคุม ในการใช้ GTLSSHD คุณสร้างไดเรกทอรี ETC/GTLSSHD ในไดเรกทอรี Gensio คุณต้องตั้งค่าสิทธิ์ในไดเรกทอรีนี้ดังนั้นระบบและผู้ดูแลระบบเท่านั้นที่สามารถเข้าถึงได้เช่น:
ps c: program files (x86) gensio etc> icacls gtlssh GTLSSH NT Authority System: (OI) (CI) (F) Builtin Administrators: (OI) (CI) (F)
มิฉะนั้น GTLSSHD จะล้มเหลวโดยมีข้อผิดพลาดเกี่ยวกับการอนุญาตในคีย์ คุณสามารถตั้งค่าการอนุญาตเหล่านี้ในไฟล์. key แทนไดเรกทอรี แต่คุณจะต้องตั้งค่าอีกครั้งทุกครั้งที่คุณสร้างคีย์ใหม่
สำหรับการใช้คอมไพเลอร์การตั้งค่า Inno ให้ทำ "ติดตั้ง destdir = $ home/install" จากนั้นเรียกใช้ Inno บน gensio.iss มันจะสร้างตัวติดตั้งที่ใช้งานได้สำหรับการติดตั้ง Gensio
จากนั้นคุณจะต้องลบไฟล์. la ออกจากไดเรกทอรีการติดตั้งเนื่องจากพวกเขาพยายามเชื่อมโยงกับสิ่งอื่น ๆ :
rm $ home/install/gensio/lib/*. la
มีการทดสอบจำนวนมากสำหรับ Gensios พวกเขาทั้งหมดทำงานบน Linux หากคุณมีโมดูลเคอร์เนล serialsim นอกเหนือจากพอร์ตอนุกรมพวกเขาทำงานบนแพลตฟอร์มอื่น ๆ เนื่องจาก Gensios รองรับบนแพลตฟอร์มนั้น
การทดสอบพอร์ตอนุกรมต้องใช้โมดูลเคอร์เนล Serialsim และอินเตอร์เฟส Python เหล่านี้อยู่ที่ https://github.com/cminyard/serialsim และอนุญาตให้การทดสอบใช้พอร์ตอนุกรมจำลองเพื่ออ่านสายควบคุมโมเด็มข้อผิดพลาดในการฉีด ฯลฯ
คุณสามารถผ่านไปได้โดยไม่ต้องทำ serialsim หากคุณมีอุปกรณ์อนุกรมสามตัว: หนึ่งติดตั้งในโหมด echo (RX และ TX ผูกติดกัน) และอุปกรณ์อนุกรมสองตัวเชื่อมต่อกัน I/O บนอุปกรณ์หนึ่งไป/มาจากที่อื่น สิ่งนี้ควรทำงานบนแพลตฟอร์มที่ไม่ใช่ Linux จากนั้นตั้งค่าตัวแปรสภาพแวดล้อมต่อไปนี้:
export GENSIO_TEST_PIPE_DEVS= " /dev/ttyxxx:/dev/ttywww "
export GENSIO_TEST_ECHO_DEV= " /dev/ttyzzz "
มันจะไม่สามารถทดสอบโมเด็มหรือ RS485
พวกเขายังต้องการโปรแกรม IPMI_SIM จาก OpenIPMI Library ที่ https://github.com/cminyard/openipmi เพื่อเรียกใช้การทดสอบ IPMISOL
ในการเรียกใช้การทดสอบคุณจะต้องเปิดใช้งานการดีบักภายในเพื่อให้ได้ผลเต็มรูปแบบ โดยทั่วไปคุณต้องการทำงานบางอย่างเช่น:
./configure --enable-internal-trace CFLAGS= ' -g -Wall '
คุณสามารถเปิด -o3 ใน cflags ได้เช่นกันถ้าคุณต้องการ แต่มันทำให้การดีบักยากขึ้น
มีการทดสอบพื้นฐานสองประเภท การทดสอบ Python เป็นการทดสอบการทำงานการทดสอบทั้งอินเตอร์เฟส Python และไลบรารี Gensio ขณะนี้พวกเขาโอเค แต่มีพื้นที่มากมายสำหรับการปรับปรุง หากคุณต้องการความช่วยเหลือคุณสามารถเขียนการทดสอบ
Oomtest เคยเป็นเครื่องทดสอบหน่วยความจำ แต่ได้ปรับเปลี่ยนเป็นสิ่งที่กว้างขวางกว่า มันวางไข่โปรแกรม gensiot ที่มีตัวแปรสภาพแวดล้อมเฉพาะเพื่อให้มันล้มเหลวในบางจุดและเพื่อทำการรั่วไหลของหน่วยความจำและการตรวจสอบหน่วยความจำอื่น ๆ มันเขียนข้อมูลไปยัง gensiot ผ่าน stdin และรับข้อมูลใน stdout การทดสอบบางอย่าง (เช่น Serialdev) ใช้เสียงสะท้อน การทดสอบอื่น ๆ ทำให้การเชื่อมต่อแยกต่างหากผ่านเครือข่ายและข้อมูลจะไหลเข้าสู่ stdin และกลับมาที่การเชื่อมต่อแยกต่างหากและไหลเข้าสู่การเชื่อมต่อแยกต่างหากและกลับมาผ่าน stdout Oomtest เป็นมัลติเธรดและจำนวนเธรดสามารถควบคุมได้ Oomtest พบข้อบกพร่องมากมาย มันมีลูกบิดจำนวนมาก แต่คุณต้องดูซอร์สโค้ดสำหรับตัวเลือก จำเป็นต้องได้รับการบันทึกไว้ถ้ามีคนต้องการเป็นอาสาสมัคร ...
หากต้องการตั้งค่าสำหรับการฟัซซิงให้ติดตั้ง AFL จากนั้นกำหนดค่าด้วยสิ่งต่อไปนี้:
mkdir Zfuzz ; cd Zfuzz
../configure --enable-internal-trace=yes --disable-shared --with-go=no
CC=afl-gcc CXX=afl-g++
หรือใช้ Clang ถ้ามี:
../configure --enable-internal-trace=yes --disable-shared --with-go=no
CC=afl-clang-fast CXX=afl-clang-fast++ LIBS= ' -lstdc++ '
ฉันไม่แน่ใจว่าทำไมสิ่งที่ LIBS ถึงมีความจำเป็นด้านบน แต่ฉันต้องเพิ่มมันเพื่อให้มันรวบรวม
จากนั้นสร้าง จากนั้น "การทดสอบซีดี" และเรียกใช้ "ทำให้ test_fuzz_xxx" โดยที่ xxx เป็นหนึ่งใน: certauth, mux, ssl, telnet หรือ relpkt คุณอาจต้องปรับบางสิ่งบางอย่าง AFL จะบอกคุณ โปรดทราบว่ามันจะทำงานตลอดไปคุณจะต้อง ^c เมื่อคุณทำเสร็จแล้ว
makefile ในการทดสอบ/makefile.am มีคำแนะนำเกี่ยวกับวิธีจัดการความล้มเหลวในการทำซ้ำสำหรับการดีบัก
การเรียกใช้รหัสการทำงานบนไลบรารีนั้นค่อนข้างง่าย ก่อนอื่นคุณต้องกำหนดค่ารหัสเพื่อเปิดใช้งานความครอบคลุม:
mkdir Ocov ; cd Ocov
../configure --enable-internal-trace=yes
CC= ' gcc -fprofile-arcs -ftest-coverage '
CXX= ' g++ -fprofile-arcs -ftest-coverage '
คอมไพล์และเรียกใช้ "ตรวจสอบ"
เพื่อสร้างรายงาน Run:
gcovr -f ' .*/.libs/.* ' -e ' .*python.* '
สิ่งนี้จะสร้างบทสรุป หากคุณต้องการเห็นความครอบคลุมของแต่ละบรรทัดในไฟล์คุณสามารถทำได้:
cd lib
gcov -o .libs/ * .o
คุณสามารถดูไฟล์. GCOV ที่สร้างขึ้นสำหรับข้อมูลเกี่ยวกับสิ่งที่ครอบคลุม ดูรายละเอียดเอกสาร GCOV
ในช่วงเวลาของการเขียนฉันได้รับการครอบคลุมรหัสประมาณ 74% ดังนั้นมันค่อนข้างดีจริงๆ ฉันจะทำงานเพื่อปรับปรุงสิ่งนั้นส่วนใหญ่ผ่านการทดสอบการทำงานที่ดีขึ้น
Ser2Net ใช้สำหรับการทดสอบบางสิ่งโดยหลักคือการกำหนดค่าพอร์ตอนุกรม (termios และ RFC2217) คุณสามารถสร้าง ser2net กับเวอร์ชัน GCOV ของไลบรารี Gensio และเรียกใช้ "Make Check" ใน Ser2Net เพื่อรับความคุ้มครองในส่วนเหล่านั้น ด้วยเหตุนี้ฉันจึงเห็นความครอบคลุมประมาณ 76% ดังนั้นจึงไม่ได้เพิ่มจำนวนมาก
คงจะดีไม่น้อยที่จะสามารถรวมสิ่งนี้เข้ากับฟัซซิ่งได้ แต่ฉันไม่แน่ใจว่าจะทำอย่างไร AFL เป็นสิ่งที่เป็นของตัวเองด้วยการครอบคลุมรหัส ดูเหมือนจะมีแพ็คเกจ AFL-COV ที่รวม GCOV แต่ฉันไม่ได้ดู