Socket编程java.net.BindException: Address already in use: JVM_Bind

Socket编程java.net.BindException: Address already in use: JVM_Bind

问题描述:

本人最近想学Socket编程:无奈遇到个问题.不知道是啥原因,还请各位不吝赐教.
问题是这样的:我想用Socket在服务端读取文本文件,第一次运行的时候,什么都没数出来,(不停止第一次开启的服务)第二次输出了文本内容,却报了个地址被占用的错.这是为什么呢?
Socket客户端:
package socket;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;

public class socketClient {
private String ip;
public socketClient() {
// TODO Auto-generated constructor stub
}
public socketClient(String ip){
this.ip=ip;
}
public void client(){
PrintWriter print=null;
BufferedReader read=null;
File file=null;
try {
Socket ket=new Socket(ip,9000);//与服务器取得链接.
file=new File("e:\我的地址.txt");
read=new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String readLine=null;
print=new PrintWriter(ket.getOutputStream(),true);
while((readLine=read.readLine())!=null){
print.print(readLine);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
read.close();
print.close();

        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

}

Socket服务器:
package socket;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class SocketRemot {
private Map map=new HashMap();
public void reMoteRun(){
BufferedReader read=null;
PrintWriter write=null;
try {
while(true){
ServerSocket soc=new ServerSocket(9000);//为服务器Socket指定端口
Socket socket=soc.accept();//服务器端阻塞,一直等待客户端来访问.
map.put(socket.getPort()+"",socket);
System.out.println("我在等待.......");
//读取客户端文件.
//得到socket读取文件的流//字节流
/*
* InputStream是用于读取二进制文件的流,而服务器端读取的文件很有可能是文本形式的.所以要转换为字符流
* 字节流和字符流之间的转换通过InputStreamReader,和OutputStreamWrite来转换.
*/
read=new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取读文件的字符流
write=new PrintWriter(socket.getOutputStream(),true);//通过现有的output流来创建新的printWrite流
System.out.println(read.readLine());
// String str=null;
// while((str=read.readLine())!=null){
// System.out.println(read.readLine());//边读边写.
// }
// write.close();
// read.close();
// socket.close();

        }


    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        try {
            if(read!=null){
                read.close();
            }
            if(write!=null){
                write.close();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

public void closeSocket(){
    Iterator tor=map.values().iterator();
    while(tor.hasNext()){
        Socket soc=(Socket)tor.next();
        if(!soc.isClosed()){
            try {
                soc.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

}

Test:
package socket;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Test {
public static void main(String[] args) {
SocketRemot remot=new SocketRemot();
socketClient ket=new socketClient(getAddIp());
remot.reMoteRun();
ket.client();
remot.closeSocket();

}

public static String getAddIp(){
 String serverIp=null;
   try {
    serverIp = InetAddress.getLocalHost().toString();
    serverIp = serverIp.substring(serverIp.indexOf("/")+1);
    System.out.println(serverIp);
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } 
    return serverIp;

}
}

error:
java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(Unknown Source)
at java.net.AbstractPlainSocketImpl.bind(Unknown Source)
at java.net.PlainSocketImpl.bind(Unknown Source)
at java.net.ServerSocket.bind(Unknown Source)
at java.net.ServerSocket.(Unknown Source)
at java.net.ServerSocket.(Unknown Source)
at socket.SocketRemot.reMoteRun(SocketRemot.java:25)
at socket.Test.main(Test.java:10)

[quote],(不停止第一次开启的服务)第二次输出了文本内容,却报了个地址被占用的错.这是为什么呢?[/quote]
你启动第一个,就占用了你的端口,然后再启动,又用了这个端口,所以会错了啊。

就比如你用tomcat的时候,你启动一次,第二次启动,就报你jvm 8080重复的错误是吧。不懂的站内问我吧。

因为你第一次启动的时候,一个socket已经使用了这个端口,而且没有被正常关闭,所以,在你再次启动的时候,它当然就 in use 了啊

不停止第一次开启的服务,那么9000端口一直被占用了,后续再启动一个还想使用这个端口当然不行了

SocketRemot remot=new SocketRemot();
socketClient ket=new socketClient(getAddIp());

你怎把服务和客户端放到同一个main方法里

[quote]第一次的时候端口没有被占用,为什么内容没有数出来呢。第二次端口占用了,内容却数出来了。这是为什么呢? [/quote]
这是因为你没有调用 flush()。在你的[quote]while((readLine=read.readLine())!=null){
print.print(readLine);
} [/quote]
这个 while() 外面加上
[code="java"]print.flush()[/code]试试

你在[quote]while((readLine=read.readLine())!=null){
print.print(readLine);
} [/quote]的while处打个断点,然后debug一下,看看第一次到底有没有执行到这个地方

[quote]public static void main(String[] args) {
SocketRemot remot=new SocketRemot();
socketClient ket=new socketClient(getAddIp());
remot.reMoteRun();
ket.client();
remot.closeSocket();

} [/quote]
你不这样弄啊,你用两个工程分别启动啊,别一起启动啊。你先启动你的服务器SocketRemot,然后在另外的工程,编写client,并且启动。

[quote]运行到这一句就没了下文。是不是Socket服务端压根就没检测到有客户端在访问啊?到底是哪有问题呢。[/quote]
我刚才说了哦,你先启动服务器端,然后再启动客户端。

[quote]public static void main(String[] args) {
SocketRemot remot=new SocketRemot();
socketClient ket=new socketClient(getAddIp());
remot.reMoteRun();
ket.client();
remot.closeSocket();

} [/quote]

问题就在这了。这样写是不行的。解决有两个:
① 起两个线程分别启动 SocketRemot 和 socketClient
② 新建两个工程,把 SocketRemot 和 socketClient 放在不同的工程中启动(SocketRemot 要先启动)
这样就应该可以了