ใน C ฉันเข้าใจว่าถ้าเราปิดซ็อกเก็ตหมายความว่าซ็อกเก็ตจะถูกทำลายและสามารถนำกลับมาใช้ใหม่ได้ในภายหลัง
วิธีการปิดระบบ? คำอธิบายกล่าวว่าปิดครึ่งหนึ่งของการเชื่อมต่อเพล็กซ์กับซ็อกเก็ตนั้น แต่ซ็อกเก็ตนั้นจะถูกทำลายเหมือนการclose
เรียกของระบบหรือไม่
ใน C ฉันเข้าใจว่าถ้าเราปิดซ็อกเก็ตหมายความว่าซ็อกเก็ตจะถูกทำลายและสามารถนำกลับมาใช้ใหม่ได้ในภายหลัง
วิธีการปิดระบบ? คำอธิบายกล่าวว่าปิดครึ่งหนึ่งของการเชื่อมต่อเพล็กซ์กับซ็อกเก็ตนั้น แต่ซ็อกเก็ตนั้นจะถูกทำลายเหมือนการclose
เรียกของระบบหรือไม่
คำตอบ:
นี่คือคำอธิบายในคู่มือเครือข่ายของ Beej shutdown
เป็นวิธีที่ยืดหยุ่นในการบล็อกการสื่อสารในทิศทางเดียวหรือทั้งสอง เมื่อพารามิเตอร์ที่สองคือSHUT_RDWR
มันจะบล็อกทั้งการส่งและรับ (เช่นclose
) อย่างไรก็ตามclose
เป็นวิธีการทำลายซ็อกเก็ตจริง
ด้วยshutdown
คุณจะยังสามารถรับข้อมูลที่อยู่ระหว่างดำเนินการที่เพียร์ส่งไปแล้วได้ด้วย (ขอบคุณ Joey Adams สำหรับการสังเกตสิ่งนี้)
shutdown
ทั้งสองทิศทาง แต่ไม่close
คือถ้าคุณทำอ้างอิงถึงซ็อกเก็ตที่ใช้FILE
fdopen
หากคุณclose
ซ็อกเก็ตไฟล์ที่เพิ่งเปิดใหม่สามารถกำหนด fd เดียวกันและการใช้ในภายหลังFILE
จะอ่าน / เขียนสถานที่ผิดซึ่งอาจไม่ดีมาก หากคุณเพียงแค่shutdown
ใช้งานในภายหลังFILE
จะเพียงแค่ให้ข้อผิดพลาดจนกว่าfclose
จะมีการเรียก
shutdown
: เพื่อส่งสัญญาณ EOF ไปยังเพียร์และยังสามารถรับข้อมูลที่ค้างอยู่ที่เพียร์ส่ง
ไม่มีคำตอบใดที่บอกวิธีshutdown
และclose
ทำงานในระดับโปรโตคอล TCP ดังนั้นจึงควรเพิ่มสิ่งนี้
การเชื่อมต่อ TCP มาตรฐานสิ้นสุดลงด้วยการสรุป 4 ทาง:
อย่างไรก็ตามมีวิธี "ฉุกเฉิน" อีกวิธีหนึ่งในการปิดการเชื่อมต่อ TCP:
ในการทดสอบของฉันกับ Wireshark ด้วยตัวเลือกซ็อกเก็ตเริ่มต้นshutdown
ส่งแพ็กเก็ต FIN ไปยังปลายอีกด้านหนึ่ง แต่มันคือทั้งหมดที่มันทำ จนกว่าอีกฝ่ายจะส่งแพ็คเก็ต FIN ให้คุณคุณก็ยังสามารถรับข้อมูลได้ เมื่อสิ่งนี้เกิดขึ้นคุณReceive
จะได้ผลลัพธ์ขนาด 0 ดังนั้นหากคุณเป็นคนแรกที่ปิด "ส่ง" คุณควรปิดซ็อกเก็ตเมื่อคุณได้รับข้อมูลเสร็จแล้ว
ในทางกลับกันถ้าคุณโทร close
ในขณะที่การเชื่อมต่อยังคงทำงานอยู่ (อีกด้านหนึ่งยังคงทำงานอยู่และคุณอาจมีข้อมูลที่ไม่ได้ส่งในบัฟเฟอร์ของระบบเช่นกัน) แพ็คเก็ต RST จะถูกส่งไปอีกด้านหนึ่ง สิ่งนี้ดีสำหรับข้อผิดพลาด ตัวอย่างเช่นหากคุณคิดว่าอีกฝ่ายให้ข้อมูลที่ไม่ถูกต้องหรือปฏิเสธที่จะให้ข้อมูล (โจมตี DOS หรือไม่) คุณสามารถปิดซ็อกเก็ตได้ทันที
ความคิดเห็นของฉันของกฎจะเป็น:
shutdown
ก่อนclose
เมื่อเป็นไปได้การใช้งานในอุดมคติสำหรับ SHUT_RD และ SHUT_WR
สิ่งต่อไปนี้ยังไม่ได้ผ่านการทดสอบเชื่อมั่นในความเสี่ยงของคุณเอง อย่างไรก็ตามฉันเชื่อว่านี่เป็นวิธีที่สมเหตุสมผลและใช้งานได้จริงในการทำสิ่งต่าง ๆ
หากสแต็ก TCP ได้รับการปิดด้วย SHUT_RD เท่านั้นมันจะทำเครื่องหมายการเชื่อมต่อนี้เป็นข้อมูลที่ไม่คาดหวัง read
คำขอที่รอดำเนินการและอื่น ๆ ที่ตามมา(ไม่ว่าจะมีเธรดใดก็ตามที่อยู่ในนั้น) จะถูกส่งกลับพร้อมผลลัพธ์ขนาดศูนย์ อย่างไรก็ตามการเชื่อมต่อยังคงเปิดใช้งานและใช้งานได้ - คุณยังสามารถรับข้อมูล OOB ได้ นอกจากนี้ระบบปฏิบัติการจะปล่อยข้อมูลใด ๆ ที่ได้รับสำหรับการเชื่อมต่อนี้ แต่นั่นคือทั้งหมดจะไม่มีการส่งแพคเกจไปยังอีกด้านหนึ่ง
หากสแต็ก TCP ได้รับการปิดด้วย SHUT_WR เท่านั้นมันจะทำเครื่องหมายการเชื่อมต่อนี้ว่าจะไม่มีการส่งข้อมูลอีก การร้องขอการเขียนที่ค้างอยู่ทั้งหมดจะเสร็จสิ้น แต่การร้องขอการเขียนที่ตามมาจะล้มเหลว นอกจากนี้แพ็คเก็ต FIN จะถูกส่งไปยังอีกฝั่งหนึ่งเพื่อแจ้งให้ทราบว่าเราไม่มีข้อมูลเพิ่มเติมที่จะส่ง
shutdown()
เชื่อมต่อและจากนั้นจะไม่มีชีวิตอีกต่อไป คุณยังมีไฟล์ descriptor อยู่ คุณยังคงสามารถrecv()
รับบัฟเฟอร์ได้ และคุณยังจำเป็นต้องโทรติดต่อclose()
เพื่อทิ้งไฟล์ descriptor
มีข้อ จำกัด บางประการclose()
ที่สามารถหลีกเลี่ยงได้หากใช้shutdown()
แทน
close()
จะยุติทั้งสองทิศทางในการเชื่อมต่อ TCP บางครั้งคุณต้องการบอกจุดสิ้นสุดอื่น ๆ ว่าคุณเสร็จสิ้นการส่งข้อมูลแล้ว แต่ยังต้องการรับข้อมูล
close()
ลดจำนวนการอ้างอิง descriptors (เก็บรักษาไว้ในรายการตารางไฟล์และนับจำนวน descriptors ที่เปิดในขณะนี้ที่อ้างถึงไฟล์ / ซ็อกเก็ต) และไม่ปิดซ็อกเก็ต / ไฟล์หาก descriptor ไม่ใช่ 0 ซึ่งหมายความว่าถ้าคุณกำลังฟอร์ก การล้างข้อมูลจะเกิดขึ้นหลังจากการนับการอ้างอิงลดลงถึง 0 โดยshutdown()
สามารถเริ่มต้นลำดับการปิด TCP ปกติโดยไม่สนใจการนับการอ้างอิง
พารามิเตอร์มีดังนี้:
int shutdown(int s, int how); // s is socket descriptor
int how
เป็นไปได้:
SHUT_RD
หรือ0
ไม่อนุญาตให้รับเพิ่มเติม
SHUT_WR
หรือ1
ไม่อนุญาตให้ส่งเพิ่มเติม
SHUT_RDWR
หรือ2
ไม่อนุญาตให้ส่งและรับเพิ่มเติม
นี่อาจเป็นแพลตฟอร์มเฉพาะฉันสงสัยอย่างใด แต่ต่อไปคำอธิบายที่ดีที่สุดที่ฉันเคยเห็นอยู่ที่นี่ในหน้า msdn นี้ซึ่งพวกเขาอธิบายเกี่ยวกับการปิดตัวเลือกอิทธิพลการปิดซ็อกเก็ตและลำดับการยกเลิกการเชื่อมต่อทั่วไป
โดยสรุปให้ใช้การปิดระบบเพื่อส่งลำดับการปิดเครื่องที่ระดับ TCP และใช้การปิดเพื่อเพิ่มทรัพยากรที่ใช้โดยโครงสร้างข้อมูลซ็อกเก็ตในกระบวนการของคุณ หากคุณยังไม่ได้รับลำดับการปิดที่ชัดเจนตามเวลาที่คุณโทรเข้าจะมีการเริ่มต้นลำดับหนึ่งให้กับคุณ
ฉันยังประสบความสำเร็จภายใต้ linux ที่ใช้shutdown()
จาก pthread หนึ่งเพื่อบังคับให้ pthread อื่นที่บล็อกในปัจจุบันconnect()
ยกเลิกก่อนกำหนด
ภายใต้ระบบปฏิบัติการอื่น (อย่างน้อย OSX) ฉันพบว่าการโทรclose()
นั้นเพียงพอที่จะทำให้ระบบconnect()
ล้มเหลว
"shutdown () ไม่ได้ปิดตัวอธิบายไฟล์ - เพียงแค่เปลี่ยนการใช้งานของมันในการเพิ่มตัวแสดงรายละเอียดซ็อกเก็ตคุณต้องใช้ close ()" 1
ปิด
เมื่อคุณใช้ซ็อกเก็ตเสร็จแล้วคุณสามารถปิดไฟล์ descriptor พร้อมกับปิด หากยังมีข้อมูลรอการส่งผ่านการเชื่อมต่อโดยปกติแล้วจะพยายามปิดการส่งข้อมูลนี้ให้เสร็จ คุณสามารถควบคุมพฤติกรรมนี้ได้โดยใช้ตัวเลือกซ็อกเก็ต SO_LINGER เพื่อระบุระยะหมดเวลา ดูตัวเลือกซ็อกเก็ต
ปิดตัวลง
คุณยังสามารถปิดการรับหรือส่งสัญญาณผ่านการเชื่อมต่อโดยการปิดการโทร
ฟังก์ชั่นปิดเครื่องจะปิดการเชื่อมต่อของซ็อกเก็ต อาร์กิวเมนต์เป็นวิธีระบุการดำเนินการที่จะดำเนินการ: 0 หยุดรับข้อมูลสำหรับซ็อกเก็ตนี้ หากข้อมูลเพิ่มเติมมาถึงให้ปฏิเสธ 1 หยุดพยายามส่งข้อมูลจากซ็อกเก็ตนี้ ยกเลิกข้อมูลใด ๆ ที่รอส่ง หยุดค้นหาการตอบรับข้อมูลที่ส่งไปแล้ว อย่าส่งใหม่หากสูญหาย 2 หยุดการรับและส่งสัญญาณ
ค่าส่งคืนคือ 0 เมื่อสำเร็จและ -1 เมื่อล้มเหลว
ในการทดสอบของฉัน
close
จะส่งแพ็คเก็ตครีบและทำลาย fd ทันทีเมื่อซ็อกเก็ตไม่ได้ใช้ร่วมกับกระบวนการอื่น ๆ
shutdown
SHUT_RDกระบวนการยังคงสามารถรับข้อมูลจากซ็อกเก็ตได้ แต่recv
จะส่งคืนค่า 0 หากบัฟเฟอร์ TCP ว่างเปล่าหลังจากเพียร์ส่งข้อมูลเพิ่มเติมrecv
จะส่งคืนข้อมูลอีกครั้ง
shutdown
SHUT_WRจะส่งแพ็คเก็ตครีบเพื่อระบุว่าการส่งเพิ่มเติมนั้นไม่ได้รับอนุญาต เพียร์สามารถ recv ข้อมูล แต่มันจะ recv 0 ถ้าบัฟเฟอร์ TCP ของมันว่างเปล่า
shutdown
SHUT_RDWR (เท่ากับใช้ทั้งSHUT_RDและSHUT_WR ) จะส่งแพ็กเก็ต rst ถ้าเพื่อนส่งข้อมูลเพิ่มเติม
close()
ส่ง RST บน Linux แทน FIN
recv()
จะส่งคืนข้อมูลอีกครั้ง' ไม่ถูกต้อง 2. พฤติกรรมหากเพื่อนส่งข้อมูลมากขึ้นหลังจากSHUT_RD
นั้นขึ้นอยู่กับแพลตฟอร์ม