我现在正在学习<<java网络编程》,书上有个例子,是做2个线程,一个发送udp包,另一个接收udp包,收发均使用同一个socket,但我一运行就提示:java.net.PortUnreachableException: ICMP Port Unreachable
发送线程类:
package test;import java.net.*;
import java.io.*;public class SenderThread extends  Thread{
    private InetAddress server;
    private DatagramSocket socket;
    private boolean stopped=false;
    private int port;    public SenderThread(InetAddress server, int port) throws SocketException{
        this.server = server;
        this.port = port;
        this.socket=new DatagramSocket();
        this.socket.connect(server,port);
    }    public void halt(){
        this.stopped=true;
    }    public DatagramSocket getSocket(){
        return this.socket;
    }    public void run() {        BufferedReader userInput=new BufferedReader(
                new InputStreamReader(System.in)
        );        try {
            while(true){
                if (stopped){
                    return;
                }
                String theLine=userInput.readLine();
                if (theLine.equals(".")){
                        break;
                }
                byte[] data=theLine.getBytes();
                DatagramPacket output=new DatagramPacket(data,data.length,server,port);
                socket.send(output);
                Thread.yield();
            }
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
}接收线程类:
package test;import java.net.*;
import java.io.*;public class ReceiverThread extends Thread{
    DatagramSocket socket;
    private boolean stopped=false;    public ReceiverThread(DatagramSocket socket) {
        this.socket = socket;
    }    public void halt(){
        this.stopped=true;
    }    public void run() {
        byte[] buffer=new byte[3000];
        while (true){
            if (stopped){
                return;
            }
            DatagramPacket dp=new DatagramPacket(buffer,buffer.length);
            try {
                socket.receive(dp);//异常出现在这行。!!!!!!!!!!!!!!!!
                String s=new String(dp.getData(),0,dp.getLength());
                System.out.println(s);
                Thread.yield();
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }
}调用者:
package test;import java.net.*;
import java.io.*;public class UDPEchoClient {
    public final static int DEFAULT_PORT=7;    public static void main(String[] args) {
        try {
            String hostname="localhost";
            int port;            try {
                port=Integer.parseInt(args[1]);
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                port=DEFAULT_PORT;
            }
            if (args.length>0){
                hostname=args[0];
            }            InetAddress ia=InetAddress.getByName(hostname);
            SenderThread sender=new SenderThread(ia,port);
            sender.start();            Thread receiver=new ReceiverThread(sender.getSocket());
            receiver.start();
        } catch (UnknownHostException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
}

解决方案 »

  1.   

    我运行UDPEchoClient的参数是:localhost 3456
      

  2.   

    ICMP不可达, 可能是你的网络把ICMP屏蔽了, 你可以试一下你的网络是否可以运行ICMP协议.
    还有可能是PORT被屏蔽了.
      

  3.   

    当我们给一个主机发送icmp包时,如果对方的主机不可达,就会返回ICMP Port Unreachable,有两种原因:
    1。你的地址写的不对;
    2。防火墙过滤了某些规则的包;给分
      

  4.   

    to hemiao_1993:
      怎么知道是否可以运行icmp协议,再说我是发给自己,也没有发给别的机器啊。
      

  5.   

    我调试了一下你的程序, 确实有这个错误, 不知道是什么原因. 我另外写了一个两个进程的UDP通信, 是可以实现的. 不知道为什么你那个就会报错.
    你完全是按照书上写的吗? 没有任何改动?
    发送程序:UdpSend.java
    import java.net.*;
    public class UdpSend
    {
    public static void main(String [] args) throws Exception
    {
    DatagramSocket ds=new DatagramSocket();
    String str="hello world";
    DatagramPacket dp=new DatagramPacket(str.getBytes(),str.length(),
    InetAddress.getByName("127.0.0.1"),3000);
    ds.send(dp);
    ds.close();
    }
    }接收程序:UdpRecv.java
    import java.net.*;
    public class UdpRecv
    {
    public static void main(String [] args) throws Exception
    {
    DatagramSocket ds=new DatagramSocket(3000);
    byte [] buf=new byte[1024];
    DatagramPacket dp=new DatagramPacket(buf,1024);
    ds.receive(dp);
    String strRecv=new String(dp.getData(),0,dp.getLength()) +
    " from " + dp.getAddress().getHostAddress()+":"+dp.getPort(); 
    System.out.println(strRecv);
    ds.close();
    }
    }
      

  6.   

    原因已经找到, 是因为收发你共用了同一个Socket, 这是不行的. 当发送线程起来之后, 就把端口占用了, 接收的时候由于用的是同一个Socket, 结果发现端口已经被占用了, 引起了端口不可达的异常, 改动如下后就正常了(为了方便调试我去掉了一些无关的代码):
    import java.net.*;
    import java.io.*;public class SenderThread extends Thread {
    private InetAddress server; private DatagramSocket socket;// private boolean stopped = false; private int port; public SenderThread(InetAddress server, int port) {
    this.server = server;
    this.port = port;
    try {
    this.socket = new DatagramSocket();
    } catch (SocketException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    // this.socket.connect(server, port);
    }/* public void halt() {
    this.stopped = true;
    } public DatagramSocket getSocket() {
    return this.socket;
    }*/ public void run() { BufferedReader userInput = new BufferedReader(new InputStreamReader(
    System.in)); try {
    while (true) {
    /* if (stopped) {
    return;
    }*/
    String theLine = userInput.readLine();
    if (theLine.equals(".")) {
    break;
    }
    byte[] data = theLine.getBytes();
    DatagramPacket output = new DatagramPacket(data, data.length,
    server, port);
    socket.send(output);
    Thread.yield();
    }
    } catch (Exception e) {
    e.printStackTrace(); // To change body of catch statement use
    // File | Settings | File Templates.
    }
    }
    }import java.net.*;
    import java.io.*;public class ReceiverThread extends Thread {
    DatagramSocket socket; private boolean stopped = false; public ReceiverThread() {
    try {
    socket = new DatagramSocket(444);
    } catch (SocketException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    } public void halt() {
    this.stopped = true;
    } public void run() {
    byte[] buffer = new byte[3000];
    while (true) {
    if (stopped) {
    return;
    }
    DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
    try {
    socket.receive(dp);// 异常出现在这行。!!!!!!!!!!!!!!!!
    String s = new String(dp.getData(), 0, dp.getLength());
    System.out.println(s);
    Thread.yield();
    } catch (Exception e) {
    e.printStackTrace(); // To change body of catch statement use
    // File | Settings | File Templates.
    }
    }
    }
    }import java.net.*;
    import java.io.*;public class UDPEchoClient {
    public final static int DEFAULT_PORT = 444; public static void main(String[] args) {
    try {
    String hostname = "localhost";
    int port = DEFAULT_PORT; /*
     * try { port=Integer.parseInt(args[1]); } catch (Exception e) {
     * e.printStackTrace(); //To change body of catch statement use File |
     * Settings | File Templates. port=DEFAULT_PORT; }
     * 
     * 
     * if (args.length>0){ hostname=args[0]; }
     */ InetAddress ia = InetAddress.getByName(hostname);
    SenderThread sender = new SenderThread(ia, port);
    sender.start(); Thread receiver = new ReceiverThread();
    receiver.start();
    } catch (UnknownHostException e) {
    e.printStackTrace(); // To change body of catch statement use
    // File | Settings | File Templates.
    } catch (Exception e) {
    e.printStackTrace(); // To change body of catch statement use
    // File | Settings | File Templates.
    }
    }
    }
      

  7.   

    不对呀,楼上,你的收发socket不都是用的444吗,和我唯一的区别就是创建接收socket的时候没用传过来的发的socket,而是同样用444端口重新创建了一遍,代码和书上一样,书上就这么写的。
      

  8.   

    为什么不可以呢?书上的例子就是用同一个的。难道它错了,作者可是这方面的专家啊。我用是的jdk1.5,难道是jdk的版本问题吗。以前可以,现在不可以了?
      

  9.   

    嘿嘿, 不知道还配叫冷血动物吗? 哈哈, 但是最喜欢的是<永远是个秘密>.
    在CSDN上还能见到摇友, 不容易啊. 缘份啊.不能用一个Socket是我猜的, 具体原因我也不清楚了, 反正既然用两个可以以后记着就用两个就成了.
      

  10.   

    冷血动物的第二张专辑比第一张要好得多,很经典。第一张我买的是录音带,听起来效果也不太好。也许是同一个socket只能用于一种用途吧