[英]java.net.BindException: Address already in use: Cannot bind
對不起,我已經搜索了但似乎所有答案都沒有解決我的問題。 嘗試創建ServerSocket以回復多個客戶端消息時出現此錯誤。
我的服務器代碼:
package Server;
import java.net.*;
import java.io.*;
public class Server {
public final static int defaultPort = 7;
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(defaultPort);
int i = 0;
while (true) {
try {
System.out.println("Server is running on port "
+ defaultPort);
Socket s = ss.accept();
System.out.println("Client " + i + " connected");
RequestProcessing rp = new RequestProcessing(s, i);
i++;
rp.start();
} catch (IOException e) {
System.out.println("Connection Error: " + e);
}
}
} catch (IOException e) {
System.err.println("Create Socket Error: " + e);
} finally {
}
}
}
class RequestProcessing extends Thread {
Socket channel;
int soHieuClient;
public RequestProcessing(Socket s, int i) {
channel = s;
clientNo = i;
}
public void run() {
try {
byte[] buffer = new byte[6000];
DatagramSocket ds = new DatagramSocket(7);
while (true) {
DatagramPacket incoming = new DatagramPacket(buffer,
buffer.length);
ds.receive(incoming);
String theString = new String(incoming.getData(), 0,
incoming.getLength());
System.out.println("Client " + clientNo
+ " sent: " + theString);
if ("quit".equals(theString)) {
System.out.println("Client " + clientNo
+ " disconnected");
ds.close();
break;
}
theString = theString.toUpperCase();
DatagramPacket outsending = new DatagramPacket(
theString.getBytes(), incoming.getLength(),
incoming.getAddress(), incoming.getPort());
System.out.println("Server reply to Client "
+ clientNo + ": " + theString);
ds.send(outsending);
}
} catch (IOException e) {
System.err.println(e);
}
}
}
和我的客戶代碼:
package Client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
public class Client extends Object {
public final static int serverPort = 7;
public static void main(String[] args) {
try {
DatagramSocket ds = new DatagramSocket();
InetAddress server = InetAddress.getByName("192.168.109.128");
Socket s = new Socket("192.168.109.128", 7);
String theString = "";
do {
System.out.print("Enter message: ");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
theString = br.readLine();
byte[] data = theString.getBytes();
DatagramPacket dp = new DatagramPacket(data, data.length,
server, serverPort);
ds.send(dp);
System.out.println("Sent to server server: " + theString);
byte[] buffer = new byte[6000];
DatagramPacket incoming = new DatagramPacket(buffer,
buffer.length);
ds.receive(incoming);
System.out.print("Server reply: ");
System.out.println(new String(incoming.getData(), 0, incoming
.getLength()));
} while (!"quit".equals(theString));
s.close();
} catch (IOException e) {
System.err.println(e);
}
}
}
通過第一個客戶端連接,它可以順利運行。 但是從第二個客戶端,它拋出java.net.BindException:地址已經在使用:無法綁定。 第二個客戶端也可以發送和接收消息,但客戶端號仍為0。
Server is running on port 7
Client 0 connected
Server is running on port 7
Client 0 sent: msg 0
Server reply to Client 0: MSG 0
Client 1 connected
Server is running on port 7
java.net.BindException: Address already in use: Cannot bind
Client 0 sent: msg 1 <<-- this one is sent from client 1 but Client No is 0
Server reply to Client 0: MSG 1
因此,在RequestProcessing.run
您決定忽略在構造函數中接收的套接字,並在與您正在偵聽的端口相同的端口上打開DatagramSocket。 你期望它會發生什么?
class RequestProcessing extends Thread {
Socket channel;
int soHieuClient;
public RequestProcessing(Socket s, int i) {
// *****************
// The processor should be using this socket to communicate
// with a connected client *using TCP Streams*
channel = s;
clientNo = i;
}
public void run() {
try {
byte[] buffer = new byte[6000];
// *****************************
// But, instead of using the this.channel, your code
// decides to ignore the TCP socket,
// then open another UDP *"server-side like"* socket.
// First time it's OK, but the second thread attempting
// to open another DatagramSocket on the same port will fail.
// It's like attempting to open two TCP ServerSockets on the
// same port
DatagramSocket ds = new DatagramSocket(7);
[額外]
你需要決定你將使用什么協議:如果你使用ServerSocket
/ Socket
對,那么你可能需要TCP通信,所以沒有DatagramSocket
。
如果您想要UDP通信, ServerSocket
/ Socket
與您的方法幾乎沒有關系,您需要使用DatagramSocket
。 構建它:
port
- 並且只執行一次。 DatagramPackets
。 請參閱有關數據報客戶端/服務器配置的 Oracle站點上的教程。
每次在main
服務器套接字上收到新的客戶端TCP連接時,都會啟動RequestProcessing類的另一個實例。 第一次啟動RequestProcessing實例線程時,它成功綁定到UDP端口7.但是第二個客戶端連接並嘗試啟動另一個RequestProcessing實例,而另一個實例已經存在。 那不行。
您可能應該修改協議,以便RequestProcessing類每次都選擇一個新端口,並通過TCP套接字向選擇的端口發送信號。
但如果是我,我會這樣做。 為所有客戶端提供一個RequestProcessing實例。 鑒於您的UDP echo套接字只是發送回來自該數據包來自的地址的響應,您只需要該類的一個實例。
TCP解決方案:
一個實用程序類(我懶得在多個地方編寫相同的代碼):
public class SocketRW {
Socket socket;
BufferedReader in;
PrintWriter out;
public SocketRW(Socket socket)
throws IOException
{
super();
this.socket = socket;
if(null!=socket) {
this.in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.out=new PrintWriter(socket.getOutputStream());
}
}
public String readLine()
throws IOException {
return this.in.readLine();
}
public void println(String str) {
this.out.println(str);
}
public Socket getSocket() {
return socket;
}
public BufferedReader getIn() {
return in;
}
public PrintWriter getOut() {
return out;
}
}
服務器代碼 - 不再使用數據報,只使用來自套接字的輸入/輸出流,使用該實用程序包裝為Reader / Writer
public class TCPServer
implements Runnable // in case you want to run the server on a separate thread
{
ServerSocket listenOnThis;
public TCPServer(int port)
throws IOException {
this.listenOnThis=new ServerSocket(port);
}
@Override
public void run() {
int client=0;
while(true) {
try {
Socket clientConn=this.listenOnThis.accept();
RequestProcessing processor=new RequestProcessing(clientConn, client++);
processor.start();
} catch (IOException e) {
break;
}
}
}
static public void main(String args[]) {
// port to be provided as the first CLI option
TCPServer server=new TCPServer(Integer.valueOf(args[0]));
server.run(); // or spawn it on another thread
}
}
class RequestProcessing extends Thread {
Socket channel;
int clientNo;
public RequestProcessing(Socket s, int i) {
channel = s;
clientNo = i;
}
public void run() {
try {
SocketRW utility=new SocketRW(this.channel);
while (true) {
String theString=utility.readLine().trim();
System.out.println("Client " + clientNo
+ " sent: " + theString);
if ("quit".equals(theString)) {
System.out.println("Client " + clientNo
+ " disconnected");
this.channel.close();
break;
}
theString = theString.toUpperCase();
utility.println(theString);
}
} catch (IOException e) {
System.err.println(e);
}
}
}
客戶端代碼 - 不再使用套接字的相同IO流的數據報套接字。
class TCPClient
implements Runnable // just in case you want to run multithreaded clients
{
Socket socket;
public TCPClient(InetAddress serverAddr, int port)
throws IOException {
this.socket=new Socket(serverAddr, port);
}
public void run() {
String theString="";
InputStreamReader isr = new InputStreamReader(System.in);
try {
SocketRW utility=new SocketRW(this.socket);
BufferedReader br = new BufferedReader(isr);
do {
System.out.print("Enter message: ");
theString = br.readLine().trim();
utility.println(theString);
System.out.println("Sent to server server: " + theString);
String received=utility.readLine();
System.out.println("Server reply: "+received);
} while (!"quit".equals(theString));
}
catch(IOException e) {
e.printStackTrace();
}
}
static public void main(String[] args) {
int port=Integer.valueOf(args[0]); // will throw if its no OK.
TCPClient client=new TCPClient(
InetAddress.getByName("192.168.109.128"),
port
);
client.run();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.