मैं एक ServerSocket स्वीकृति () विधि को कैसे बाधित कर सकता हूं?


143

मेरे मुख्य धागे में मेरे पास एक while(listening)लूप है जो accept()मेरे सर्वर सॉकेट ऑब्जेक्ट पर कॉल करता है, फिर एक नया क्लाइंट थ्रेड शुरू करता है और एक नए क्लाइंट को स्वीकार किए जाने पर इसे एक संग्रह में जोड़ता है।

मेरे पास एक व्यवस्थापक थ्रेड भी है जिसे मैं कमांड जारी करने के लिए उपयोग करना चाहता हूं, जैसे 'निकास', जिसके कारण सभी क्लाइंट थ्रेड बंद हो जाएंगे, स्वयं बंद हो जाएंगे, और मुख्य थ्रेड को बंद कर देंगे, झूठी बात सुनकर।

हालाँकि, लूप ब्लॉक accept()में कॉल while(listening), और इसे बाधित करने का कोई तरीका प्रतीत नहीं होता है, इसलिए स्थिति को फिर से जाँच नहीं किया जा सकता है और प्रोग्राम बाहर नहीं निकल सकता है!

क्या ऐसा करने के लिए इससे अच्छा तरीका है? या अवरुद्ध विधि को बाधित करने का कोई तरीका?



पेपोल के लिए, जो x समय की प्रतीक्षा करना चाहता है और फिर सेटसूटाइमआउट () का उपयोग करता है।
अब्दुल्ला ओरबी

जवाबों:


151

आप close()किसी अन्य थ्रेड से कॉल कर सकते हैं , और accept()कॉल एक फेंक देगा SocketException


2
धन्यवाद, इतना स्पष्ट, मेरे लिए भी नहीं हुआ! लूप से बाहर निकलने के बाद मैं करीब बुला रहा था।
lukeo05

4
अजीब बात है, कि डॉक्स में यह जानकारी नहीं है: download.oracle.com/javase/6/docs/api/java/net/… इस विधि को SocketException को फेंकने के रूप में चिह्नित नहीं किया गया है। यह केवल यहाँ बताया गया है। डाउनलोड
.oracle.com/javase/1.4.2/docs/api/java/net/…

1
क्या यह कॉल करने के लिए ठीक है close(), मेरा मतलब है कि इसे करने पर अपवाद फेंक देंगे, तो क्या कोई अन्य तरीका है (जो अपवाद को नहीं फेंकता है, यह भी टाइमआउट पर आधारित नहीं है) अनुरोधों को सुनने से रोकने के लिए?
कुशाल

3
और क्या करें यदि कनेक्शन पहले से ही स्वीकार किया गया था और थ्रेड कुछ डेटा की प्रतीक्षा कर रहा है: जबकि ((s = in.readLread) () =? Null)
एलेक्स फेडुलोव

1
@AlexFedulov शटडाउन कि इनपुट के लिए सॉकेट। 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है धाराओं।
icza


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.
      */
}

वास्तविक दुनिया उदाहरण:

इस उदाहरण में, मेरे पास एक सर्वर-थ्रेड के अंदर कनेक्शन के लिए प्रतीक्षा कर रहा है। जब मैं एप्लिकेशन को बंद कर देता हूं, तो मैं एप्लिकेशन को बंद करने से पहले थ्रेड (अधिक विशेष रूप से, सॉकेट) को बंद करना चाहता हूं, इसलिए मैं सर्वरसेट पर .setSoTimeout () का उपयोग करता हूं फिर मैं उस अवरोध का उपयोग करता हूं जो फेंक दिया गया है। जाँच करने और देखने के बाद कि क्या अभिभावक थ्रेड को बंद करने का प्रयास कर रहा है। यदि ऐसा है, तो मैं सॉकेट बंद कर देता हूं, फिर एक ध्वज सेट करता है जो दर्शाता है कि धागा किया गया है, फिर मैं थ्रेड लूप से बाहर निकलता हूं जो एक अशक्त लौटाता है।

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

एक और चीज आप कोशिश कर सकते हैं जो क्लीनर है, स्वीकार लूप में एक ध्वज की जांच करना है, और फिर जब आपका व्यवस्थापक थ्रेड स्वीकार पर रोक रहे धागे को मारना चाहता है, तो ध्वज सेट करें (इसे थ्रेड को सुरक्षित रखें) और फिर क्लाइंट सॉकेट बनाएं सुनने वाले सॉकेट से कनेक्शन। स्वीकार ब्लॉक करना बंद कर देगा और नया सॉकेट लौटाएगा। आप थ्रेड को साफ से बाहर निकलने के लिए सुनने वाले धागे को बताकर कुछ साधारण प्रोटोकॉल चीज़ को काम कर सकते हैं। और फिर क्लाइंट साइड पर सॉकेट बंद कर दें। कोई अपवाद नहीं, बहुत क्लीनर।


इसका कोई मतलब नहीं है ... जब आपके पास इस सॉकेट जैसा कोड होता है = serverSocket.accept (); उस समय, अवरुद्ध करना प्रारंभ हो जाता है और लूप हमारे कोड का हिस्सा नहीं होता है, इसलिए उस ब्लॉक कोड को उस ध्वज के लिए देखना है जो मैंने सेट किया है ... कम से कम मुझे ऐसा करने का तरीका नहीं मिल पाया है। .. अगर आपके पास वर्किंग कोड है, तो कृपया साझा करें?
माइकल सिम्स

हाँ, ऐसा लगता है कि मैंने एक महत्वपूर्ण जानकारी को छोड़ दिया है, जो इसे बहुत मायने नहीं रखेगा। आपको स्वीकार किए जाने वाले सॉकेट को अवरुद्ध करने की आवश्यकता होती है और लूप के दोहराए जाने से पहले कुछ समय के लिए केवल उसी ब्लॉक को ब्लॉक करना होता है, जिस क्षेत्र में आप बाहर निकलने वाले झंडे की जांच करेंगे।
स्टू

कैसे, वास्तव में, क्या आप सॉकेट, गैर-अवरोधक बनाते हैं?
माइकल सिम्स

लंबे समय तक = 1 एल; अगर (ioctl (सॉकेट, (int) FIONBIO, (char *) और पर))
stu

@stu यह सवाल जावा के सॉकेट्स के लिए है।
क्रॉ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.