Java socket objectoutputstream多线程

时间:2013-04-24 14:58:28

标签: java sockets serversocket objectoutputstream

我得到的代码使用多线程将对象发送到ServerSocket(目前是localy,但将来在本地网络中)

用于发送对象:

public class SocketToAdapter {

public static void writeObject(Object object) {
    try {

        give().writeUnshared(object);

    } catch (IOException e) {
        System.out.println(e.getMessage());
    }
}

static ObjectOutputStream give() {
    Socket s = null;
    try {
        s = new Socket("localhost", 9990);
        s.setTcpNoDelay(true);
        return new ObjectOutputStream(s.getOutputStream());

    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

主要方法:

SocketToAdapter soc = new SocketToAdapter();

    thread1.setSocket(soc);
    thread2.setSocket(soc);
    thread3.setSocket(soc);
    thread4.setSocket(soc);
    thread5.setSocket(soc);

    synchronized (valueExchanging) {
        synchronized (soc) {
            thread1.start();
            thread2.start();
            thread3.start();
            thread4.start();
            thread5.start();
        }

valueExchanging是一个用于交换beetwen线程数据的Object。

从线程运行方法:

public void run() {
    try {
        while (true) {
            curr = new Object(pair, RandomUtil.getRandomExchange(),
                    RandomUtil.getRandomTurn());
            //not important Business Logic.
                            int v1 = valueExchanger.getExchangeInTread()+1;
            int v2 = valueExchanger.getExchangeInTread()-100;
            curr = new Object(pair, BigInteger.valueOf(v1),
                    BigInteger.valueOf(v2));
                            //
            SocketToAdapter.writeObject(curr);
            valueExchanger.setExchangeInTread(v1);
            Thread.sleep(0, 1);
        }
    } catch (InterruptedException iex) {
    }
}

这很有效但很慢。因为我每次需要时都会创建Socket和ObjectOutputStream。我尝试创建一个Socket和一个OOS并像这样使用它:

                   {
        Socket s = new Socket("localhost", 9990);
        ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); }

然后

oos.writeUnshared(object); 
oos.flush(); 
oos.writeUnshared(object);

但如果我第二次尝试重用oos我得到软件导致连接中止:套接字写入错误。无论我使用多少线程。

我需要的是每秒发送许多(例如100k)对象,任何sugesstions的可能性吗?

在服务器端我做:

Serwer.java:

    ServerSocket ss;
public static void pre()throws IOException, ClassNotFoundException {
    ss = new ServerSocket(9990);
    }

public static Object start() throws IOException, ClassNotFoundException {
    Object o = null;
    Socket s = ss.accept(); 
    while (!s.isClosed()) {
        ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
        o = (Object) ois.readObject();
        ois.close();
        s.close(); 
    }
    ss.close();
    return o;

}

“主要方法”

    while (true) { 

            try {
                Serwer.pre();
                Object o = Serwer.start();
                                    //im do somethink with that object o.
            } catch (IOException e1) {
                e1.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

4 个答案:

答案 0 :(得分:1)

在客户端,它为每个发送的对象打开一个新的TCP连接。这会破坏性能,因为建立TCP连接会产生大量开销。

从您的代码中,服务器在处理单个对象后看起来正在关闭连接。在处理单个连接之后它也会关闭ServerSocket,这似乎根本不起作用。提供的服务器代码是否正确?是否在服务器代码中出现了另一个循环,它将启动另一个ServerSocket

最好的方法可能是让每个客户端线程创建自己的Socket,每个客户端都有一个与服务器的单独连接。如果您尝试推送大量数据并使用多个线程来实现这一点,那么服务器很可能需要多个线程来处理数据。这些套接字应该只创建一次并重复使用以发送所有对象。

在服务器端,您将需要创建适当的多线程TCP服务器。这里的一般想法是创建一个SocketServer并在accept()循环中调用其while方法。对于从Socket返回的每个accept(),您将启动一个新线程来处理请求。可以在此处找到一个示例:Multithreaded Server using TCP in Java

答案 1 :(得分:1)

我遇到了同样的问题,并通过为我的套接字使用一个简单的Wrapper-Class来解决它。 该类的对象必须存在于需要读/写操作的任何位置。

public class Sender implements Closeable 
{
  private final Socket sock;
  private final ObjectOutputStream out;
  private ObjectInputStream in = null;

  private final Object oLock = new Object();
  private final Object iLock = new Object();

  //optional
  public boolean isClosed(){
    return sock.isClosed();
  }

  //there is a better way to do this
  public Socket getSocket(){

    return sock;
  }

  //use this to send data
  public void send(Object o) throws IOException {
    synchronized (oLock){
        getOOS().writeObject(o);
    }
  }

  //use this to read data
  public Object get() throws IOException {
    synchronized (iLock){
        return getOIS().readObject();
    }
  }

  private ObjectOutputStream getOOS() {
    return out;
  }

  //not the best way... but wouldn't work otherwise
  private ObjectInputStream getOIS() throws IOException {
    if(in == null)
        in = new ObjectInputStream(sock.getInputStream());
    return in;
  }

  public Sender(Socket s) throws IOException {
    sock = s;
    out = new ObjectOutputStream(s.getOutputStream());
    //in = new ObjectInputStream(s.getInputStream());
    //getting the input and output stream gave me some weird deadlock
  }

  //optional
  @Override
  public String toString() {
    return sock.toString();
  }

  //flush and close if sock is not yet closed
  @Override
  public void close() throws IOException {
    if(!sock.isClosed()){
        if(out != null)
            out.flush();

        sock.close();
    }
  }
}

这个在客户端运行良好(Sender是连接到服务器的Socket)和 server(发件人是连接到客户端的套接字)。

希望这有帮助。

Greets roop

答案 2 :(得分:0)

服务器是在9990读取对象后关闭连接,还是失败?

完成此操作后,您可以使用快速对象序列化程序(如kryo

)查看优化速度序列化

答案 3 :(得分:0)

我没有java套接字的经验,但是通过行s.setTcpNoDelay(true);我认为您的程序正在使用tcp发送数据包,请尝试使用udp。 tcp协议旨在保证数据包到达目的地,为此,它必须在到达时验证完整性。另一方面,udp没有这样做,它只发送数据包而不关心完整性,这就是在线多人游戏使用它的原因。