让多个 DatagramChannels 在一个端口上工作的最佳方法
Best approach to having multiple DatagramChannels working on one port
最近我一直在与 DatagramChannels 打交道,并制作了一个相当复杂且功能良好的系统,以便在连接的两侧使用它们。
但是,我 运行 遇到了问题。在对我的连接协议进行健全性检查时,我意识到 运行 在一个端口上设置多个通道是一个很大的问题。似乎与 java 的 TCP 套接字不同,java 的 udp 套接字在数据包到达适当的通道时没有正确路由数据包。
更具体地说,如果我有两个通道,在两个线程上,等待一个数据包,都在同一个端口上,但连接到不同的输出,第一个被绑定的将是获取数据包的那个,即使它来自其他频道的连接。问题是它会自动将其过滤掉(应该如此),结果,该数据包将永远完全丢失,而第二个通道将继续等待。
由于技术限制,我需要服务器端在一个端口上 运行,这让我很困惑我应该怎么做。
难道我做错了什么?另外,这是通过使用选择器来修复的吗?我对 DatagramSockets 和通道有点陌生,因为到目前为止我主要使用 java 中的 tcp。
我这里也有一些健全性检查的测试代码来验证它,有点乱,但是有两个定时器不断地尝试从同一个连接接收数据包,而且只有一个正在接收。
通过首先更改哪个计时器任务 运行s,我可以更改哪个计时器任务获取数据包。更让我困惑的是,第一个计时器任务能够与每个现在的套接字一起工作,同时仍然不让 "outsider channel" 接收到一个数据包。
public static void main(String[] args) {
runServer();
runClient();
}
public static void runClient() {
DatagramChannel channel;
try {
channel = DatagramChannel.open();
channel.bind(new InetSocketAddress("localhost", 8000));
channel.connect(new InetSocketAddress("localhost", 8001));
while(true) {
channel.write(ByteBuffer.wrap("let's see who wins".getBytes()));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static class Channel{
DatagramChannel channel;
int number;
public Channel(int number) {
try {
channel = DatagramChannel.open();
this.number = number;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static boolean outsiderLost = false;
// client on port 8000
// server on port 8001
public static void runServer() {
ByteBuffer buf = ByteBuffer.wrap(new byte[300]);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
boolean firstTime = true;
int i = 0;
Channel channel = new Channel(i);
DatagramChannel channel1 = channel.channel;
while(true) {
try {
if(firstTime) {
channel1.socket().setReuseAddress(true);
channel1.bind(new InetSocketAddress("localhost", 8001));
channel1.connect(new InetSocketAddress("localhost", 8000));
channel1.configureBlocking(true);
firstTime = false;
} else {
SocketAddress add = channel1.receive(buf);
i++;
channel = new Channel(i);
channel1 = channel.channel;
channel1.socket().setReuseAddress(true);
channel1.bind(new InetSocketAddress("localhost", 8001));
channel1.connect(add);
buf.clear();
System.out.println("channel " + channel.number + " wins");
outsiderLost = true;
}} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}, 500);
Timer timer2 = new Timer();
timer2.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
DatagramChannel channel1 = null;
try {
channel1 = DatagramChannel.open();
channel1.socket().setReuseAddress(true);
channel1.bind(new InetSocketAddress("localhost", 8001));
channel1.connect(new InetSocketAddress("localhost", 8000));
channel1.configureBlocking(true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(!outsiderLost) {
try {
channel1.read(buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
buf.clear();
System.out.println("outsider wins");
outsiderLost = true;
}
}
}, 1000);
}
}
最终创建了一个 reader 实际在服务器上读取的通道,然后将数据包重新路由到不同的发送通道进行处理,然后发送响应。
最近我一直在与 DatagramChannels 打交道,并制作了一个相当复杂且功能良好的系统,以便在连接的两侧使用它们。 但是,我 运行 遇到了问题。在对我的连接协议进行健全性检查时,我意识到 运行 在一个端口上设置多个通道是一个很大的问题。似乎与 java 的 TCP 套接字不同,java 的 udp 套接字在数据包到达适当的通道时没有正确路由数据包。 更具体地说,如果我有两个通道,在两个线程上,等待一个数据包,都在同一个端口上,但连接到不同的输出,第一个被绑定的将是获取数据包的那个,即使它来自其他频道的连接。问题是它会自动将其过滤掉(应该如此),结果,该数据包将永远完全丢失,而第二个通道将继续等待。 由于技术限制,我需要服务器端在一个端口上 运行,这让我很困惑我应该怎么做。 难道我做错了什么?另外,这是通过使用选择器来修复的吗?我对 DatagramSockets 和通道有点陌生,因为到目前为止我主要使用 java 中的 tcp。
我这里也有一些健全性检查的测试代码来验证它,有点乱,但是有两个定时器不断地尝试从同一个连接接收数据包,而且只有一个正在接收。 通过首先更改哪个计时器任务 运行s,我可以更改哪个计时器任务获取数据包。更让我困惑的是,第一个计时器任务能够与每个现在的套接字一起工作,同时仍然不让 "outsider channel" 接收到一个数据包。
public static void main(String[] args) {
runServer();
runClient();
}
public static void runClient() {
DatagramChannel channel;
try {
channel = DatagramChannel.open();
channel.bind(new InetSocketAddress("localhost", 8000));
channel.connect(new InetSocketAddress("localhost", 8001));
while(true) {
channel.write(ByteBuffer.wrap("let's see who wins".getBytes()));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static class Channel{
DatagramChannel channel;
int number;
public Channel(int number) {
try {
channel = DatagramChannel.open();
this.number = number;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static boolean outsiderLost = false;
// client on port 8000
// server on port 8001
public static void runServer() {
ByteBuffer buf = ByteBuffer.wrap(new byte[300]);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
boolean firstTime = true;
int i = 0;
Channel channel = new Channel(i);
DatagramChannel channel1 = channel.channel;
while(true) {
try {
if(firstTime) {
channel1.socket().setReuseAddress(true);
channel1.bind(new InetSocketAddress("localhost", 8001));
channel1.connect(new InetSocketAddress("localhost", 8000));
channel1.configureBlocking(true);
firstTime = false;
} else {
SocketAddress add = channel1.receive(buf);
i++;
channel = new Channel(i);
channel1 = channel.channel;
channel1.socket().setReuseAddress(true);
channel1.bind(new InetSocketAddress("localhost", 8001));
channel1.connect(add);
buf.clear();
System.out.println("channel " + channel.number + " wins");
outsiderLost = true;
}} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}, 500);
Timer timer2 = new Timer();
timer2.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
DatagramChannel channel1 = null;
try {
channel1 = DatagramChannel.open();
channel1.socket().setReuseAddress(true);
channel1.bind(new InetSocketAddress("localhost", 8001));
channel1.connect(new InetSocketAddress("localhost", 8000));
channel1.configureBlocking(true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(!outsiderLost) {
try {
channel1.read(buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
buf.clear();
System.out.println("outsider wins");
outsiderLost = true;
}
}
}, 1000);
}
}
最终创建了一个 reader 实际在服务器上读取的通道,然后将数据包重新路由到不同的发送通道进行处理,然后发送响应。