Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Возврат по условию-2


Автор: Alone 19.8.2004, 16:34
По ходу дела возник еще вопрос:
а как отловить таймаут в ожидании???
wait(timeout) генерит ексепшны
# IllegalArgumentException
# IllegalMonitorStateException
# InterruptedException
но это не туда... как быть? Чего я не учел?
как мне определить, что было прерывание по таймауту???

Автор: AntonSaburov 19.8.2004, 17:15
А почему должно быть прерывание по таймауту. Если просто истекло время - программа продолжит свое исполнение. И все. Т.е. отсутствие эксепшенов и есть признак, что таймаут кончился.

Если ошибаюсь - поправьте.

Автор: Alone 19.8.2004, 17:45
Скажем так: из объекта А я отправил запрос объекту Б, который работает с сокетом. Он в свою очередь удачно отправил запрос на сервер. Но я со стороны А ставлю условие, что ответ должен прийти не позднее чем через 3 сек. и ставлю таймаут.
Если нужный мне тип ответа придет - объект Б нотифицирует моего ожидающего А и он продолжит работу. Но если вылет по таймауту - я должен сигнализировать об ошибке.
Вот такая ситуация...
Я кстати уже нашел решение. smile.gif

Объект А:

boolean a=false;
lock.wait(timeOut)
if(!a) {
timeout error
}

Объект Б:

if(received){
A.a=true;
lock.notify()
}

что то типа такого...

Автор: Domestic Cat 19.8.2004, 21:34
А лучсе всего использовать java.nio.* - он позволяет асинхронную работу с сокетами, что
гораздо эффективнее.

Автор: LSD 19.8.2004, 23:04
Alone решение правильное (я бы тоже так делал), только добавить синхронизацию и все.

Автор: redrick 20.8.2004, 03:58
я вот подобную вещь видел сделанной немного по-другому... завтра попробую раскопать сорс и сказать как именно, но идея в том, что вокруг объекта Б делается класс типа TimeoutSocket, а он в случае таймаута кидает ексепшн, который и ловится...

Автор: Alone 20.8.2004, 09:51
Цитата(LSD @ 19.8.2004, 23:04)
Alone решение правильное (я бы тоже так делал), только добавить синхронизацию и все.

Естественно с синхронизацией, я просто в примере не писал. wink.gif
Добавлено @ 09:57
Цитата(Domestic @ 19.8.2004, 21:34)
А лучсе всего использовать java.nio.* - он позволяет асинхронную работу с сокетами, что
гораздо эффективнее.

Эффективнее по сравнению с чем?

Автор: Alone 20.8.2004, 10:44
Цитата(redrick @ 20.8.2004, 03:58)
я вот подобную вещь видел сделанной немного по-другому... завтра попробую раскопать сорс и сказать как именно, но идея в том, что вокруг объекта Б делается класс типа TimeoutSocket, а он в случае таймаута кидает ексепшн, который и ловится...

Тут хитрость - в работе с сокетами...
в данном случае с сокетом одновременно работают несколько объектов. каждый из них отправляет через сокет запросы. Когда что-то приходит на сокет - оно парсится и выполняется соответствующие вызова каких либо методов. вот тут никто никакой гарантии на временные интервалы дать не сможет. Пример
1. Объект "А" послал запрос сокету (Объект "Б")
2. Объект "С" тоже послал свой запрос "Б"
"Б" взаимодействует с сервером
3. в "Б" возвращается ответ для "А" , который передается по сети 20сек
4. И о каком таймауте для сокета может идти речь smile.gif
Сокет "работает" честно... а вот данные пришли позднее чем были нужны smile.gif
Если сокет по какой либо "технической" причине не сможет принять / отправить данные , он сообщит через своего обработчика ошибок, и это будет ошибка сети wink.gif

Хух... заговорился... smile.gif

Автор: Domestic Cat 20.8.2004, 15:14
Цитата(Alone @ 20.8.2004, 01:44)
Эффективнее по сравнению с чем?


По сравнению с синхронным IO, то есть java.net.*, java.io.*.

Автор: Alone 20.8.2004, 16:09
Гм... я почему то думал, что как раз наоборот, синхронные лучше/эффективнее асинхронных...
Где я неправ?

Автор: Domestic Cat 20.8.2004, 16:28
Синхронный IO означает, что поток должен ждать завершения действия
(например, подключения клиента). В это время ничего другого поток делать не может.
Значит, нужно несколько потоков.
В асинхронном такие операции не являются блокирующими, и поток может одновременно
(почти smile.gif ) ждать клиента, работать с 10 другими клиентами и пр.
Если нужен всего один поток, то это естественно, эффективнее, чем несколько потоков.

Автор: redrick 20.8.2004, 16:41
вот по этому поводу

Цитата

и поток может одновременно
(почти  ) ждать клиента, работать с 10 другими клиентами и пр.


интересна такая вещь : это реализуется внутри самого потока ? т. е. это ведь возможно только если один объект знает о нескольких потоках, которые он обслуживает (скажем сокет соединяется с несколькими серверами). Я по роду деятельности сталкивался с асинхронным API в .NET - там есть beginInvoke(), который отправляет запрос на сервер и выдает вам хендел hr, вы делаете что хотите и когда закончили и вам понадобились данные вызываете endInvoke(hr), который либо выдает данные, либо блокируется до тоговремени, когда они будут. Ну и т. п.

Вобщем есть ли в Java нечто подобное и почему ?

Автор: Domestic Cat 20.8.2004, 16:50
Ну я просто для примера приведу код асинхронного сервера (из J. Hart, Java 1.4 Core Platform Update):
Server2 может делать accept, чтение и запись в несколько сокетов в одном потоке.
Код

import java.nio.channels.*;
import java.nio.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class Server2 implements MessageProtocol {

 public static void main(String[] args) {
   MessageReceiver messageReceiver = new MessageReceiver();
   MessageSender messageSender = new MessageSender();

   try {
     int id = 0;

     Selector selector = Selector.open();

     ServerSocketChannel ssc = ServerSocketChannel.open();
     ssc.configureBlocking(false);

     ServerSocket server = ssc.socket();
     server.bind(new InetSocketAddress(DEFAULT_PORT));

     ssc.register(selector, SelectionKey.OP_ACCEPT);
     int a;

     while (true) {
       a = selector.select();

       if (a > 0) {
         try {
           Set keys = selector.selectedKeys();

           Iterator i = keys.iterator();

           while (i.hasNext()) {

             SelectionKey selectedChannelKey =
               (SelectionKey) i.next();

             i.remove();

             int purpose = selectedChannelKey.interestOps();

             if ((purpose & SelectionKey.OP_ACCEPT) > 0) {

               ServerSocketChannel selectedChannel =
                 (ServerSocketChannel) selectedChannelKey.channel();
               SocketChannel sock = selectedChannel.accept();
               sock.configureBlocking(false);

               sock.register(selector, SelectionKey.OP_READ);

             } else if ((purpose & SelectionKey.OP_READ) > 0) {
               
               SocketChannel sock =
                 (SocketChannel) selectedChannelKey.channel();
               messageReceiver.receive(sock);

               sock.register(selector, SelectionKey.OP_WRITE);

             } else if ((purpose & SelectionKey.OP_WRITE) > 0) {
               
               SocketChannel sock =
                 (SocketChannel) selectedChannelKey.channel();

               messageSender.send(sock, id++, "TEXT",
                                  "Message received and understood");

               sock.close();

             }
           }
         } catch (Exception e) {
           System.out.println(e.getMessage());
           e.printStackTrace();
         }
       }
     }
   } catch (Exception e) {
     System.out.println(e.getMessage());
     e.printStackTrace();
   }
 }
}



Код

public class Client implements MessageProtocol {

 public static void main(String[] args) {
   if (args.length < 1) {
     System.exit(1);
   }

   try {
     SocketChannel sock = SocketChannel.open();
     sock.connect(new InetSocketAddress(args[0], DEFAULT_PORT));

     new  MessageSender().send(sock, 0, "TEXT",
                              "testing, testing, 1, 2, 3");
     new MessageReceiver().receive(sock);
   } catch (Exception e) {
     System.out.println(e.getMessage());
     e.printStackTrace();
   }
 }
}


Код

public interface MessageProtocol extends ByteSizes {
 public static final int MESSAGE_ID_LENGTH     = 1 * INT_SIZE;
 public static final int MESSAGE_TYPE_LENGTH   = 4 * CHAR_SIZE;
 public static final int MESSAGE_LENGTH_LENGTH = 1 * LONG_SIZE;
 public static final int DEFAULT_PORT          = 2000;
}



Конкретная имплементация MessageSender и MessageReceiver не важна, но если нужно, могу и их запостить
Добавлено @ 16:56
Код

public interface ByteSizes {
 public static final int BYTE_SIZE   = 1;
 public static final int CHAR_SIZE   = 2;
 public static final int SHORT_SIZE  = 2;
 public static final int INT_SIZE    = 4;
 public static final int FLOAT_SIZE  = 4;
 public static final int LONG_SIZE   = 8;
 public static final int DOUBLE_SIZE = 8;
}


Код

import java.nio.channels.*;
import java.nio.*;
import java.io.*;

public class MessageReceiver implements MessageProtocol {

 public void receive(ScatteringByteChannel in) throws IOException {
   ByteBuffer messageIdBytes = ByteBuffer.allocate(MESSAGE_ID_LENGTH);
   ByteBuffer messageTypeBytes = ByteBuffer.allocate(MESSAGE_TYPE_LENGTH);
   ByteBuffer messageLengthBytes = ByteBuffer.allocate(MESSAGE_LENGTH_LENGTH);

   in.read(new ByteBuffer[] {messageIdBytes, messageTypeBytes, messageLengthBytes});

   messageIdBytes.rewind();
   messageTypeBytes.rewind();
   messageLengthBytes.rewind();
   
int messageId      = messageIdBytes.asIntBuffer().get();
    String messageType = messageTypeBytes.asCharBuffer().toString();
    long messageLength = messageLengthBytes.asLongBuffer().get();

   ByteBuffer messageBytes = ByteBuffer.allocate((int) messageLength
                                                 * CHAR_SIZE);
   in.read(messageBytes);
   messageBytes.rewind();
   String message = messageBytes.asCharBuffer().toString();

   System.out.println("Msg: " + messageId);
   System.out.println("Type: " + messageType);
   System.out.println(message);
 }

 public static void main(String[] args) {
   if (args.length < 1) {
     System.exit(1);
   }

   try {
     FileChannel fc = new FileInputStream(args[0]).getChannel();

     new MessageReceiver().receive(fc);

   } catch (Exception e) {
     System.out.println(e.getMessage());
     e.printStackTrace();
   }
 }
}


Код

import java.nio.channels.*;
import java.nio.*;
import java.io.*;

public class MessageSender implements MessageProtocol {

 public void send(GatheringByteChannel out, int messageId,String messageType,String message) throws IOException {
   
ByteBuffer messageIdBytes = ByteBuffer.allocate(MESSAGE_ID_LENGTH);
    ByteBuffer messageTypeBytes = ByteBuffer.allocate(MESSAGE_TYPE_LENGTH);
    ByteBuffer messageLengthBytes = ByteBuffer.allocate(MESSAGE_LENGTH_LENGTH);
    ByteBuffer messageBytes = ByteBuffer.allocate(message.length() * CHAR_SIZE);
   
messageIdBytes.asIntBuffer().put(messageId);
    messageTypeBytes.asCharBuffer().put(messageType);
    messageLengthBytes.asLongBuffer().put((long) message.length());
    messageBytes.asCharBuffer().put(message);

    out.write(new ByteBuffer[] {messageIdBytes, messageTypeBytes, messageLengthBytes, messageBytes});
 
}

 public static void main(String[] args) {
   if (args.length < 1) {
     System.exit(1);
   }

   try {
     FileChannel fc = new FileOutputStream(args[0]).getChannel();
     new MessageSender().send(fc, 0, "TEXT", "hello world");
   } catch (Exception e) {
     System.out.println(e.getMessage());
     e.printStackTrace();
   }
 }
}



Автор: redrick 20.8.2004, 18:49
спасибо большое за примеры (по хорошему сам конешно лазить бы должен =) ) -
прояснилось

Автор: Domestic Cat 20.8.2004, 19:33
Нема за що, как говорят у нас в Канадi smile.gif

Автор: Alone 21.8.2004, 11:39
Domestic Cat
Дякуэмо за код biggrin.gif

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)