【问题标题】:Java socket objectoutputstream multi-threadJava socket objectoutputstream 多线程
【发布时间】:2013-04-18 04:49:25
【问题描述】:

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

用于发送对象:

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();
        }

valueExchang 是一个对象,用于在线程之间交换数据。

从线程运行方法:

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)对象的可能性,有什么建议吗?

在服务器端我做:

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();
            }
        }

【问题讨论】:

  • 启动线程时为什么要在soc上同步?当使用来自多个线程的资源时,您必须在资源上进行同步。并保持同步块简短。或者甚至尝试在没有的情况下相处。同步是一个巨大的性能杀手。
  • 目前同步不是问题(即使我使用一个没有同步的线程,性能很差)。
  • 你必须为你的设计带来更多的结构。无意冒犯,但尽量不要在一个地方做太多事情......

标签: java sockets serversocket objectoutputstream


【解决方案1】:

在客户端中,它为每个发送的对象打开一个新的 TCP 连接。这会降低性能,因为建立 TCP 连接需要大量开销。

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

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

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

【讨论】:

  • 我叫“主方法”有一个循环
  • 你知道你可以只循环accept()而不是整个serversocket创建吗?您甚至可以同时处理多个连接,为您在下一次接受时获得的每个 Socket 生成一个线程 ...
【解决方案2】:

我遇到了同样的问题,并通过对我的套接字使用简单的 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)和 服务器(Sender 是连接到客户端的 Socket)。

希望这会有所帮助。

向你问好

【讨论】:

    【解决方案3】:

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

    整理完这个之后,你可以看看使用像kryo这样的快速对象序列化器来优化速度序列化

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      猜你喜欢
      • 2011-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-22
      • 2017-04-29
      • 2015-11-17
      • 2021-05-30
      • 1970-01-01
      相关资源
      最近更新 更多