2013-04-24 47 views
0

心中已经得到了其使用多线程发送对象ServerSocket的代码(目前localy,但在本地网络的未来)Java的插座ObjectOutputStream的多线程

用于发送对象:

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线程交换数据的对象。

从线程运行方法:

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

为什么在启动线程时同步soc?当使用来自多个线程的资源时,您必须在资源上进行同步。并保持同步块的简短。甚至不尝试相处。同步是一个巨大的性能杀手。 – Fildor 2013-04-24 15:07:21

+0

目前不是同步问题(即使我使用一个没有同步的线程,性能很糟糕)。 – user1055201 2013-04-24 15:12:46

+0

你一定要为你的设计带来更多的结构。没有冒犯,但尽量不要在一个地方做太多事情...... – Fildor 2013-04-24 17:12:42

回答

0

你是否在9990服务器读取对象后,关闭连接,或它失败了吗?

在此之后整理出来,你可以看看利用快速的对象序列化一样kryo

1

在它的开放为发送每个对象一个新的TCP连接的客户端优化速度系列化。这会导致性能下降,因为建立TCP连接需要大量开销。

从您的代码看,服务器看起来像是在处理完一个对象后关闭连接。在处理一个似乎完全不起作用的连接后,它也关闭了ServerSocket。服务器代码是否正确?服务器代码中是否有另一个循环会启动另一个ServerSocket

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

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

+0

我称之为“主要方法”有一个循环 – user1055201 2013-04-24 17:03:39

+0

你知道你可以循环接受accept()而不是整个serversocket创建?你甚至可以处理多个连接simultanoulsy产生一个线程为每个插座,你可以通过下一个接受... – Fildor 2013-04-24 17:08:18

0

我没有经验的java套接字,但由行s.setTcpNoDelay(true);我假设你的程序使用tcp发送数据包,请尝试使用udp。 tcp协议是为了保证数据包到达目的地,并且要做到这一点,一旦它们到达,它必须验证完整性。另一方面udp不会这样做,它只发送数据包而不关心完整性,这就是为什么在线多人游戏使用它。

+0

我如何使用UDP而不是TCP? – user1055201 2013-04-24 17:02:10

+0

@ user1055201这是一个完全不同的故事。也许这会有所帮助:http://systembash.com/content/a-simple-java-udp-server-and-udp-client/ – Fildor 2013-04-24 17:06:23

1

我有同样的问题,并通过使用一个简单的包装类为我的套接字解​​决了它。 此类的对象必须存在于需要读/写操作的任何点。

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是连接到服务器的插槽)和 服务器(发件人是连接到客户端的套接字)。

希望这会有所帮助。

Greet roop