代写C++代码 代做C++程序 C++辅导 C++教学

C++网络家教 远程写代码 在线Debug 讲解答疑 不是中介,本人直接写

微信: ittutor QQ: 14061936 Email: ittutor@qq.com

导航

代写网络程序,聊天程序FTP, Http Proxy, P2P等,语言可以是Java C C++.

Chapter 13: Web Service Callbacks and Polling: the Chat Example The obvious next step we need to take is to rebuild the chat example that we used to illustrate sockets and rmi using web services. But there are problems...


代写网络程序,聊天程序FTP, Http Proxy, P2P等,语言可以是Java C C++.

page 1

Chapter 13: Web Service Callbacks

and Polling: the Chat Example

The obvious next step we need to take is to rebuild the chat example that we used to illustrate sockets and rmi

using web services. But there are problems...

13.1. Asynchronous Web Services: Polling and Callbacks

As you might expect, web services do provide mechanisms for asynchronous service invocation - using either

polling or callbacks - and we will look at these below. However, they don't help us very much. This is because

the mechanisms are designed to enable clients to call services and then continue without blocking for their

results. Furthermore, it's not easy to build our own version (at least not for callbacks - we can do polling

straightforwardly enough) because the architectural focus for asynchronous service calls is entirely on the

client: that is, a web service is built regardless of how it will be invoked and the choice of how to invoke it -

synchronous (blocking) or ansynchronous (non blocking) is made solely at the client. And there is no mechanism

to allow a service to contact a client except in response to an invocation from a client. Therefore, we can't use

this mechanism to implement the chat application.

As an aside, this may seem silly - but you need to remember that a fair amount of the point of web services

is that they are published by an organization and then used by clients as the see fit: there is no strong ('tightly

coupled') link between the service provider and the client. A variety of large organizations now expose access

to (parts of) the business logic of their systems: for example Google, Amazon and eBay. You can fairly easily

track down and look at the published WSDL descriptions for these services, that are made available to potential

clients. To make it easier, Amazon's is at:

http://soap.amazon.com/schemas2/AmazonWebServices.wsdl

You may have to select 'view source' in your browser to see anything sensible. Notice complex the Amazon

WSDL is - representing a real, useable service - much more complex than the small examples we are going to

see.)

Can we build our own mechanism - which is more or less what we had to do in RMI - to enable a client to call a

service and pass a reference to another service of its own (technically called an endpoint) that the client can then

call? Well, possibly, but not easily. This is because the code to communicate with services is generated, from the

WSDL, statically at compile time. Since the WSDL for each client will be slightly different (the service URL

will not be the same), it's not obvious how we can do this. In fact, there are mechanisms to enable this but they

are not something we have the time to go into.

The slightly better news is that although we cannot use the built-in mechanisms for callbacks or polling, it's

pretty easy for us to build our own polling mechanism - which is what we will do.But first we will look at the the

asynchronous tools that are provided - even though they are not useful for our application, they are important.

13.1.1. Polling

Polling is the easiest mechanism to understand, just as in RMI, and centers around an interface called

java.util.concurrent.Future:

 public interface Future<V>{

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit) throws

 InterruptedException,ExecutionException,TimeoutException;

}

  

JAX-WS provides mechanisms for generating objects implementing Future which are passed back to the

client when a service is invoked asychronously. This object allows the client to monitor, control and retrieve the

result of the service. Most of the methods should be pretty obvious: get() retrieves the result if the service has

finished and waits otherwise; the other get waits for a specified period of time.

13.1.2. Callbacks

This is a bit more complicated in practice, though in principle is quite straightforward: you create an instance of

a class called AsyncHandlerService linking it to the service you are calling, and a method to be invoked

when that service has finished.page 2

13.2. WSChat with Polling

Since we can't easily use callbacks (or at least we don't have time to built a callback version - and it would be

sufficiently complex that it would not be easy to see what's going on) we will build a polling version instead.

Because the 'built in' mechanisms to handle polling won't work for us, we need to build our own: our client

will simply use a thread to periodically call the service and retrieve any waiting messages. This is not quite as

completely basic as it sounds: the service needs to keep a queue of unretrieved messages for each client. Our

Web Service chat application is less complex than the previous ones, because you're going to build a better one

for your coursework.

13.2.1. The Service

The code for the web service is very simple - though it suffers a serious drawback that would be a problem in a

real application.

  

package wschatserver;

import javax.jws.WebService;

import javax.jws.WebMethod;

import java.util.*;

@WebService

public class ChatServer {

    private static ArrayList<String> serverList = new ArrayList<String>();

    

    @WebMethod

    public int join(){

        synchronized (serverList) {

            int id = serverList.size();

            serverList.add("");

            return id;

        }

    }

    

    @WebMethod

    public void talk(String message){

        synchronized(serverList){

            for(int i = 0;i < serverList.size();i++){

                String val = serverList.get(i) + message;

                serverList.set(i,val);          

            }

        }

    }

    

    @WebMethod

    public String listen(int id) {

        synchronized(serverList){

          String temp = serverList.get(id);

          serverList.set(id,"");

          return temp;

        } 

    }

    

    @WebMethod

    public void leave(int ID){

        /* Do nothing! */

    }page 3

}

·

join. When a new client calls join it is assigned a slot in a (static) ArrayList and its position in that

list becomes its identifier.

·

talk. When a client sends text, that text is added to all the ArrayList elements. Obviously a bit

inefficient since we are copying text - but we do not know when clients will poll to collect messages, so

we cannot just keep one copy.

·

listen. When a client polls to collect messages, all text stored in the ArrayList at the location

corresponding to its identifier is sent back, and then deleted.

·

leave. This currently does nothing - because if we actually deleted elements from the ArrayList we

would mess up the ordering of identifiers - this is obviously a significant disadvantage which we won't

bother to fix here. It's not actually that hard to fix - we just need to 'decouple' client identifiers from their

position in the arraylist. We could do this with an arraylist of objects that include a name as well as the

string of as-yet-unread messages instead of just an arraylist of strings.

Unlike the previous versions, we will not attempt to improve the efficiency of the server by reducing the amount

of synchronized code - though we could if we chose to.

You can download the code.

13.2.2. The Client

The client is very similar to the socket based version (and was edited from that in fact). The only significant

change is that the thread waiting for incoming messages now actively polls the service.

Again you can download the code - the version below leaves out the various GUI bits..

package wschatclient2;

import java.io.*;

import java.net.*;

import javax.swing.*;

import java.awt.event.*;

import java.awt.*;

import javax.xml.ws.WebServiceRef;

import wschatserver2.ChatServer2Service;

import wschatserver2.ChatServer2;

        

public class ChatClient2 {

    @WebServiceRef(wsdlLocation="http://localhost:8080/WSChatServer2/

ChatServer2Service?wsdl")

    

    ...

    

    private ChatServer2Service service;

    private ChatServer2 port;

    private int id;

    private void initComponents(String host) {

     ...

        

        try {

          service = new wschatserver2.ChatServer2Service();

          port = service.getChatServer2Port();

          id = port.join();

          otherTextThread = new TextThread(otherText, id, port);

          

          otherTextThread.start();page 4

          frame.addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {

             try {

                 port.leave(id);

             }

             catch (Exception ex) {

                 otherText.append("Exit failed.");

             }

             System.exit(0);

            }

          });

          

        }

        

        catch (Exception ex) {

            otherText.append("Failed to connect to server.");

        }

    }

    private void textTyped(java.awt.event.KeyEvent evt) {

        char c = evt.getKeyChar();

        if (c == '\n'){

            try {

            String waiting = port.talk(textString,id);

                          otherText.append(waiting + "\n");

            }

            catch (Exception ie) {

             otherText.append("Failed to send message.");

            }

            textString = "";

        } else {

            textString = textString + c;

        }

    }

    

    

    public static void main(String[] args) {

     /*if (args.length < 1) {

      System.out.println("Usage: AppChatClient host");

      return;

     }*/

        //TODO put CLI for host back in

     final String host = "localhost";

     javax.swing.SwingUtilities.invokeLater(new Runnable() {

      ChatClient2 client = new ChatClient2();

      public void run() {

       client.initComponents(host);

      }

     });

     

    }

}

class TextThread extends Thread {page 5

    ObjectInputStream in;

    JTextArea otherText;

    int id;

    ChatServer2 port;

    

    TextThread(JTextArea other, int id, ChatServer2 port) throws

 IOException

    {

        otherText = other;

        this.id = id;

        this.port = port;

    }

    

    public void run() {

        while (true) {

            try {    

                String newText = port.listen(id);

                if (!newText.equals("")) {

                    otherText.append(newText + "\n");

                }

                Thread.sleep(1000);

            }

            catch (Exception e) {

                    otherText.append("Error reading from server.");

                    //return;

            }  

        }

    }

}

When the client starts up, it calls join and gets an ID; when the user types return, it calls talk to send any text

collected; when the window closes it calls leave (even though the service does not handle it, there is no need to

build the client assuming that it doesn't); and the thread TextThread polls the service every second to collect

messages.

13.3. A Slight Improvement

Although the polling is not great, in practice the only place you notice an issue is the delay between typing

some text and its appearance in your own client. We could probably actually extend the polling interval (and

save resources) quite happily except for this. The obvious change to make is to get the talk method to return

any waiting messages - sort of like picking up your mail when you're passing. There are only a few significant

changes to the service and client, which are shown below.

    

    @WebMethod

    public String talk(String message, int id){

        synchronized(serverList){

            for(int i = 0;i < serverList.size();i++){

                String val = serverList.get(i) + message;

                serverList.set(i,val);          

            }      

        }

        return listen(id);

    }

 

And the client:

    private void textTyped(java.awt.event.KeyEvent evt) {page 6

        char c = evt.getKeyChar();

        if (c == '\n'){

            try {

            String waiting = port.talk(textString,id);

                          otherText.append(waiting + "\n");

            }

            catch (Exception ie) {

             otherText.append("Failed to send message.");

            }

            textString = "";

        } else {

            textString = textString + c;

        }

    }

   


相关推荐