简体   繁体   中英

Java multi-threaded server-client communication

I'm having a frustrating issue with one problem I'm trying to do in order to prep for an university exam - there should be a bunch of clients accessing a resource through a tcp socket on a separate server, which synchronizes the access. I've got a basic entrypoint class with main essentially instantiating either the clients or the server and a class for the object being serialized and passed through the socket:

DataPacket.class source here:

import java.io.*;
import java.util.Date;

public class DataPacket implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    final public String payload;
    final public String creator;
    final public Date timestamp;

    public DataPacket(String creator, String payload){
        this.creator = creator;
        this.payload = payload;
        this.timestamp = new Date();
    }

}

client.class source here:

import java.io.*;
import java.net.*;
import java.util.Random;

public class client extends Thread implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String name;
    public client(String name){
        this.name = name;
    }
    public void run(){
        try {
            Socket sock = new Socket(InetAddress.getLocalHost(), 12345);
            ObjectInputStream in = new ObjectInputStream(sock.getInputStream());
            ObjectOutputStream out = new ObjectOutputStream(sock.getOutputStream());
            Random rand = new Random();

// obviously the only reason to have this loop here is to initiate a bunch of access 
// requests to the server, but for debugging purposes I've removed the extra cycles
// and stuck to only one;

            for(int i=0; i<1; i++){ 
                DataPacket data = new DataPacket(this.name, Integer.toString(rand.nextInt()));
                out.writeObject(data);
                out.flush();
            }
            sock.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

and finally the server.class source is here:

import java.io.*;
import java.net.*;

public class server extends Thread{
    private int port;
    private DataPacket dp;
    public boolean running=false;

    public void updateData(DataPacket dp){
        this.dp=dp;
    }

    public server(int port){
        this.port = port;
        }

    public void run(){
        this.running = true;
        while (running){
            openSocket();
            }
        }

    public void openSocket(){
        try {
            ServerSocket s = new ServerSocket(this.port, 50, InetAddress.getLocalHost());
            while (true){
                Socket incomming = s.accept();
                ObjectInputStream in = new ObjectInputStream(incomming.getInputStream());
                ObjectOutputStream out = new ObjectOutputStream(incomming.getOutputStream());
                synchronized (dp){
                    while ((dp = (DataPacket) in.readObject()) != null) {
                        System.out.println(dp.creator + "passed a frame @" + dp.timestamp + " :"+dp.payload);
                    } while (in.readObject() == null){
                        Thread.sleep(100);
                        System.out.print(".");
                    }
                }
                s.close();
            }           
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

Now I'm not sure why, but apparently the client requires a input stream defined too (not doing any talk-back from the server to the client, but it blows up with a bunch of refused connection exceptions unless I do declare one. I went on the safe side and declared one output on the server just in case. Unfortunately though it seems that either the client doesn't pass the object through the socket, resp the server doesn't get it, or that I fail somehwere miserably with the serialization and deserialization..

While I'm at it, I'd appreciate a few advises about the synchronization of the data access on the server - will this "synchronised (dp)" do the job, or do I need to put the threads of the clients manually into a wait queue and get one of them manually out with notify() to transmit their serialized data?

Thanks in advance! vlex

Well I spent a few extra days working on it and rewrote it a couple of times and now works. Here's my example of a multithreading-enabled server:

serverentry.class:

package server2;

public class serverentry {

    public static void main(String[] args) {
        server[] serv = new server[10];
        for (int i=0; i<10; i++){
            serv[i] = new server(12345+i);
            serv[i].start();
        }
    }
}

server.class:

package server2;

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

public class server extends Thread implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private int port;
    private static String data = "nothing yet";
    public server(int port){
        this.port = port;
        System.out.println("Server thread["+(this.port-12345)+"] started");
    }

    public void run(){
        try{
            ServerSocket sock = new ServerSocket(this.port, 50, InetAddress.getLocalHost());
            Socket accepted = sock.accept();                
            BufferedReader br = new BufferedReader(new InputStreamReader(accepted.getInputStream()));
            while(br.readLine() !=null){
                synchronized(data){
                    updateData(br.readLine());
                }
                if (br.readLine() == null) break;
            }
            sock.close();
        } catch (Exception e) {
            e.printStackTrace();
        }       
    }

    private void updateData(String streamObj){
        String[] streamArr = streamObj.split("&");
        data = streamArr[1];
        System.out.println("Data updated to "+data+" by "+streamArr[0]+" @ "+ new Date());
    }
}

cliententry.class:

package client2;

public class cliententry {

    public static void main(String[] args) {
        client2[] cli = new client2[10];
        for(int i=0; i<10; i++){
            cli[i] = new client2(i);
            cli[i].start();
        }
    }
}

client2.class:

package client2;

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

public class client2 extends Thread implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String payload;
    private int number; 
    private Random rand;
    public client2(int num){
        rand = new Random();
        this.number = num;
    }

    public void run(){
        try{
            Socket sock = new Socket(InetAddress.getLocalHost(),(12345+this.number));
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
            for (int i=0; i<30; i++){
                String random = Integer.toString(this.rand.nextInt());
                this.payload = "thread[" + this.number + "]&"+random; 
                pw.write(this.payload);
                pw.write("\n");
                pw.flush();
                }
            sock.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Also one of the previous times I rewrote it I used the run() menthod instead of start() which later explained why I got only 3 out of 10 updates or so - the run starts the logic in the same thread, whilst start instantiates another thread. Now it all works as a swiss clock :)

cheers, vlex

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM