2013-12-01 3 views
0

Есть два компьютера, A и B, каждый из которых ждет другого, чтобы сообщить ему, что он готов, когда они получают сообщение, что они начнут что-то делать.Java Socket не работает в локальной сети

public class SyncClientImpl implements SyncClient, Runnable { 

private Socket s; 
private String ipAddress; 
private int port; 
private boolean otherIsReady; 
private Thread thread; 
private OutputStream os; 
private ObjectOutputStream oos; 

public Thread getThread() { 
    return thread; 
} 

public void setThread(Thread thread) { 
    this.thread = thread; 
} 

public void start() { 
    thread = new Thread(this); 
    thread.start(); 
} 

public boolean isOtherIsReady() { 
    return otherIsReady; 
} 

public void setOtherIsReady(boolean otherIsReady) { 
    this.otherIsReady = otherIsReady; 
} 

public Socket getS() { 
    if (s == null) { 
     try { 
      s = new Socket(ipAddress, port); 
     } catch (UnknownHostException ex) { 
      Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IOException ex) { 
      Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
    return s; 
} 

public void setS(Socket s) { 
    this.s = s; 
} 

public String getIpAddress() { 
    return ipAddress; 
} 

public void setIpAddress(String ipAddress) { 
    this.ipAddress = ipAddress; 
} 

public int getPort() { 
    return port; 
} 

public void setPort(int port) { 
    this.port = port; 
} 

@Override 
public void send(Object o, int port, String ipAdrress) { 
    try { 
     os = this.getS().getOutputStream(); 
     oos = new ObjectOutputStream(os); 
     oos.flush(); 
     oos.writeObject(o); 
     oos.flush(); 
    } catch (IOException ex) { 
     Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

@Override 
public void update() { 
    otherIsReady = true; 
} 

@Override 
public void run() { 
    try { 
     while (!otherIsReady) { 
      try { 
       this.send("ready", port, ipAddress); 
       Thread.sleep(500); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
     oos.close(); 
     os.close(); 
     s.close(); 
    } catch (IOException ex) { 
     Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 
} 

Этот первый класс отправляет сообщение «готов» к серверу, он прекратит это делать, пока кто-то еще не уведомит об этом. Класс, который уведомит его это одна:

public class SyncServerImpl implements SyncServer, Runnable { 

private ServerSocket ss; 
private Socket s; 
private String ipAddress; 
private int port; 
private InputStream is; 
private ObjectInputStream ois; 
private boolean confirmReceived; 
private Thread thread; 
private transient List<Observer> list = new ArrayList<Observer>(); 
private Object lock; 

public boolean isConfirmReceived() { 
    return confirmReceived; 
} 

public void setConfirmReceived(boolean confirmReceived) { 
    this.confirmReceived = confirmReceived; 
} 

@Override 
public void setLock(Object lock) { 
    this.lock = lock; 
} 

public void start() { 
    thread = new Thread(this); 
    thread.start(); 
} 

public Socket getS() { 
    if (s == null) { 
     try { 
      s = this.getSS().accept(); 
     } catch (UnknownHostException ex) { 
      Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IOException ex) { 
      Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
    return s; 
} 

public void setS(Socket s) { 
    this.s = s; 
} 

public String getIpAddress() { 
    return ipAddress; 
} 

public void setIpAddress(String ipAddress) { 
    this.ipAddress = ipAddress; 
} 

public int getPort() { 
    return port; 
} 

public void setPort(int port) { 
    this.port = port; 
} 

public ServerSocket getSS() { 
    if (ss == null) { 
     try { 
      ss = new ServerSocket(port); 
     } catch (IOException ex) { 
      Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
    return ss; 
} 

public void setSS(ServerSocket ss) { 
    this.ss = ss; 
} 

@Override 
public void addObserver(Observer observer) { 
    list.add(observer); 
} 

@Override 
public void removeObserver(Observer observer) { 
    list.remove(observer); 
} 

@Override 
public void notifyObservers() { 
    for (Observer observer : list) { 
     observer.update(); 
    } 
} 

public void receive() { 
    try { 
     is = this.getS().getInputStream(); 
     ois = new ObjectInputStream(is); 
     String to = (String) ois.readObject(); 
     if (to.equalsIgnoreCase("ready")) { 

      synchronized (lock) { 
       confirmReceived = true; 
       this.notifyObservers(); 
       lock.notifyAll(); 
      } 
      System.out.println("packet received"); 

     } 
    } catch (IOException ex) { 
     Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (ClassNotFoundException ex) { 
     Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

@Override 
public void run() { 
    try { 
     while (!confirmReceived) { 
      this.receive(); 
     } 
     ois.close(); 
     is.close(); 
     s.close(); 
     ss.close(); 
    } catch (Exception ex) { 
     Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

public static void main(String args[]) { 
    final Object lock = new Object(); 
    SyncServerImpl ss = new SyncServerImpl(); 
    SyncClientImpl sc = new SyncClientImpl(); 
    ss.setLock(lock); 
    ss.addObserver(sc); 
    ss.setPort(2002); 
    ss.start(); 


    sc.setIpAddress("192.168.1.101"); 
    sc.setPort(2002); 
    sc.start(); 

    synchronized (lock) { 
     while (!ss.isConfirmReceived()) { 
      try { 
       lock.wait(); 
      } catch (InterruptedException ex) { 
      } 
     } 
    } 

    System.out.println("Ok"); 
} 
} 

Этот сервер ожидает сообщение «готового», чтобы прибыть, когда он приходит он уведомляет об этом другом классе, который прекратит отправку пакетов, и уведомляет об этом основной поток, ожидающий блокировки. Он отлично работает на локальном хосте, но не в моей локальной сети. У меня есть mac и pc, если я начинаю основной метод сначала с компьютера, а затем с mac, я получаю эту ошибку (от mac, которая будет итерировать бесконечно).

sync.SyncClientImpl send 
GRAVE: null 
java.net.SocketException: Broken pipe 
at java.net.SocketOutputStream.socketWrite0(Native Method) 
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92) 
at java.net.SocketOutputStream.write(SocketOutputStream.java:136) 
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1864) 
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1773) 
at java.io.ObjectOutputStream.<init>(ObjectOutputStream.java:229) 
at tetris.logic.online.sync.SyncClientImpl.send(SyncClientImpl.java:87) 
at tetris.logic.online.sync.SyncClientImpl.run(SyncClientImpl.java:106) 
at java.lang.Thread.run(Thread.java:695) 

в то время как на компьютере он сообщает мне, что соединение будет отказано (но это нормально, потому что он начинает первый)

Если я начну первым на макинтоше и на компьютере, я получаю эту ошибку (с компьютера), который будет итерацию до бесконечности тоже:

sync.SyncClientImpl send 
GRAVE: null 
java.net.SocketException: Software caused connection abort: socket write error 
... 
at tetris.logic.online.sync.SyncClientImpl.send(SyncClientImpl.java:87) 
at tetris.logic.online.sync.SyncClientImpl.run(SyncClientImpl.java:106) 
at java.lang.Thread.run(Thread.java:695) 

Эта ошибка выглядит таким же, одного выше, но описано в другом порядке.

Кто-нибудь знает, что вызывает эту ошибку?

+0

Не создавайте новый 'ObjectOutputStream' для каждой отправки. Создайте его один раз для жизни сокета. Тоже 'ObjectInputStream.' – EJP

ответ

0

Попробуйте упростить свое решение и взгляните на следующую статью о программировании сокетов: Writing the Server Side of a Socket.

Попробуйте сделать это в одностороннем порядке, прежде чем пытаться сделать это в обоих направлениях (хотя потребность в этой функции мне не совсем понятна). Сейчас клиентские потоки сервера & в тех же приложениях мешают паре клиент/сервер, которую вы пытаетесь настроить по сети.

Если вы хотите отправлять текст только через сокет, используйте BufferedReader и PrintWriter вместо ObjectStreams (последний может вызвать проблемы с памятью, если не будет правильно управляться).

@Override 
public void send(String line, int port, String ipAdrress) { 
    try { 
     Socket clientSocket = new Socket(ipAddress, port); 
     os = clientSocket.getOutputStream(); 
     PrintWriter out= new PrintWriter(os, true); 
     out.println(line); 
     out.close(); 
     clientSocket.close(); 
    } catch (IOException ex) { 
     Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

Если вы хотите использовать только соединение для проверки, если другой готов, чем закрытие сокета в порядке, но если вы хотите сохранить связь открыть вам нужно держать OutputStream (а не гнездо сам) для дальнейшей обработки в потоке. Опять же, взгляните на статью выше и оттуда.

Смежные вопросы