MultiClient / Server. Handle communications

2019-09-03 10:23发布

I am suffering with this codes since two days now. In fact I am developping an application which has a server side and the clients side. The server receives request from clients every seconds, treat the request by contacting the database and then send back the result to the client. I do such a way that if the client starts before the server, it will remain trying to connect to the server on the given port and the given host.
1. This is the server side:

try
    {   
        Client client = new Client(jTable1,jLabel3);
        Thread t = new Thread(client);
        t.start();

    }catch(IOException e){}

Class Client.java

public class Client implements Runnable{

private int svrPort = 0;
ServerSocket serverConnect = null;
static  Socket clientSocket = null;
static  ClientConnectThread t[] = new ClientConnectThread[1000];
JTable jtable;
JLabel jlabel;

public Client(JTable table, JLabel label) throws IOException {

    this.svrPort = 9450;
    this.jtable = table;
    this.jlabel = label;

}

public void run(){
    try{
        serverConnect = new ServerSocket(this.svrPort);

    }catch(IOException e){}
    while(true){
        try{
            clientSocket = serverConnect.accept ();
            for(int i=0; i<=1000; i++){ //I can accept up to 1000 clients
        if(t[i]==null)
        {
            (t[i] = new ClientThread(client, t, jtable, jlabel)).start();
                        System.out.println ("Etat12. Apres bloc try");
            break;
        }
    }
        }catch(IOException e){}
    }
}

}

Class ClientThread.java

public ClientThread(Socket socket, ClientThread t[], JTable table, JLabel label){

    this._socket = socket;
    this.jTable = table;
    this.jlabel = label;
    this.totalConnected = 0;       
    this.t = t;
}

public void run(){

    int index = 0;
    try{
        this._output = new PrintWriter(this._socket.getOutputStream ());
        this._input = new BufferedReader(new InputStreamReader(this._socket.getInputStream()));

        while((clientMsg = this._input.readLine ()) != null){
            if(clientMsg.equals ("@CONNECT")){ // If it is the first time the user is signig in, fill the table

                jTable.setValueAt (this._socket.getInetAddress (), index, 0);
                jTable.setValueAt (new Date(), index, 1);
                jTable.setValueAt (new Date(), index, 2);
                totalConnected++;
                jlabel.setText ("");
                jlabel.setText (totalConnected+"");

            }else if(Integer.parseInt (clientMsg) == 1){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByType (1).size () == 0){
                    }
                    _output.println (this.getData.getDataByPeriod (1));
                }else{System.out.println("You are not connected to the database server");}

            }else if(Integer.parseInt (clientMsg) == 2){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByPeriod (2).size () == 0)System.out.println ("There is no data corresponding");
                    this._output.println (this.getData.getDataByPeriod (2));
                }else{System.out.println("You are not connected to the database server");}


            }else if(Integer.parseInt (clientMsg) == 3){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByType (3).size () == 0)System.out.println ("There is no data corresponding");
                    this._output.println (this.getData.getDataByType (30));
                }else{System.out.println("You are not connected to the database server");}


            }else if(Integer.parseInt (clientMsg) == 4){
                int p = Integer.parseInt (clientMsg);
                this._output = new PrintWriter(this._socket.getOutputStream(), true);
                if (this.getData.connect ())
                {
                    if(this.getData.getDataByType (4).size () == 0)System.out.println ("There is no data corresponding");
                    this._output.println (this.getData.getDataByType (60));
                }else{System.out.println("You are not connected to the database server");}


            }else{

            }
        }
        this._input.close ();
        this._output.close ();
    }catch(IOException e){}

}

These are the two classes that make my server running. The class Client.java starts and waits to accept connection. When a client connects an instance of clientThread is created and associated to the client. Till here every thing seems to be working well.

Client side

public class ServerConnect implements Runnable{

public static Socket clientSocket = null;
public static PrintWriter out = null;
public static BufferedReader in = null;
public static int port=9450;
public static String host = "127.0.0.1";
public static JLabel myLabel;
public static JButton button;
public static ResourceMap resourceMap;
private static String serverMsg = "";

public ServerConnect(JLabel jLabel, JButton b)
{
    jLabel.setText ("Trying to contact the server");
    myLabel = jLabel;
    button = b;
    port = Integer.parseInt("9450");
    host = "127.0.0.1";

        try{
            clientSocket = new Socket(host, port);
            }catch(IOException e){e.printStackTrace ();}

}

public void run()
{
    while(true){
        while(!this.connect ())
        {myLabel.setText ("You are not connected to the server : "+host);
         button.setEnabled (false);
            try{
                clientSocket = new Socket(host, port);
            }catch(IOException e){}
        }

        myLabel.setText ("You are connected to the server : "+host);
        button.setEnabled (true);
        try{
           out = new PrintWriter(clientSocket.getOutputStream(), true);
           out.println("@CONNECT");

           in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
           while((serverMsg = in.readLine ()) != null){
                System.out.println ("<=> :"+serverMsg);
           }
        }
        catch(IOException e){e.printStackTrace ();}
    }
}
private boolean connect()
{
    try{
        clientSocket = new Socket(host, port);
        return true;
    }catch(IOException e){}
    return false;
}}

My problem is that when the two sides are starting, the only thing the client sends @CONNECT, the server receives it and all stops here. If the client sends a requests again, the server does not answer.
I would like someone to show me step by step how I can setup this applications
- Server side. Accepts connections in thread with the WHILE loop
- Client side. In another thread to try to contact the server everytime to establish a connection
- In another thread again, client sends request to server
- The server is another thread request the information from the database and sends back to client.

I thank you so much for your help

2条回答
Summer. ? 凉城
2楼-- · 2019-09-03 10:39

Ooohh its a bad idea to put everything onto a low level socket with a PrintWriter etc. I got several encoding and multithreading errors in the past. So my (of course a little bit slower, but easy to use) solution is: Jersey & Grizzly.

The big advantage is: You can modify and extend your transfer objects very easily, without modifying your transport code(the low level socket writing)

An interface...

public interface I_ServiceCommons {
        public static final String  MEDIATYPE           = "text/xml";
        public static final String  MEDIATYPE_ENCODING  = I_ServiceCommons.MEDIATYPE + "; charset=utf-8";
        public static final String SERIVCENAME = "/FUNNY_SERVICE_V001";
    }

The server-side code

@Path(I_ServiceCommons.SERIVCENAME)
public class YourService {

    @POST
    @Produces(I_ServiceCommons.MEDIATYPE)
    @Consumes(I_ServiceCommons.MEDIATYPE)
    public ResultObject request(final RequestObject yourRequest) {
        //process here your request in Server
    }
}

Your Client....

public class abstract YourAbstractClient{
        protected Logger                            log             = Logger.getLogger(this.getClass());
        protected final String                      serviceUrl;
        private final WebResource                   resource;

        public YourAbstractClient(final String url) {
            this.serviceUrl = url + getService();
            this.resource = Client.create().resource(this.serviceUrl);
        }

        public abstract String getService();

        protected <RES, REQ> RES post(final Class<RES> resultClazz, final REQ req) {
            final Builder builder = this.resource.type(I_ServiceCommons.MEDIATYPE).accept(I_ServiceCommons.MEDIATYPE);
            try {
                final RES result = builder.post(resultClazz, req);
                return result;
            } catch (final Exception e) {
                throw new RuntimeException("Error posting data to [" + this.serviceUrl + "]: " + e.getMessage(), e);
            }
        }

    }

Your ServiceClient...

public class Service extends YourAbstractClient {

    public Service(final String url) {
        super(url);
    }

    public MyResult getResult(final MyRequest req) {
        return super.post(MyResult.class, req);
    }

    @Override
    public String getService() {
        return I_ServiceCommons.SERIVCENAME;
    }
}

Your TransferObjects

@XmlRootElement
public class MyRequest implements Serializable {
    public void setRequestType(final int p_AequestType) {
        this.requestType = p_AequestType;
    }

    public int getRequestType() {
        return this.requestType;
    }
}

And the end...

String url = "http://127.0.0.1";
GrizzlyServerFactory.create(url) //starts the server
MyRequest res = new MyRequest();
MyResult result = new Service(url).getResult(req); // Corrected
查看更多
我想做一个坏孩纸
3楼-- · 2019-09-03 10:45

It's quiet simple - but the underlaying technology is complex. ;) I explain it in the reverse order (of my answer @ https://stackoverflow.com/a/11625335/1268954).

In the main code you start the Grizzlyserver with GrizzlyServerFactory.create(url), which listens on "127.0.0.1".

When the Server starts, it searches for classes with an Annotation @Path ... and find "YourService".

So Grizzly will "register" (or something like that) the ServiceClass "YourService" on url "http://127.0.0.1/FUNNY_SERVICE_V001" (see I_ServiceCommons).

Well.. we're in the main code again. We create a MyRequest Object and create an instance of the concrete service "Service". A much better name should be "ServiceClient", because its the code on client side. The "Service" is created with the url ("http://127.0.0.1") and steps into the common constructor code (for all clients) in YourAbstractClient and creates the service-url "http://127.0.0.1/FUNNY_SERVICE_V001" . Inside YourAbstractClient a Client Object (for connection/encoding handling etc.) will be created. When we want to access the Server, we only have to put the MyRequest object into the "getResult" method of the "Service". The client inside YourAbstractClient converts the MyRequest object into an XML Reresentation (notice the @XMLRootElement Annotation, parameterless Constructor and set/get Methods in it) doing a HTTP POST to the server, which recreate a MyRequest Object.

So on the server side again... So when a client connect to "http://127.0.0.1/FUNNY_SERVICE_V001" in the right way, the server create an instance of YourService (parameterless constructor needed) and read the xml, create the transferobject MyRequest and put it into the method public ResultObject request(final RequestObject yourRequest), because its annotated with the @POST Annotation (in the client we do HTTP-POST). You can process your MyReqeust Object an have to return a MyResult object, wich will converted to xml, sent, recieved by the client and recreated to a MyResult object. Thats it.

查看更多
登录 后发表回答