Java Socket无法在LAN上运行

时间:2013-12-01 19:52:59

标签: java multithreading sockets synchronization

有两台计算机,A和B,每一台计算机都在等待另一台计算机告诉他已做好准备,当他们收到消息时他们会开始做某事。

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

此第一类将消息“ready”发送到服务器,它将停止执行,直到其他人通知它。 将通知它的类是这样的:

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

此服务器正在等待“准备好”消息到达,当它到来时它将通知将停止发送数据包的其他类,并将通知等待锁定的主线程。 它在localhost上运行正常但在我的LAN上运行不正常。 我有一台Mac和一台电脑,如果我首先从电脑上启动主要方法,然后从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)

虽然在PC上它报告我连接被拒绝(但它没关系,因为它首先启动)

如果我首先在mac和PC上启动,我会收到这个错误(来自电脑),它也会无休止地迭代:

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)

此错误看起来与上面的错误相同,但以不同的方式描述。

有人知道导致此错误的原因吗?

1 个答案:

答案 0 :(得分:0)

尝试简化您的解决方案,并查看以下有关套接字编程的文章:Writing the Server Side of a Socket

尝试在双向尝试之前先使其工作(尽管我对此功能的需求并不十分清楚)。现在客户&amp;同一应用程序中的服务器线程正在干扰您尝试通过网络设置的客户端/服务器对。

如果您只想通过套接字发送文本,请使用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);
    }
}

如果您只想使用连接来检查另一个是否准备好比关闭Socket还可以,但是如果您想保持连接打开,则需要保持OutputStream(而不是Socket本身)以进一步线程中的处理。再次,看看上面的文章并从那里开始工作。