使用java中的套接字在客户端和服务器之间交换对象

时间:2013-07-02 20:09:31

标签: java sockets objectinputstream objectoutputstream

我正在尝试构建一个应用程序,其中服务器是银行,客户端是该银行的bracnhs,因此它是经典的多线程服务器/客户端应用程序。在第一步中,我希望银行记录连接到它的每个分支。所以我想将branck作为对象发送到套接字的对象流中,以便银行可以提取并记录它。

这是我到目前为止所做的事情

import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


public class Banque {
private List<Succursale> listSucc = new ArrayList<Succursale>();
private int sommeTotale;
private int nbSuccInit = 4;

public void ajouteSucc(Succursale suc){

}
public Banque(){
    initialiserServeur();       
}
private void initialiserServeur() {
    ServerSocket serverSocket = null; 
    try { 
        serverSocket = new ServerSocket(10118); 
    } 
    catch (IOException e) 
    { 
        System.err.println("On ne peut pas ecouter au  port: 10118."); 
        System.exit(1); 
    }
    System.out.println ("Le serveur est en marche, Attente de la connexion.....");
    int i = 0;
    while(i<5){
        try {
            UtilMultiTh mt = new UtilMultiTh(serverSocket.accept());
            Thread t = new Thread(mt);
            t.start();
            listSucc.add(mt.getSuc());
            System.out.println(listSucc.size());

            for(int j =0; j<listSucc.size();j++){
                System.out.println("La succursale "+(j+1)+" est:"+listSucc.get(j).getName());
            }
            i++;
            System.out.println("FLAGPOSTban");
        } 
        catch (IOException e) 
        { 
            System.err.println("Accept a echoue."); 
            System.exit(1); 
        } 
    }


    System.out.println ("connexion reussie");
    System.out.println ("Attente de l'entree.....");

}
public static void main (String [] args){
    Banque banK = new Banque();
}

}

管理分支的多线程连接的类MultiTh

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.*;

public class UtilMultiTh implements Runnable {

private Socket soc;
private Succursale suc;
public UtilMultiTh(Socket s){
    System.out.println("FLAGconsmth");
    this.soc = s;
    }
public void run() {
    System.out.println("FLAGPOSrun");
    ObjectOutputStream oos;
    ObjectInputStream ois;
    try{            
        oos = new ObjectOutputStream(soc.getOutputStream());
        ois = new ObjectInputStream(soc.getInputStream());

        //System.out.println("La succ est");
        try {
            Object o = ois.readObject();
            if(o!=null){
                suc = (Succursale)o;
                //System.out.println("La succ est"+suc.getName());
            }
            /*while(o!=null){
                suc = (Succursale)o;
                System.out.println("La succ est"+suc.getName());
            }*/
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        oos.close();
        ois.close();
        soc.close();
    } catch (IOException e1) {
        e1.printStackTrace();
    } 
}
public synchronized Succursale getSuc() {
    return suc;
}
public void setSuc(Succursale suc) {
    this.suc = suc;
}

}

这是分支的Succursale类

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

public class Succursale implements Serializable {
private String coordonnees;
private String name;
private int sommeDepart;
private int sommeRecue;
private int sommeEnvoyee;
private List<Succursale> listSuccAc = new ArrayList<Succursale>();
private GuiSuccursale succView;

public Succursale (){
    succView = new GuiSuccursale(Constantes.sommeDepart,1);
    this.sommeDepart=Constantes.sommeDepart;
    this.name="Succursale: "+(1);
    connexionBanque();
}
public void connexionBanque(){
    String host = Constantes.adrBanque[0];
    int port = Constantes.portBanque[0];
    Socket echoSocket = null;
    try {
        echoSocket = new Socket(host, port);
        ObjectOutputStream oos = new ObjectOutputStream(echoSocket.getOutputStream());
        oos.writeObject(this);
        System.out.println("FLAGPOSTSUcc");
    } catch (UnknownHostException e) {
        System.err.println("Hôte inconnu: " + host);
        System.exit(1);
    } catch (IOException e) {
        e.printStackTrace();
        System.err.println("Ne pas se connecter au serveur: " + host);
        System.exit(1);
    }
}
public void connexionSuccursales(){

}
public void envoiManuel(){

}
public String getName() {
    return name;
}
public void envoiPeriodique(){

}
public static void main (String[] args){
    Succursale suc = new Succursale();
}
}

我有两个问题,我怎么能从UtilMultuTh返回一个Succursale到Banque,之前为什么在UtilMultiTh类readObject中返回null而在succursale类中刚刚建立连接之后我把类放在socket中?我必须在这里放一个无限循环吗?

编辑:我改变了代码,现在multith正确地从套接字中获取Succursale,现在的问题是线程没有同步,因为在Banque想要得到它之后,UtilMultiTh得到了Succursale,我不熟悉synchrnosation,如何在utilMultiTh执行其运行后告诉Banque执行getSuccursale?

2 个答案:

答案 0 :(得分:0)

谷歌的protobufs非常适合这一点。我建议使用它们并在客户端和服务器之间发送字节输出。如果您计划使用TCP,则需要对输出进行构图。

Java的序列化机制总是可以在不同的运行时版本之间中断。此外,如果您决定使用其他语言实现服务器或客户端,该怎么办?您将不得不复制java的整个序列化逻辑。 Protobuf负责将对象与字节进行编组和解组所需的繁琐过程。所以,它是一种更好的java内置序列化形式,与语言无关。

所以我建议你放弃对象流。我知道这不是你所希望的答案,但从长远来看,它会让你更好。

ProtoBuffers

答案 1 :(得分:0)

这不是你问题的答案,但它不适合评论,我认为需要说。

确保在每次写入后重置输出流! ObjecdtOutputStream只写一次对象。如果你再次尝试写它,它只会发送一个小音符“把我刚刚发送的那个对象放回输入流中。”节省空间,但如果您的对象已更改,则这些更改将无法通过。此外,发送的原始对象将被保存在内存中,从而导致您的性能下降。重置可以清除所有内容并为您提供一个全新的开始。

另外,我使用的是Externalizable而不是Serializable。这使您可以控制发送的内容(尽管您必须编写一些代码)。如果你编写一个引用其他对象的对象,它会写出所有其他对象,这可能是你不想要的。此外,Externalizable允许您写入相同的旧格式,即使类更改。此外,它允许您输入版本号。这些有时可以允许较新版本读取旧版本编写的流,但它总是会向您发出格式已更改的警告。

ObjectOutputStream的目的是您可以编写一个包含所有数据的对象。只需一次调用writeObject即可发送真正庞大的图形。这是巧妙的。它对我来说很好,将计算机游戏的完整状态写入一个writeObject( this )的磁盘文件,但写入套接字通常是一个灾难。

我有点倾向于不使用ObjectOutput,而只是编写基元。它更简单,更快速,你有很多控制权。但是我无法知道在Input端创建哪个对象。我认为最好的做法是读取和写入对象,但是通过为Externalizable接口编写自己的方法并在每个reset()之后调用writeObject来保持I / O简单。