0

我有使用多线程将对象发送到 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)对象的可能性,有什么建议吗?

在服务器端我做:

服务器.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

4 回答 4

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)和服务器(Sender 是连接到客户端的 Socket)中运行良好且快速。

希望这可以帮助。

问候圈

于 2013-09-02T16:41:07.080 回答
1

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

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

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

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

于 2013-04-24T16:19:45.293 回答
0

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

于 2013-04-24T16:34:28.017 回答
0

您在 9990 的服务器是否在读取对象后关闭连接,或者它是否失败?

整理好之后,可以看看使用快速对象序列化器(如kryo )优化速度序列化

于 2013-04-24T15:27:31.163 回答