两个不同的套接字实例是否可以监听同一个 TCP 端口(端口已在使用中)
Can two different socket instances listen to same TCP port ( Port already in use )
我有一个 TcpServer class 负责,嗯,就像一个 tcp 服务器。您可以在下面找到 class :
public class TcpServer {
private ServerSocket serverSocket;
private Socket socket;
private int locallyBoundPort;
public TcpServer() {
}
public TcpServer(int locallyBoundPort) {
try {
this.serverSocket = new ServerSocket(locallyBoundPort);
serverSocket.setReuseAddress(true);
} catch (IOException e) {
System.out.println("Error at binding to port TCP : " + locallyBoundPort + "...cause : " + e.getMessage());
}
socket = null;
}
public void accept() {
try {
socket = serverSocket.accept();
socket.setReuseAddress(true);
} catch (IOException e) {
System.out.println("Error at accept : " + locallyBoundPort);
}
}
public void send(Data data) throws IOException {
if(socket != null) {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(data);
}
}
public Data receive() throws ClassNotFoundException, IOException {
if(socket != null) {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
return (Data) in.readObject();
} else {
return null;
}
}
public boolean bind(int port) throws IOException {
try {
this.serverSocket = new ServerSocket(port);
this.locallyBoundPort = port;
} catch(IOException e) {
return false;
}
return true;
}
public void close() {
try {
serverSocket.close();
socket.close();
} catch (IOException e) {
OzumUtils.print("IOException in close, TcpServer");
}
}
public int getLocallyBoundPort() {
return locallyBoundPort;
}
public Socket getSocket() {
return socket;
}
public ServerSocket getServerSocket() {
return serverSocket;
}
}
我有一段代码可以做到这一点:
TcpServer tcpServer = new TcpServer(LocalPort);
while(1)
{
tcpServer.accept();
Thread thread = new Thread(new runnable(tcpServer));
thread.start();
tcpServer = new TcpServer(LocalPort);
}
但是我收到端口已在使用错误。我认为两个不同的套接字实例可以侦听同一个端口,因为当连接器具有不同的 ip 或端口时,多路复用允许通过同一个端口进行两个连接?
我错过了什么?
您不能将两个 tcp 服务器套接字绑定到同一个端口。 reuseAddress
确实适用于客户端套接字,它并不像您认为的那样工作……而且您使用它的方式根本不会做任何事情(因为您是在绑定后设置它)。
你也不需要两次绑定到同一个端口。只需从 while
循环的底部删除这一行 tcpServer = new TcpServer(LocalPort);
,一切就绪。
它的工作方式是绑定一次服务器套接字并监听端口。当一个连接到达时,它会 fork 一个客户端套接字供你与客户端通信,而原来的服务器套接字会继续监听更多的连接。
基本上,您需要从 TcpServer
中删除 socket
成员(和任何其他状态),并使 accept
方法成为 return 接受的套接字。然后让您的 runnable
将 socket
作为参数而不是 TcpServer
,并使用它来为客户端连接提供服务。然后继续在循环中调用 accept
,并按照您所知道的方式为新连接分叉线程,只是不要每次都重新创建服务器。
或者,或者,从 TcpServer
中删除服务器套接字和端口,在循环外创建套接字,然后 while(true)
在其上调用 accept
,创建一个新的 TcpServer
与 returned 客户端套接字,并在线程中使用它来处理连接。
完成后不要忘记关闭客户端套接字。
不,您不能使用已经处于侦听状态的端口。但是,任意数量的客户端都可以连接到同一个端口。您不需要再次监听该端口,您只需生成一个新线程来处理当前连接并等待新连接。例如,假设您有一个 class TcpConnectionHanlder
实现 Runnable
并将 Socket
作为参数,循环看起来像
while (true) { //while(1) is not valid Java syntax
final Socket tcpSocket = tcpServer.accept(); // Get socket for incoming connection
final Thread thread = new Thread(new TcpConnectionHanlder(tcpSocket)); // Create a thread for this socket/client connection
thread.start(); // Launch the thread
// tcpServer = new TcpServer(LocalPort); <- not needed, port still listening.
}
然后在您的 TcpConnectionHanlder
实例中处理这个特定的客户端(套接字)。
我有一个 TcpServer class 负责,嗯,就像一个 tcp 服务器。您可以在下面找到 class :
public class TcpServer {
private ServerSocket serverSocket;
private Socket socket;
private int locallyBoundPort;
public TcpServer() {
}
public TcpServer(int locallyBoundPort) {
try {
this.serverSocket = new ServerSocket(locallyBoundPort);
serverSocket.setReuseAddress(true);
} catch (IOException e) {
System.out.println("Error at binding to port TCP : " + locallyBoundPort + "...cause : " + e.getMessage());
}
socket = null;
}
public void accept() {
try {
socket = serverSocket.accept();
socket.setReuseAddress(true);
} catch (IOException e) {
System.out.println("Error at accept : " + locallyBoundPort);
}
}
public void send(Data data) throws IOException {
if(socket != null) {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(data);
}
}
public Data receive() throws ClassNotFoundException, IOException {
if(socket != null) {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
return (Data) in.readObject();
} else {
return null;
}
}
public boolean bind(int port) throws IOException {
try {
this.serverSocket = new ServerSocket(port);
this.locallyBoundPort = port;
} catch(IOException e) {
return false;
}
return true;
}
public void close() {
try {
serverSocket.close();
socket.close();
} catch (IOException e) {
OzumUtils.print("IOException in close, TcpServer");
}
}
public int getLocallyBoundPort() {
return locallyBoundPort;
}
public Socket getSocket() {
return socket;
}
public ServerSocket getServerSocket() {
return serverSocket;
}
}
我有一段代码可以做到这一点:
TcpServer tcpServer = new TcpServer(LocalPort);
while(1)
{
tcpServer.accept();
Thread thread = new Thread(new runnable(tcpServer));
thread.start();
tcpServer = new TcpServer(LocalPort);
}
但是我收到端口已在使用错误。我认为两个不同的套接字实例可以侦听同一个端口,因为当连接器具有不同的 ip 或端口时,多路复用允许通过同一个端口进行两个连接? 我错过了什么?
您不能将两个 tcp 服务器套接字绑定到同一个端口。 reuseAddress
确实适用于客户端套接字,它并不像您认为的那样工作……而且您使用它的方式根本不会做任何事情(因为您是在绑定后设置它)。
你也不需要两次绑定到同一个端口。只需从 while
循环的底部删除这一行 tcpServer = new TcpServer(LocalPort);
,一切就绪。
它的工作方式是绑定一次服务器套接字并监听端口。当一个连接到达时,它会 fork 一个客户端套接字供你与客户端通信,而原来的服务器套接字会继续监听更多的连接。
基本上,您需要从 TcpServer
中删除 socket
成员(和任何其他状态),并使 accept
方法成为 return 接受的套接字。然后让您的 runnable
将 socket
作为参数而不是 TcpServer
,并使用它来为客户端连接提供服务。然后继续在循环中调用 accept
,并按照您所知道的方式为新连接分叉线程,只是不要每次都重新创建服务器。
或者,或者,从 TcpServer
中删除服务器套接字和端口,在循环外创建套接字,然后 while(true)
在其上调用 accept
,创建一个新的 TcpServer
与 returned 客户端套接字,并在线程中使用它来处理连接。
完成后不要忘记关闭客户端套接字。
不,您不能使用已经处于侦听状态的端口。但是,任意数量的客户端都可以连接到同一个端口。您不需要再次监听该端口,您只需生成一个新线程来处理当前连接并等待新连接。例如,假设您有一个 class TcpConnectionHanlder
实现 Runnable
并将 Socket
作为参数,循环看起来像
while (true) { //while(1) is not valid Java syntax
final Socket tcpSocket = tcpServer.accept(); // Get socket for incoming connection
final Thread thread = new Thread(new TcpConnectionHanlder(tcpSocket)); // Create a thread for this socket/client connection
thread.start(); // Launch the thread
// tcpServer = new TcpServer(LocalPort); <- not needed, port still listening.
}
然后在您的 TcpConnectionHanlder
实例中处理这个特定的客户端(套接字)。