জাভা সকেট এপিআই: কোনও সংযোগ বন্ধ হয়ে গেছে কিনা তা কীভাবে বলবেন?


95

আমি জাভা সকেট এপিআই দিয়ে কিছু সমস্যা নিয়ে চলেছি। আমি বর্তমানে আমার গেমের সাথে সংযুক্ত খেলোয়াড়ের সংখ্যা প্রদর্শন করার চেষ্টা করছি। কোনও খেলোয়াড় কখন সংযুক্ত হয়েছে তা নির্ধারণ করা সহজ। তবে, খেলোয়াড় কখন সকেট এপিআই ব্যবহার করে সংযোগ বিচ্ছিন্ন করেছে তা নির্ধারণ করা অযথা জটিল বলে মনে হয়।

isConnected()দূরবর্তীভাবে সংযোগ বিচ্ছিন্ন করা এমন একটি সকেটে কল করা সর্বদা ফিরে আসবে বলে মনে হয় true। একইভাবে, isClosed()দূরবর্তীভাবে বন্ধ হয়ে যাওয়া সকেটে কল করা সর্বদা ফিরে আসবে বলে মনে হয় false। আমি পড়েছি যে সকেট বন্ধ হয়েছে কিনা তা নির্ধারণ করার জন্য, আউটপুট স্ট্রিমে ডেটা লিখতে হবে এবং একটি ব্যতিক্রম অবশ্যই ধরা উচিত। এটিকে পরিস্থিতি পরিচালনা করার জন্য এটি সত্যিই অশুচি উপায় বলে মনে হচ্ছে। সকেট কখন বন্ধ হয়ে গেছে তা জানতে আমাদের কেবল ক্রমাগত নেটওয়ার্কের মধ্যে কোনও আবর্জনা বার্তা স্প্যাম করতে হবে।

অন্য কোন সমাধান আছে কি?

উত্তর:


185

কোনও টিসিপি এপিআই নেই যা আপনাকে সংযোগের বর্তমান অবস্থা বলবে। isConnected()এবং isClosed()আপনাকে আপনার সকেটের বর্তমান অবস্থা বলুন । একই জিনিস না।

  1. isConnected()আপনি এই সকেটটি সংযুক্ত করেছেন কিনা তা আপনাকে জানায় । আপনার আছে, তাই এটি সত্য ফিরে।

  2. isClosed()আপনি এই সকেটটি বন্ধ করেছেন কিনা তা আপনাকে জানায় আপনার না হওয়া পর্যন্ত এটি মিথ্যা প্রত্যাবর্তন করে।

  3. পিয়ারটি যদি সুশৃঙ্খলভাবে সংযোগটি বন্ধ করে দেয়

    • read() রিটার্ন -1
    • readLine() প্রত্যাবর্তন null
    • readXXX()EOFExceptionঅন্য যে কোনও XXX এর জন্য ছোঁড়া ।

    • একটি লেখা একটি নিক্ষেপ করবে IOException: 'পিয়ার দ্বারা সংযোগ পুনরায় সেট করুন', অবশেষে, বাফারিং বিলম্বের বিষয়।

  4. যদি অন্য কোনও কারণে সংযোগটি বাদ পড়ে তবে একটি লেখা IOExceptionশেষ পর্যন্ত উপরে ফেলে দেবে এবং একটি পঠন একই জিনিস করতে পারে।

  5. যদি পিয়ারটি এখনও সংযুক্ত থাকে তবে সংযোগটি ব্যবহার না করে, একটি পঠনের সময়সীমা ব্যবহার করা যেতে পারে।

  6. আপনি অন্য কোথাও যা পড়তে পারেন তার বিপরীতে, ClosedChannelExceptionএটি আপনাকে বলে না। [উভয়ই করেন না SocketException: socket closed.] এটি আপনাকে কেবল এটিই বলে দেয় যে আপনি চ্যানেলটি বন্ধ করে দিয়েছেন , এবং তারপরে এটি ব্যবহার চালিয়ে যাওয়া। অন্য কথায়, আপনার পক্ষ থেকে একটি প্রোগ্রামিং ত্রুটি। এটি একটি বদ্ধ সংযোগ নির্দেশ করে না

  7. উইন্ডোজ এক্সপি-তে জাভা with নিয়ে কিছু পরীক্ষার ফলস্বরূপ এটিও উপস্থিত হয় যে যদি:

    • আপনি নির্বাচন করছেন OP_READ
    • select() শূন্যের চেয়ে বেশি মানের মান প্রদান করে
    • সম্পর্কিত SelectionKeyইতিমধ্যে অবৈধ ( key.isValid() == false)

    এর অর্থ পিয়ার সংযোগটি পুনরায় সেট করেছে। তবে এটি জেআরই সংস্করণ বা প্ল্যাটফর্মের জন্যই অদ্ভুত হতে পারে।


19
এটি বিশ্বাস করা শক্ত যে টিসিপি প্রোটোকল, যা সংযোগ কেন্দ্রিক, এটির সংযোগের অবস্থাও জানতে পারে না ... এই প্রোটোকলগুলি নিয়ে আসা ছেলেরা কি চোখ বন্ধ করে গাড়ি চালাচ্ছেন?
পেড্রোড

34
@ পেড্রোড বিপরীতে: এটি ইচ্ছাকৃত ছিল। পূর্ববর্তী প্রোটোকল স্যুট যেমন এসএনএর একটি 'ডায়াল টোন' ছিল। টিসিপি একটি পরমাণু যুদ্ধ থেকে বাঁচার জন্য ডিজাইন করা হয়েছিল, এবং আরও তুচ্ছভাবে রাউটার ডাউন এবং আপস: তাই ডায়াল টোন, সংযোগের স্থিতি ইত্যাদির মতো কোনও কিছুর সম্পূর্ণ অনুপস্থিতি; আর টিসিপি রক্ষণশীলকে আরএফসিগুলিতে বিতর্কিত বৈশিষ্ট্য হিসাবে বর্ণনা করা হয়েছে এবং এটি কেন সর্বদা ডিফল্টরূপে বন্ধ থাকে is টিসিপি এখনও আমাদের সাথে রয়েছে। এসএনএ? আইপিএক্স? আইএসও? না. তারা ঠিক আছে।
ব্যবহারকারী 207421

4
আমি বিশ্বাস করি না যে এটি আমাদের কাছ থেকে এই তথ্য গোপন করার জন্য একটি ভাল অজুহাত। এই সংযোগটি হারিয়ে গেছে তা জেনে যে প্রোটোকলটি কম ত্রুটি প্রতিরোধী তা নয়, এটি সর্বদা নির্ভর করে আমরা সেই জ্ঞানের সাথে কি করি ... আমার জন্য পদ্ধতিটি বাউন্ড এবং জাভা থেকে সংযুক্ত খাঁটি মক পদ্ধতি, তাদের কোনও ব্যবহার নেই , তবে কোনও সংযোগ ইভেন্ট শ্রোতার প্রয়োজনীয়তাটি প্রকাশ করুন ... তবে আমি আবার বলছি: সংযোগটি হারিয়ে গেছে তা জেনে প্রোটোকলটি আরও খারাপ হয় না। এখন যদি আপনি যে প্রোটোকলগুলি বলছেন যে এটি সংযোগটি হারিয়ে গেছে তা আবিষ্কার করার সাথে সাথেই এটি হত্যা করেছে, এটি একটি ভিন্ন গল্প।
পেড্রোড

24
@ পেড্রো আপনি বুঝতে পারছেন না। এটি কোনও 'অজুহাত' নয়। আটকে রাখার মতো কোনও তথ্য নেই। কোনও ডায়াল টোন নেই। আপনি যদি কিছু করার চেষ্টা না করেন ততক্ষণ সংযোগটি ব্যর্থ হয়েছে কিনা তা টিসিপি জানে না এটি ছিল মৌলিক নকশার মানদণ্ড।
ব্যবহারকারী 207421

4
আপনার জবাবের জন্য @ ইজেপিকে ধন্যবাদ "ব্লকিং" না করে কোনও সকেট বন্ধ হয়ে গেছে কিনা তা আপনি কীভাবে জানেন? রিড বা রিডলাইন ব্যবহার ব্লক হতে চলেছে। উপলব্ধ পদ্ধতিটির সাথে যদি অন্য সকেটটি বন্ধ পদ্ধতিতে বন্ধ হয়ে যায়, তবে এটি 0পরিবর্তে ফিরে আসবে বলে মনে হচ্ছে -1
অসম্পূর্ণ

9

একে অপরকে হার্টবিট করে রাখা (পিং প্যাকেটগুলি প্রেরণ করা চালিয়ে যান) প্যাকেটটি খুব বড় হওয়ার দরকার নেই এটি বিভিন্ন মেসেজিং প্রোটোকলগুলিতে সাধারণ অনুশীলন। অনুসন্ধান প্রক্রিয়াটি আপনাকে টিসিপি সাধারণভাবে বের করার আগেই সংযোগ বিচ্ছিন্ন ক্লায়েন্ট সনাক্ত করতে দেয় (টিসিপি সময়সীমা অনেক বেশি) একটি তদন্ত প্রেরণ করুন এবং উত্তরটির জন্য 5 সেকেন্ড অপেক্ষা করতে অপেক্ষা করুন, যদি আপনি 2-3 বলার জন্য উত্তর না দেখেন পরবর্তী প্রোবগুলি, আপনার প্লেয়ার সংযোগ বিচ্ছিন্ন।

এছাড়াও, সম্পর্কিত প্রশ্ন


6
কিছু প্রোটোকলে এটি 'সাধারণ অনুশীলন' । আমি লক্ষ করেছি যে এইচটিটিপি, গ্রহের সবচেয়ে বেশি ব্যবহৃত অ্যাপ্লিকেশন প্রোটোকল, এর পিং অপারেশন নেই।
ব্যবহারকারী 207421

4
@ user207421 কারণ HTTP / 1 হ'ল একটি শট প্রোটোকল। আপনি অনুরোধ পাঠান, আপনি প্রতিক্রিয়া পাবেন। এবং আপনি সম্পন্ন হয়েছে। সকেট বন্ধ আছে। ওয়েবসকেট এক্সটেনশনে পিং অপারেশন রয়েছে, এইচটিটিপি / 2ও রয়েছে।
মিশা łাবিয়েলস্কি

আমি যদি সম্ভব হয় তবে একক বাইট দিয়ে হৃদস্পন্দনের সুপারিশ করেছি :)
স্টিফান রেইচ

@ মাইচাজাবিয়েলস্কি এটি এইচটিটিপি ডিজাইনারগণ নির্দিষ্ট করে নি বলেই। আপনি কেন জানেন না। এইচটিটিপি / ১.১ কোনও শট প্রোটোকল নয়। সকেটটি বন্ধ নেই: HTTP সংযোগগুলি ডিফল্টরূপে স্থির থাকে pers এফটিপি, এসএমটিপি, পিওপি 3, আইএমএপি, টিএলএস, ... হৃদস্পন্দন নেই।
ব্যবহারকারী 207421

4
হার্টবিট এবং পিং দুটি আলাদা জিনিস না? আপনি যখন পিং প্রেরণ করেন আপনি একটি পং আশা করেন তবে হৃদস্পন্দন দিয়ে আপনি কিছুই আশা করেন না।
ডিএফএসফট

2

আমি পোস্ট করা অন্যান্য উত্তরটি দেখতে পাচ্ছি, তবে আমি মনে করি আপনি ক্লায়েন্টদের সাথে আপনার গেমটি খেলছেন তাদের সাথে আপনি ইন্টারেক্টিভ রয়েছেন, তাই আমি আরও একটি পদ্ধতির ধারণা দিতে পারি (যখন বাফারড্রেডার কিছু ক্ষেত্রে অবশ্যই কার্যকর)।

আপনি যদি চান ... আপনি ক্লায়েন্টের কাছে "নিবন্ধকরণ" দায়িত্ব অর্পণ করতে পারেন। অর্থ্যাৎ আপনার প্রত্যেকটির কাছ থেকে প্রাপ্ত সর্বশেষ বার্তায় টাইমস্ট্যাম্প যুক্ত সংযুক্ত ব্যবহারকারীদের একটি সংগ্রহ থাকবে ... যদি কোনও ক্লায়েন্ট সময় বেরিয়ে যায়, আপনি ক্লায়েন্টটির পুনরায় নিবন্ধন করতে বাধ্য করবেন, তবে এটি নীচে উদ্ধৃতি এবং ধারণা নিয়ে আসে।

আমি পড়েছি যে সকেটটি বন্ধ হয়েছে কিনা তা নির্ধারণ করার জন্য আউটপুট প্রবাহে ডেটা লিখতে হবে এবং একটি ব্যতিক্রম অবশ্যই ধরা উচিত। এটিকে পরিস্থিতি পরিচালনা করার জন্য এটি সত্যিই অশুচি উপায় বলে মনে হচ্ছে।

যদি আপনার জাভা কোডটি সকেটটি বন্ধ / সংযোগ বিচ্ছিন্ন না করে, তবে আর কীভাবে আপনাকে জানানো হবে যে দূরবর্তী হোস্ট আপনার সংযোগটি বন্ধ করে দিয়েছে? শেষ পর্যন্ত, আপনার চেষ্টা / ধরা মোটামুটি একই কাজ করছে যা বাস্তব সকেটের ইভেন্টগুলির জন্য শ্রোতা শুনছেন। নিম্নোক্ত বিবেচনা কর:

  • আপনার স্থানীয় সিস্টেম আপনাকে অবহিত না করে আপনার সকেটটি বন্ধ করে দিতে পারে ... এটি কেবল সকেটের বাস্তবায়ন (যেমন এটি হার্ডওয়্যার / ড্রাইভার / ফার্মওয়্যার / রাষ্ট্র পরিবর্তনের জন্য যা কিছু পোল করে না)।
  • নতুন সকেট (প্রক্সি পি) ... একাধিক পক্ষ রয়েছে (6 টি শেষ পয়েন্টগুলি সত্যই) যা আপনার উপর সংযোগ বন্ধ করে দিতে পারে ...

আমি মনে করি বিমুক্ত ভাষাগুলির একটি বৈশিষ্ট্য হ'ল আপনি মিনটিয়া থেকে বিমূর্ত হন। এসকিএল সংযোগের জন্য বা যা-ই হোক না কেন সি # (চেষ্টা / শেষ পর্যন্ত) কীওয়ার্ডটি ব্যবহার করে ভাবুন ... এটি কেবল ব্যবসা করার ব্যয় ... আমার মনে হয় চেষ্টা / ধরা / শেষ পর্যন্ত সকেট ব্যবহারের জন্য গৃহীত এবং প্রয়োজনীয় প্যাটার্ন।


আপনার স্থানীয় সিস্টেম আপনাকে सूचित করে বা ছাড়াই 'আপনার সকেটটি বন্ধ' করতে পারে না। আপনার প্রশ্নটি শুরু হচ্ছে 'যদি আপনার জাভা কোডটি সকেটটি বন্ধ / সংযোগ বিচ্ছিন্ন না করে ...?' কোন মানে হয় না।
ব্যবহারকারী 207421

4
সকেটটি জোর করে বন্ধ করা থেকে সিস্টেমকে (উদাহরণস্বরূপ লিনাক্স) ঠিক কীভাবে বাধা দেয়? 'কল ক্লোজ' কমান্ড ব্যবহার করে 'জিডিবি' থেকে এটি করা কি এখনও সম্ভব?
অ্যান্ড্রে লেবেডেনকো

@ আন্দ্রে লেবেডেনকো কিছুই 'একেবারে বাধা দেয় না', তবে তা তা করে না।
ব্যবহারকারী 207421

@ এজেবি কে তখন করে?
আন্দ্রে লেবেডেনকো 17'17

@ আন্দ্রে লেবেডেনকো কেউ তা করে না। কেবলমাত্র অ্যাপ্লিকেশন তার নিজস্ব সকেটগুলি বন্ধ করতে পারে, যদি না এটি না করে প্রস্থান করে, তবে এই ক্ষেত্রে ওএস পরিষ্কার হয়ে যাবে।
ব্যবহারকারী 207421

1

আমি মনে করি এটি টিসিপি সংযোগগুলির প্রকৃতি, সেই মানগুলির মধ্যে সংক্রমণটি শেষ হয়ে যাওয়ার আগেই আমরা সংক্রমণে প্রায় 6 মিনিটের নীরবতা নেয়! সুতরাং আমি মনে করি না আপনি এই সমস্যার সঠিক সমাধান খুঁজে পেতে পারেন। সম্ভবত আরও ভাল উপায় হ'ল সার্ভারের মনে করা উচিত যে কোনও ব্যবহারকারীর সংযোগটি বন্ধ রয়েছে।


4
এটির তুলনায় এটি আরও অনেক বেশি সময় নিতে পারে, দুই ঘন্টা পর্যন্ত।
ব্যবহারকারী 207421

0

@ ব্যবহারকারী 207421 হিসাবে বলেছেন যে টিসিপি / আইপি প্রোটোকল আর্কিটেকচার মডেলের কারণে সংযোগের বর্তমান অবস্থা জানার কোনও উপায় নেই। সুতরাং সংযোগটি বন্ধ করার আগে সার্ভারটি আপনাকে খেয়াল করতে হবে বা আপনি নিজেই এটি পরীক্ষা করে দেখেন।
এটি একটি সহজ উদাহরণ যা সকেটটি কীভাবে সার্ভার দ্বারা বন্ধ রয়েছে তা জানার জন্য:

sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null) 
      log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");

0

আমিও একই সমস্যার মুখোমুখি হয়েছি। আমার ক্ষেত্রে ক্লায়েন্টকে অবশ্যই পর্যায়ক্রমে ডেটা প্রেরণ করতে হবে। আমি আশা করি আপনার একই চাহিদা আছে তারপরে আমি SO_TIMEOUT সেট করেছিলাম socket.setSoTimeout(1000 * 60 * 5);যা নির্দিষ্ট সময়টির java.net.SocketTimeoutExceptionমেয়াদ শেষ হয়ে গেলে নিক্ষেপ করা হয়। তাহলে আমি সহজেই মৃত ক্লায়েন্ট সনাক্ত করতে পারি।


0

যে কোনও ডেটা টাইপের জন্য আপনি এখানে অন্য সাধারণ সমাধান।

int offset = 0;
byte[] buffer = new byte[8192];

try {
    do {
        int b = inputStream.read();

        if (b == -1)
           break;

        buffer[offset++] = (byte) b;

        //check offset with buffer length and reallocate array if needed
    } while (inputStream.available() > 0);
} catch (SocketException e) {
    //connection was lost
}

//process buffer

-2

আমি কীভাবে এটি পরিচালনা করব তা ঠিক

 while(true) {
        if((receiveMessage = receiveRead.readLine()) != null ) {  

        System.out.println("first message same :"+receiveMessage);
        System.out.println(receiveMessage);      

        }
        else if(receiveRead.readLine()==null)
        {

        System.out.println("Client has disconected: "+sock.isClosed()); 
        System.exit(1);
         }    } 

যদি ফলাফলের কোড কোড == নাল হয়


আপনার readLine()দুবার কল করার দরকার নেই । আপনি ইতিমধ্যে জানেন যে এটি elseব্লকটি শূন্য ছিল ।
ব্যবহারকারী 207421

-4

লিনাক্সে যখন লিখুন () কোনও সকেটে প্রবেশ করান যা অন্যদিকে, আপনার অজানা, বন্ধ করা একটি সিগপাইপ সিগন্যাল / ব্যতিক্রম প্ররোচিত করবে তবে আপনি এটি কল করতে চান। তবে আপনি যদি সিগপাইপ দ্বারা ধরা পড়তে না চান তবে আপনি এমএসজি_এনওসিএনএনএল পতাকা সহ প্রেরণ () ব্যবহার করতে পারেন। প্রেরণ () কলটি -1 এর সাথে ফিরে আসবে এবং এই ক্ষেত্রে আপনি ত্রুটিটি পরীক্ষা করতে পারবেন যা আপনাকে বলবে যে আপনি ভাঙা পাইপ (এই ক্ষেত্রে একটি সকেট) লিখতে চেষ্টা করেছেন এমন মূল্য EPIPE যার সাথে errno.h এর সমান? 32. EPIPE এর প্রতিক্রিয়া হিসাবে আপনি দ্বিগুণ হয়ে যেতে পারেন এবং সকেটটি আবার খোলার চেষ্টা করতে পারেন এবং আবার আপনার তথ্য প্রেরণের চেষ্টা করতে পারেন।


send()কল ফিরে আসবে -1 শুধুমাত্র যদি বিদায়ী তথ্য পাঠাতে টাইমার মেয়াদ শেষ হওয়ার জন্য দীর্ঘ যথেষ্ট জন্য বাফার হয়। উভয় প্রান্তে বাফারিং এবং send()হুডের নীচে অ্যাসিনক্রোনাস প্রকৃতির কারণে সংযোগ বিচ্ছিন্ন হওয়ার পরে এটি অবশ্যই প্রথম প্রেরণে ঘটবে না ।
ব্যবহারকারী 207421
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.