【发布时间】:2018-12-16 20:48:49
【问题描述】:
在评论正确使用 SO_REUSEADDR 后编辑
我想在 java 中为入站和出站连接使用相同的端口
目的是在分布式环境中做一个节点。但在 Tcp 中,我需要使用两个不同的端口来接受和启动连接。
// accept incoming connection on one port
ServerSocket.accept()
// connect to remote, the port used will be different from the one used for accepting
Socket.connect()
现在的问题是:
- A 开始监听端口 a。 B 上的 B 和 c 上的 C。
- 当 A 连接 B(使用
Socket.connect())时,A 和 B 将保持套接字打开以供将来的消息传递。 - B 仍然不知道端口 A 正在侦听,因为 b 接收连接的端口与 a 不同。
- 当 C 连接 B 时,B 将 A 的套接字地址提供给 C,但该端口被
Socket()实例绑定,该实例没有accept()方法
当然,A 可以通知 B 它正在侦听的端口,但是没有直接的方法吗?
我怎样才能使这个测试通过?
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DualSocketTest {
ExecutorService service= Executors.newFixedThreadPool(10);
int echoServerport=8080;
int localServerport=8090;
@Test
public void testConnectivity() throws IOException {
// create a echo server on port 8080
startEcho();
// create a local Server instance
ServerSocket localServer=new ServerSocket();
// set the reuseAddress to true
localServer.setReuseAddress(true);
// bind the serverSocket
localServer.bind(new InetSocketAddress(localServerport));
// create a socket to connect the echo server using the same port used by localServer
Socket socket = new Socket();
socket.setReuseAddress(true);
// but this will throw SocketBindException
socket.bind(new InetSocketAddress(localServerport));
socket.connect(new InetSocketAddress(echoServerport));
// write hello
socket.getOutputStream().write("Hello !".getBytes());
byte[] result=new byte[100];
// receive hello
String ans=new String(result,0,socket.getInputStream().read(result));
System.out.println("Server replied with : "+ans);
// what was written and what was received must be same.
assert(ans.equals("Hello !"));
}
// start a echo server listening on the specified port
private void startEcho() throws IOException {
ServerSocket echoServer=new ServerSocket(echoServerport);
service.submit(()->{
try {
while(!echoServer.isClosed()) {
Socket socket = echoServer.accept();
System.out.println("connected with :" + socket.getInetAddress().toString() + ":" + socket.getPort());
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
service.submit(() -> {
while (socket.isConnected()) {
try {
outputStream.write(inputStream.read());
} catch (IOException e) {
break;
}
}
System.out.println("The Client has closed connection.");
});
}
} catch (IOException e) {
e.printStackTrace();
}
});
Thread.yield();
}
// Write something to the socket.
}
我以前使用udp的时候没有这个问题。同一个socket支持receive()和send()方法。对于udp,分享地址很简单。
- 当A连接B时,B会保存A的
socketAddress, - 当 C 连接 B 时,B 将 A 的地址发送给 C,C 将连接到 A
【问题讨论】:
-
“但是 A 不能接受来自与 B 通信的同一个套接字的新连接”。你在说什么。如果
A正在监听端口a,则B和C都可以通过端口A连接到A。 -
@Kayaman 我已经编辑了这个问题。问题是 b 看到的端口与 A 正在侦听的端口不同。
-
您似乎使这变得不必要地困难。要么为监听套接字使用标准端口,因此您不需要传递该信息,或者将 IP/端口组合传递给新节点。
-
'我想在 java 中为入站和出站连接使用相同的端口。'为什么?
-
NB 调用
setReuseAddress()你绑定了套接字是没有意义的。
标签: java sockets tcp ip-address