【问题标题】:Java how to wait until a command has completed?Java如何等到一个命令完成?
【发布时间】:2016-01-07 20:18:01
【问题描述】:

我有以下脚本:

    Connection con = new Connection("host",80);

    ByteBuffer loginbb = ByteBuffer.allocate(300);
    <snip>
    loginbb.flip();

    byte[]login = new byte[loginbb.remaining()];
    loginbb.get(login);


    ByteBuffer headerbb = ByteBuffer.allocate(7);
    <snip>
    headerbb.flip();

    byte[]header = new byte[headerbb.remaining()];
    headerbb.get(header);

    con.run(login, header);


    try {
        Thread.sleep(1000);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }


    long pid = Long.parseLong(request.getParameter("player"));
    PrintWriter out = response.getWriter();
    ByteBuffer bb = ByteBuffer.allocate(100);
    bb.putLong(pid);
    bb.putLong(pid);
    bb.put((byte) 0x00);
    bb.flip();

    byte[] payload = new byte[bb.remaining()];
    bb.get(payload);


    ByteBuffer headerbb2 = ByteBuffer.allocate(7);
    <snip>
    headerbb2.flip();

    byte[]header2 = new byte[headerbb2.remaining()];
    headerbb2.get(header2);

    con.send(payload, header2);

    try {
        Thread.sleep(700);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    JsonParser jp = new JsonParser();
    JsonElement je = jp.parse(Avatar.getJson().toString());
    String json = gson.toJson(je);
    out.flush();
    out.println(json);
    out.flush();

注意以下几点?

    try {
        Thread.sleep(700);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }

还有这个:

    try {
        Thread.sleep(1000);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }

所以这会暂停我的脚本一段时间,但我不希望这样,因为脚本可能需要更长或更短的时间。那会浪费一些时间 D:

我想要发生的是它只是等待事情完成。

con.run 基本上是做一个初始任务,然后是一个 con.send。

con.send 基本上是这样运行的:

private void sendToServer(byte[] message, int length, byte[]header) {

    byte[]payload = outrc4.encrypt(message,false);
    byte[] data = new byte[header.length+payload.length];

    System.arraycopy(header,0,data,0,header.length);
    System.arraycopy(payload,0,data,header.length,payload.length);


    try {
        out.write(data);
    } catch (IOException e) {
        System.out.println("Error!");
    }
}

它只是将数据包发送到服务器。

从这里开始,在 con.run 上我收到了多个数据包。我可以捕获数据包的 ID,并且在接收和解析数据包的循环中,我可以添加一个 if 语句来检查是否收到 loginDone 数据包。

void receive() {
    try {

        while (in.available() > -1) {

              int type = in.readUnsignedShort();
              int size = in.readUnsignedByte();
              size <<= 8;
              size |= in.readUnsignedByte();
              size <<= 8;
              size |= in.readUnsignedByte();
              int version = in.readUnsignedShort();

              byte array[] = new byte[7];
              array[0] = (byte)((type >>> 8) & 0xFF);
              array[1] = (byte)(type & 0xFF);
              array[2] = (byte)((size >>> 16) & 0xFF);
              array[3] = (byte)((size >>> 8) & 0xFF);
              array[4] = (byte)(size & 0xFF);
              array[5] = (byte)((version >>> 8) & 0xFF);
              array[6] = (byte)(version & 0xFF);

              final byte[] reply = new byte[size];

             in.readFully(reply,0,size);

             byte[] data = new byte[array.length + reply.length];
             System.arraycopy(array, 0, data, 0, array.length);
             System.arraycopy(reply, 0, data, array.length, reply.length);
             byte[] decryptedPayload = inrc4.encrypt(reply,false);

            if(type == 20000){
                updateKeys(decryptedPayload);
            }

            if(type == 24411){
            //this one means that the 1st packet that uses con.run is done

                System.out.println("Logged In!");
            }

            if(type == 24334){
            //this one means that the 2nd packet that uses con.send is done 

                InputStream myis = new ByteArrayInputStream(decryptedPayload);
                new Avatar(myis);
                t.interrupt();
            }

        }


    } catch (Exception e) {}

}

Take not of these cmets: //这意味着第二个使用 con.send 的数据包已经完成 和 //这意味着第一个使用 con.run 的数据包已经完成

这是我所知道的。有人知道我应该从这里做什么吗?

【问题讨论】:

标签: java sockets


【解决方案1】:

如果您的服务器和客户端在同一个 java 进程中,请使用 CountDownLatchthread.join()。如果它们是不同的机器,请阅读 EDIT 部分。

class Foo extends Thread {

    CountDownLatch latch;

    public Foo(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override
    public synchronized void start() {

        try {
            sleep(1000);
            latch.countDown(); // in every call latch decrease one, when it    reach to zero, every thread that is waiting the latch will continue.
sleep(100);
        } catch (InterruptedException e) {

        }
    }
}    
class FooBar {

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch latch = new CountDownLatch(1);

        new Foo(latch).start();

        latch.await(); // wait latch reach to zero. BE CAREFUL, IT'S NOT WAIT(),
                        // IT'S AWAIT()   
        System.out.println("done");
    }
}

编辑 为简单起见,我将保留上面的代码。我认为这很不言自明,可以帮助其他人。

好的,如果你想等到receive()方法完成,你需要开发一种方法,服务器可以告诉客户端方法完成,或者你可以开发一种方法,让你的客户端不断检查一些服务器中的状态,如isTaskCompleted()。我不知道你的情况有多难让服务器向客户端发送数据包。我将描述这种情况的两种方法,我将使用其他名称的类和变量,所以尽量适应你的代码。

public class WaitServer extends Thread {

    synchronized void serverCompleted() {
        // when server completes
        notify();

    }

    @Override
    public synchronized void start() {

        try {
            wait(); // waits the server
        } catch (InterruptedException e) {                      

        }       
    }   
}
class ClientSide {

    void doSomething() {

        // ... some stuff ....      
        sendToServer();

        new WaitServer().join();

        // continues execution      
    }   
}

class ServerSide {
    void received() {

        // ... do some stuff .....

        if (someStuff) {            
            sendSignalToClient();

        }       
        // .. others stuff          
    }

    void sendSignalToClient() {     
        // here of course you need to send in the way that you are sending today, this is "pseudocode"
        client.serverCompleted()        
    }       
}

另一种方法是让您的客户端检查服务器直到任务完成,只需创建一个线程发送验证作业,如果未完成则休眠一段时间。当你想让一个线程等待另一个线程时,使用join()。如果您希望一个线程在另一个线程中等待处理的某些部分,请使用CountDownLatch

【讨论】:

  • @ShivamPaw 你想等到 receive() 完成还是等到 send()?
  • 请看看这是否有帮助:stackoverflow.com/questions/15956231/…
  • 因此,每次通过输入流进入时,我都可以检查数据包的 ID。如果数据包 x 进来,那么我可以从我将第一个数据包发送到服务器(con.run)的地方继续,当 pakcet y 从 con.send 进来时,我可以继续解析 josn 位
  • @ShivamPaw 一个问题,您的“服务器”和“客户端”是否在同一个程序/java 进程中?还是它们是不同的机器?
  • @ShivamPaw 好的,再看看我的回答。
猜你喜欢
  • 1970-01-01
  • 2015-07-05
  • 1970-01-01
  • 2011-02-19
  • 2011-09-20
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
相关资源
最近更新 更多