আমি কীভাবে কোনও সার্ভারসকেট গ্রহণযোগ্য () পদ্ধতিতে বাধা দিতে পারি?


143

আমার মূল থ্রেডে আমার একটি while(listening)লুপ রয়েছে যা accept()আমার সার্ভারসকেট অবজেক্টে কল করে, তারপরে একটি নতুন ক্লায়েন্ট থ্রেড শুরু করে এবং যখন কোনও নতুন ক্লায়েন্ট গ্রহণযোগ্য হয় তখন এটি একটি সংযোজনে যুক্ত হয়।

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

যাইহোক, লুপ ব্লকগুলিতে accept()কল while(listening), এবং এটির ব্যত্যয় করার কোনও উপায় বলে মনে হচ্ছে না, তাই কিছুক্ষণ শর্তটি আবার পরীক্ষা করা যায় না এবং প্রোগ্রামটি প্রস্থান করতে পারে না!

এই কাজ করতে একটি ভাল উপায় আছে কি? বা ব্লকিং পদ্ধতিতে বাধা দেওয়ার কোনও উপায়?



যে পিপলটি x সময় অপেক্ষা করতে চান এবং তারপরে setSoTimeout () ব্যবহার করুন wants
আবদুল্লাহ ওরাবি

উত্তর:


151

আপনি close()অন্য থ্রেড থেকে কল করতে পারেন এবং accept()কলটি একটি নিক্ষেপ করবে SocketException


2
ধন্যবাদ, তাই সুস্পষ্ট, এমনকি আমার কাছে ঘটেনি! আমি লুপটি ছাড়ার পরে কাছে () কল করছিলাম calling
lukeo05

4
আশ্চর্যের বিষয়, ডক্সে এই তথ্য নেই: download.oracle.com/javase/6/docs/api/java/net/… পদ্ধতিটি সকেটএক্সসেপশন নিক্ষেপ হিসাবে চিহ্নিত নয় as এটি কেবল এখানেই উল্লেখ করা হয়েছে download.oracle.com/javase/1.4.2/docs/api/java/net/…
ভ্লাদিস্লাভ রাস্ট্রুসনি

1
ফোন করা কি ঠিক আছে close(), মানে এটি করার ব্যতিক্রমটি ছুঁড়ে ফেলবে, অনুরোধের জন্য শ্রবণ বন্ধ করার জন্য অন্য কোনও উপায় আছে (যা ব্যতিক্রম নিক্ষেপ করে না, সময়সীমার উপর ভিত্তি করেও নয়)?
কুশল

3
এবং সংযোগটি ইতিমধ্যে গৃহীত হয়ে থাকলে এবং থ্রেডটি কোনও ডেটার জন্য অপেক্ষা করছে: যখন ((গুলি = ইন। রিডলাইন ())! = নাল)?
অ্যালেক্স ফেদুলভ

1
@ অ্যালেক্সফিডুলভ ইনপুট জন্য সকেট। readLine()তারপরে নাল ফিরে আসবে এবং থ্রেডটির ইতিমধ্যে থাকা স্বাভাবিক বন্ধের ক্রিয়াকলাপগুলি ঘটবে।
লার্নের মারকুইস

31

টাইমআউট চালু করুন accept(), তারপরে কল নির্দিষ্ট সময়ের পরে অবরুদ্ধকরণের সময়সীমা শেষ করবে:

http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT

অবরুদ্ধকরণের Socketক্রিয়াকলাপের সময়সীমা নির্ধারণ করুন :

ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();

কার্যকর হওয়ার জন্য ব্লকিং অপারেশনে প্রবেশের আগে বিকল্পটি অবশ্যই সেট করতে হবে। সময়সীমা শেষ হলে এবং অপারেশন অবরুদ্ধ অবিরত থাকলে java.io.InterruptedIOExceptionউত্থাপিত হয়। Socketএই ক্ষেত্রে বন্ধ হয়নি।



4

আপনি কেবল বিরতি সার্ভারসোকট.অ্যাকসেপ্টের জন্য "বাতিল" সকেট তৈরি করতে পারেন ()

সার্ভার সাইড

private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;

while (true) {
      Socket clientSock = serverSocket.accept();
      int code = clientSock.getInputStream().read();
      if (code == END_WAITING
           /*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
             // End waiting clients code detected
             break;
       } else if (code == CONNECT_REQUEST) { // other action
           // ...
       }
  }

বিরতি সার্ভার চক্র জন্য পদ্ধতি

void acceptClients() {
     try {
          Socket s = new Socket(myIp, PORT);
          s.getOutputStream().write(END_WAITING);
          s.getOutputStream().flush();
          s.close();
     } catch (IOException e) {
     }
}

4

কারণ ServerSocket.close()ছোঁড়ার একটি ব্যতিক্রম কারণ আপনি একটি আছে outputstreamঅথবা একটি inputstream যে সকেট সংযুক্ত। আপনি প্রথমে ইনপুট এবং আউটপুট স্ট্রিমগুলি বন্ধ করে এই ব্যতিক্রমটি নিরাপদে এড়াতে পারবেন। তারপরে বন্ধ করার চেষ্টা করুন ServerSocket। এখানে একটি উদাহরণ:

void closeServer() throws IOException {
  try {
    if (outputstream != null)
      outputstream.close();
    if (inputstream != null)
      inputstream.close();
  } catch (IOException e1) {
    e1.printStackTrace();
  }
  if (!serversock.isClosed())
    serversock.close();
  }
}

ব্যতিক্রম না পেয়ে যে কোনও জায়গা থেকে যে কোনও সকেট বন্ধ করতে আপনি এই পদ্ধতিটি কল করতে পারেন।


7
ইনপুট এবং আউটপুট স্ট্রিম সংযুক্ত হয় না ServerSocketকিন্তু একটি থেকে Socketএবং আমরা বন্ধ বিষয়ে কথা বলছি ServerSocketনা Socket, তাই ServerSocketএকটি বন্ধ না করেই বন্ধ করা যেতে পারে Socketএর স্ট্রিম।
আইজজা

1

এটি কাজ করে না ... আপনি যদি এটি কাজ করে থাকেন তবে আপনি কি দয়া করে ওয়ার্কিং কোডের একটি উদাহরণ দেখাবেন?
মাইকেল সিমস

1

ঠিক আছে, আমি এটি এমনভাবে কাজ করেছি যাতে ওপির প্রশ্নটিকে আরও সরাসরি সম্বোধন করা হয়।

আমি কীভাবে এটি ব্যবহার করি তার একটি থ্রেড উদাহরণের জন্য সংক্ষিপ্ত উত্তরটি পড়তে থাকুন।

সংক্ষিপ্ত উত্তর:

ServerSocket myServer;
Socket clientSocket;

  try {    
      myServer = new ServerSocket(port)
      myServer.setSoTimeout(2000); 
      //YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
      clientSocket = myServer.accept();
      //In this case, after 2 seconds the below interruption will be thrown
  }

  catch (java.io.InterruptedIOException e) {
      /*  This is where you handle the timeout. THIS WILL NOT stop
      the running of your code unless you issue a break; so you
      can do whatever you need to do here to handle whatever you
      want to happen when the timeout occurs.
      */
}

বাস্তব বিশ্বের উদাহরণ:

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

package MyServer;

import javafx.concurrent.Task;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

public class Server {

public Server (int port) {this.port = port;}

private boolean      threadDone        = false;
private boolean      threadInterrupted = false;
private boolean      threadRunning     = false;
private ServerSocket myServer          = null;
private Socket       clientSocket      = null;
private Thread       serverThread      = null;;
private int          port;
private static final int SO_TIMEOUT    = 5000; //5 seconds

public void startServer() {
    if (!threadRunning) {
        serverThread = new Thread(thisServerTask);
        serverThread.setDaemon(true);
        serverThread.start();
    }
}

public void stopServer() {
    if (threadRunning) {
        threadInterrupted = true;
        while (!threadDone) {
            //We are just waiting for the timeout to exception happen
        }
        if (threadDone) {threadRunning = false;}
    }
}

public boolean isRunning() {return threadRunning;}


private Task<Void> thisServerTask = new Task <Void>() {
    @Override public Void call() throws InterruptedException {

        threadRunning = true;
        try {
            myServer = new ServerSocket(port);
            myServer.setSoTimeout(SO_TIMEOUT);
            clientSocket = new Socket();
        } catch (IOException e) {
            e.printStackTrace();
        }
        while(true) {
            try {
                clientSocket = myServer.accept();
            }
            catch (java.io.InterruptedIOException e) {
                if (threadInterrupted) {
                    try { clientSocket.close(); } //This is the clean exit I'm after.
                    catch (IOException e1) { e1.printStackTrace(); }
                    threadDone = true;
                    break;
                }
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
};

}

তারপরে, আমার নিয়ামক শ্রেণিতে ... (আমি কেবল প্রাসঙ্গিক কোডটি দেখাব, এটি আপনার নিজের কোডে প্রয়োজনমতো ম্যাসাজ করব)

public class Controller {

    Server server = null;
    private static final int port = 10000;

    private void stopTheServer() {
        server.stopServer();
        while (server.isRunning() {
        //We just wait for the server service to stop.
        }
    }

    @FXML private void initialize() {
        Platform.runLater(()-> {
            server = new Server(port);
            server.startServer();
            Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
            stage.setOnCloseRequest(event->stopTheServer());
        });
    }

}

আমি আশা করি এটি কারও পথে নেমে সহায়তা করবে।


0

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


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

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

কীভাবে, ঠিক আপনি কীভাবে গ্রহণযোগ্য সকেটটি অ-ব্লকিং করেন?
মাইকেল সিমস 0

লং অন = 1 এল; যদি (ioctl (সকেট, (int) FIONBIO, (চর *) এবং))
stu

@ স্টু এই প্রশ্নটি জাভার সকেটগুলির জন্য।
ক্রু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.