最近,我一直在使用DatagramChannels做很多事情,并且制作了一个非常复杂且功能良好的系统,可以在连接的两个侧面上使用它们。 但是,我遇到了一个问题。在检查连接协议的完整性时,我意识到在一个端口上运行多个通道存在很大的问题。似乎与Java的TCP套接字不同,Java的udp套接字在数据包到达适当的通道时不能正确地路由它们。 更具体地说,如果我在两个线程上有两个通道,等待一个数据包,它们都在同一端口上,但连接到不同的输出,则似乎第一个绑定的通道将是获取数据包的通道,即使它来自另一个通道的连接。问题在于它会自动(按理应)将其过滤掉,结果,该数据包将永远丢失,第二个信道将一直处于等待状态。 由于技术限制,我需要服务器端仅在一个端口上运行,这使我对应该做什么感到困惑。 难道我做错了什么?另外,这是使用选择器修复的吗?我对DatagramSockets和通道有点陌生,因为到目前为止,我在Java中大多使用过tcp。
我这里也有一些完整性检查的测试代码来验证它,这有点混乱,但是有两个计时器不断地尝试从同一连接接收数据包,只有其中一个正在接收。 通过更改首先运行哪个计时器任务,我可以更改哪个计时器获取数据包。更令我感到困惑的是,第一个计时器任务能够与现在的每个套接字一起工作,而仍然不让“外部通道”接收单个数据包。
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);
}
}
答案 0 :(得分:0)
最终创建了一个实际上在服务器上读取的读取器通道,然后将数据包重新路由到要处理的不同发送者通道,然后发送响应。