java.net.SocketException: รีเซ็ตการเชื่อมต่อ


129

ฉันได้รับข้อผิดพลาดต่อไปนี้พยายามอ่านจากซ็อกเก็ต ฉันทำreadInt()ในที่InputStreamและฉันได้รับข้อผิดพลาดนี้ การอ่านเอกสารนี้แสดงให้เห็นว่าส่วนไคลเอ็นต์ของการเชื่อมต่อปิดการเชื่อมต่อ ในสถานการณ์นี้ฉันเป็นเซิร์ฟเวอร์

ฉันสามารถเข้าถึงไฟล์บันทึกของไคลเอ็นต์และไม่ได้ปิดการเชื่อมต่อและในความเป็นจริงไฟล์บันทึกของมันแนะนำให้ฉันปิดการเชื่อมต่อ ใครมีความคิดว่าทำไมถึงเกิดขึ้น? ต้องตรวจสอบอะไรอีก? สิ่งนี้เกิดขึ้นเมื่อมีทรัพยากรในท้องถิ่นที่อาจถึงเกณฑ์หรือไม่?


ฉันทราบว่าฉันมีบรรทัดต่อไปนี้:

socket.setSoTimeout(10000);

ก่อนหน้าไฟล์readInt(). มีเหตุผลสำหรับเรื่องนี้ (เรื่องยาว) แต่แค่อยากรู้ว่ามีสถานการณ์ที่อาจนำไปสู่ข้อผิดพลาดที่ระบุไว้หรือไม่? ฉันมีเซิร์ฟเวอร์ที่ทำงานใน IDE ของฉันและฉันบังเอิญปล่อยให้ IDE ของฉันติดอยู่บนเบรกพอยต์จากนั้นฉันก็สังเกตเห็นข้อผิดพลาดเดียวกันทั้งหมดเริ่มปรากฏในบันทึกของฉันเองใน IDE ของฉัน

อย่างไรก็ตามเพียงแค่พูดถึงมันหวังว่าจะไม่ใช่ปลาเฮอริ่งแดง :-(


คุณมีสแต็กเทรซจากทั้งสองด้านหรือไม่? คุณช่วยอธิบายสถาปัตยกรรมเครือข่ายอีกเล็กน้อยได้ไหม (ผ่านอินเทอร์เน็ตบนเครื่องเดียวกันหรือไม่ที่ไหนสักแห่งในระหว่างนั้น) มันเกิดขึ้นตลอดเวลาหรือไม่? หรือไม่ต่อเนื่อง?
Stu Thompson

คำตอบ:


117

มีสาเหตุหลายประการ

  1. ปลายอีกด้านหนึ่งจงใจรีเซ็ตการเชื่อมต่อซึ่งฉันจะไม่บันทึกไว้ที่นี่ เป็นเรื่องที่หายากและโดยทั่วไปไม่ถูกต้องสำหรับซอฟต์แวร์แอปพลิเคชันในการทำเช่นนี้ แต่ซอฟต์แวร์เชิงพาณิชย์ไม่เป็นที่รู้จัก

  2. โดยทั่วไปมักเกิดจากการเขียนไปยังการเชื่อมต่อที่ปลายอีกด้านหนึ่งปิดไปแล้วตามปกติ กล่าวอีกนัยหนึ่งคือข้อผิดพลาดของโปรโตคอลแอปพลิเคชัน

  3. นอกจากนี้ยังอาจเกิดจากการปิดซ็อกเก็ตเมื่อมีข้อมูลที่ยังไม่ได้อ่านในบัฟเฟอร์การรับซ็อกเก็ต

  4. ใน Windows 'ซอฟต์แวร์ทำให้การเชื่อมต่อถูกยกเลิก' ซึ่งไม่เหมือนกับ 'การรีเซ็ตการเชื่อมต่อ' เกิดจากปัญหาเครือข่ายที่ส่งจากปลายทางของคุณ มีบทความฐานความรู้ของ Microsoft เกี่ยวกับเรื่องนี้


@MattLyons ขอบคุณ มีบทความ MSDN ที่ดีกว่านั้นมาก ตรงไปตรงมาฉันพบว่ามันยากที่จะเชื่อ การเชื่อมต่อจะไม่มีอยู่จนกว่าจะมีการสร้างที่อยู่ IP ต้นทางและเป้าหมายที่ถูกต้อง บทความ MSDN ที่ฉันเห็นอ้างถึงข้อผิดพลาดของเครือข่ายแบบถาวรหมดเวลาการเชื่อมต่อ
Marquis of Lorne

49

การรีเซ็ตการเชื่อมต่อหมายความว่าได้รับ TCP RST แล้ว เหตุการณ์นี้เกิดขึ้นเมื่อเพื่อนของคุณได้รับข้อมูลที่ไม่สามารถประมวลผลได้และอาจมีสาเหตุหลายประการ

วิธีที่ง่ายที่สุดคือเมื่อคุณปิดซ็อกเก็ตจากนั้นเขียนข้อมูลเพิ่มเติมในสตรีมเอาต์พุต การปิดซ็อกเก็ตจะเป็นการบอกเพื่อนของคุณว่าคุณพูดเสร็จแล้วและอาจลืมการเชื่อมต่อของคุณได้ เมื่อคุณส่งข้อมูลเพิ่มเติมในสตรีมนั้นเพียร์จะปฏิเสธด้วย RST เพื่อแจ้งให้คุณทราบว่าไม่ได้รับฟัง

ในกรณีอื่นไฟร์วอลล์ที่แทรกแซงหรือแม้แต่โฮสต์ระยะไกลเองอาจ "ลืม" เกี่ยวกับการเชื่อมต่อ TCP ของคุณ กรณีนี้อาจเกิดขึ้นได้หากคุณไม่ได้ส่งข้อมูลใด ๆ เป็นเวลานาน (2 ชั่วโมงเป็นช่วงหมดเวลาทั่วไป) หรือเนื่องจากเครื่องเพียร์ถูกรีบูตและสูญเสียข้อมูลเกี่ยวกับการเชื่อมต่อที่ใช้งานอยู่ การส่งข้อมูลบนหนึ่งในการเชื่อมต่อที่ไม่ทำงานเหล่านี้จะทำให้เกิด RST เช่นกัน


อัปเดตตามข้อมูลเพิ่มเติม:

ดูการจัดการไฟล์SocketTimeoutException. ข้อยกเว้นนี้จะเพิ่มขึ้นหากเกินระยะหมดเวลาที่กำหนดไว้ในขณะที่บล็อกการทำงานของซ็อกเก็ต สถานะของซ็อกเก็ตเองจะไม่เปลี่ยนแปลงเมื่อมีการทิ้งข้อยกเว้นนี้ แต่ถ้าตัวจัดการข้อยกเว้นของคุณปิดซ็อกเก็ตแล้วพยายามเขียนลงไปคุณจะอยู่ในเงื่อนไขการรีเซ็ตการเชื่อมต่อ setSoTimeout()มีขึ้นเพื่อให้คุณมีวิธีที่สะอาดในการแยกออกจากการread()ทำงานที่อาจปิดกั้นตลอดไปโดยไม่ทำสิ่งสกปรกเช่นการปิดซ็อกเก็ตจากเธรดอื่น


ไม่ถูกต้องหลายประการ การรวบรวมขยะและการออกจากกระบวนการทำให้เกิดการปิดอย่างเหมาะสมไม่ใช่การรีเซ็ต แต่การปิดตามด้วยการเขียนโดยเพื่อนอาจทำให้เกิดการรีเซ็ตได้มากกว่า EOS SocketTimeoutExceptions จะเพิ่มขึ้นก็ต่อเมื่อผู้อ่านตั้งค่าระยะหมดเวลาการอ่าน
Marquis of Lorne

และไม่ได้หมายความว่าได้รับ RST เสมอไป นอกจากนี้ยังสามารถหมายถึงหนึ่งถูกสร้างขึ้นโดยด้านนี้
Marquis of Lorne

17

เมื่อใดก็ตามที่ฉันมีปัญหาแปลก ๆ เช่นนี้ฉันมักจะนั่งลงกับเครื่องมือเช่นWireSharkและดูข้อมูลดิบที่ส่งผ่านไปมา คุณอาจแปลกใจที่มีการตัดการเชื่อมต่อและคุณจะได้รับการแจ้งเตือนเมื่อคุณพยายามอ่านเท่านั้น


10

คุณควรตรวจสอบร่องรอยทั้งหมดอย่างระมัดระวัง

ฉันมีแอปพลิเคชันซ็อกเก็ตเซิร์ฟเวอร์และแก้ไขjava.net.SocketException: Connection resetกรณี

ในกรณีของฉันมันเกิดขึ้นขณะอ่านจากSocketอ็อบเจ็กต์clientSocket ซึ่งปิดการเชื่อมต่อเนื่องจากเหตุผลบางประการ (เครือข่ายสูญหายไฟร์วอลล์หรือแอปพลิเคชันขัดข้องหรือตั้งใจปิด)

อันที่จริงฉันกำลังสร้างการเชื่อมต่อใหม่เมื่อฉันได้รับข้อผิดพลาดขณะอ่านจากวัตถุ Socket นี้

Socket clientSocket = ServerSocket.accept();
is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int readed = is.read(); // WHERE ERROR STARTS !!!

สิ่งที่น่าสนใจคือfor my JAVA Socketถ้าไคลเอนต์เชื่อมต่อกับฉันServerSocketและปิดการเชื่อมต่อโดยไม่ต้องส่งอะไรis.read()เรียกตัวเองซ้ำดูเหมือนว่าเป็นเพราะอยู่ในช่วงที่ไม่มีที่สิ้นสุดในขณะที่วนลูปสำหรับการอ่านจากซ็อกเก็ตนี้คุณพยายามอ่านจากการเชื่อมต่อแบบปิด หากคุณใช้สิ่งที่ต้องการด้านล่างสำหรับการอ่าน

while(true)
{
  Receive();
}

จากนั้นคุณจะได้รับ stackTrace บางอย่างเช่นด้านล่างและบน

java.net.SocketException: Socket is closed
    at java.net.ServerSocket.accept(ServerSocket.java:494)

สิ่งที่ฉันทำก็แค่ปิด ServerSocket และต่ออายุการเชื่อมต่อและรอการเชื่อมต่อไคลเอนต์ขาเข้าเพิ่มเติม

String Receive() throws Exception
{
try {                   
            int readed = is.read();
           ....
}catch(Exception e)
{
        tryReConnect();
        logit(); //etc
}


//...
}

สิ่งนี้สร้างการเชื่อมต่อของฉันใหม่สำหรับซ็อกเก็ตไคลเอนต์ที่ไม่รู้จักหายไป

private void tryReConnect()
        {
            try
            {
                ServerSocket.close();
                //empty my old lost connection and let it get by garbage col. immediately 
                clientSocket=null;
                System.gc();
                //Wait a new client Socket connection and address this to my local variable
                clientSocket= ServerSocket.accept(); // Waiting for another Connection
                System.out.println("Connection established...");
            }catch (Exception e) {
                String message="ReConnect not successful "+e.getMessage();
                logit();//etc...
            }
        }

ฉันหาวิธีอื่นไม่ได้เพราะอย่างที่คุณเห็นจากภาพด้านล่างคุณไม่สามารถเข้าใจได้ว่าการเชื่อมต่อขาดหายหรือไม่หากไม่มี A try and catchเพราะทุกอย่างดูเหมือนจะถูกต้อง ฉันได้สแนปชอตนี้ในขณะที่ฉันได้รับConnection resetอย่างต่อเนื่อง

ใส่คำอธิบายภาพที่นี่


9

น่าอายที่จะพูด แต่เมื่อฉันมีปัญหานี้มันเป็นความผิดพลาดที่ฉันปิดการเชื่อมต่อก่อนที่จะอ่านข้อมูลทั้งหมด ในกรณีที่มีการส่งคืนสตริงขนาดเล็กมันใช้งานได้ แต่นั่นอาจเป็นเพราะการตอบสนองทั้งหมดถูกบัฟเฟอร์ก่อนที่ฉันจะปิดมัน

ในกรณีที่มีการส่งคืนข้อความจำนวนมากขึ้นข้อยกเว้นจะถูกส่งกลับเนื่องจากบัฟเฟอร์จึงกลับมามากขึ้น

คุณอาจตรวจสอบการกำกับดูแลนี้ จำไว้ว่าการเปิด URL ก็เหมือนไฟล์อย่าลืมปิด (ปล่อยการเชื่อมต่อ) เมื่ออ่านเสร็จแล้ว


6

ฉันมีข้อผิดพลาดเดียวกัน ฉันพบวิธีแก้ปัญหาแล้ว ปัญหาคือโปรแกรมไคลเอ็นต์เสร็จสิ้นก่อนที่เซิร์ฟเวอร์จะอ่านสตรีม


นั่นจะไม่ทำให้เกิดข้อยกเว้นนี้ด้วยตัวมันเอง
Marquis of Lorne

มันจะเกิดขึ้นถ้า System.exit (0) ฆ่าโปรแกรมและไม่มีใครเรียก socket.close () เนื่องจากการเชื่อมต่ออยู่ในสถานะไม่ดีและไม่ได้ปิดอย่างถูกต้อง ถูกต้องมากขึ้นกล่าวว่าเขามีโปรแกรมไคลเอนต์ที่ปิดโดยไม่ต้องปิดซ็อกเก็ต;) ซึ่งเป็นสิ่งที่ไม่ดีและควรได้รับการแก้ไข
Dean Hiller

1
@DeanHiller ไม่มันจะไม่ ระบบปฏิบัติการจะปิดซ็อกเก็ตในลักษณะเดียวกับที่แอปพลิเคชันควรมี
Marquis of Lorne

@EJP .... ฉันไม่แน่ใจ ... ฉันเพิ่งรู้ว่าเราสามารถทำซ้ำได้ด้วย System.exit แต่ฉันจำ OS / config ไม่ได้เพราะเมื่อครู่แล้ว .... เรียก socket.close ( ) บนเซิร์ฟเวอร์ป้องกันไม่ให้รีเซ็ตการเชื่อมต่อและทำงานได้ถูกต้องมากขึ้น
Dean Hiller

2
@DeanHiller กระบวนการอ่านออกก่อนที่กระบวนการเขียนจะเขียนเสร็จ
Marquis of Lorne

4

ฉันมีปัญหากับระบบ SOA ที่เขียนด้วย Java ฉันใช้งานทั้งไคลเอนต์และเซิร์ฟเวอร์บนเครื่องทางกายภาพที่แตกต่างกันและทำงานได้ดีเป็นเวลานานจากนั้นการรีเซ็ตการเชื่อมต่อที่น่ารังเกียจเหล่านั้นก็ปรากฏในบันทึกไคลเอ็นต์และไม่มีอะไรแปลก ๆ ในบันทึกของเซิร์ฟเวอร์ การรีสตาร์ททั้งไคลเอนต์และเซิร์ฟเวอร์ไม่สามารถแก้ปัญหาได้ ในที่สุดเราก็ค้นพบว่าฮีปบนฝั่งเซิร์ฟเวอร์ค่อนข้างเต็มดังนั้นเราจึงเพิ่มหน่วยความจำที่มีให้สำหรับ JVM: ปัญหาได้รับการแก้ไขแล้ว! โปรดทราบว่าไม่มี OutOfMemoryError ในบันทึก: หน่วยความจำนั้นหายากและยังไม่หมด


2

ตรวจสอบเวอร์ชัน Java ของเซิร์ฟเวอร์ของคุณ เกิดขึ้นกับฉันเพราะ Weblogic 10.3.6 ของฉันอยู่บน JDK 1.7.0_75 ซึ่งอยู่บน TLSv1 จุดสิ้นสุดที่เหลือที่ฉันพยายามใช้คือการปิดสิ่งใดก็ตามที่อยู่ต่ำกว่า TLSv1.2

ตามค่าเริ่มต้น Weblogic พยายามเจรจาโปรโตคอลที่ใช้ร่วมกันที่แข็งแกร่งที่สุด ดูรายละเอียดที่นี่: ปัญหาเกี่ยวกับการตั้งค่าระบบ https.protocols ทรัพย์สินสำหรับการเชื่อมต่อ

ฉันเพิ่มการบันทึก SSL แบบละเอียดเพื่อระบุ TLS ที่รองรับ สิ่งนี้บ่งชี้ว่ามีการใช้ TLSv1 สำหรับการจับมือกัน
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

ฉันแก้ไขปัญหานี้ได้โดยการส่งคุณลักษณะนี้ออกไปยังผลิตภัณฑ์ที่เข้ากันได้กับ JDK8 ของเราค่าเริ่มต้นของ JDK8 เป็น TLSv1.2 สำหรับผู้ที่ จำกัด เฉพาะ JDK7 ฉันยังทดสอบวิธีแก้ปัญหาสำหรับ Java 7 สำเร็จด้วยการอัปเกรดเป็น TLSv1.2 ฉันใช้คำตอบนี้: วิธีเปิดใช้งาน TLS 1.2 ใน Java 7


ขอบคุณมากคุณแสดงแนวทางใหม่ในการแก้ไขปัญหาของฉัน และในที่สุดฉันก็พบว่ามันเป็นอย่างนั้น !!!
karl li

1

ฉันยังมีปัญหากับโปรแกรม Java ที่พยายามส่งคำสั่งบนเซิร์ฟเวอร์ผ่าน SSH ปัญหาเกิดจากเครื่องรันโค้ด Java ไม่ได้รับอนุญาตให้เชื่อมต่อกับเซิร์ฟเวอร์ระยะไกล เมธอด write () ทำได้ดี แต่เมธอด read () กำลังขว้าง java.net.SocketException: การรีเซ็ตการเชื่อมต่อ ฉันแก้ไขปัญหานี้ด้วยการเพิ่มคีย์ SSH ของไคลเอ็นต์ไปยังคีย์ที่รู้จักของเซิร์ฟเวอร์ระยะไกล


0

จากประสบการณ์ของฉันฉันมักจะพบกับสถานการณ์ต่อไปนี้

  1. หากคุณทำงานใน บริษัท ของ บริษัท โปรดติดต่อเครือข่ายและทีมรักษาความปลอดภัย เนื่องจากในการร้องขอไปยังบริการภายนอกอาจจำเป็นต้องให้สิทธิ์สำหรับปลายทางที่เกี่ยวข้อง

  2. ปัญหาอีกประการหนึ่งคือใบรับรอง SSL อาจหมดอายุบนเซิร์ฟเวอร์ที่แอปพลิเคชันของคุณกำลังทำงานอยู่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.