各位大侠好,小弟想问一下问题,搞了一两天没有搞明白的。因为要实现一个UDP传输服务端,于是在网上找了很多资料然后就写了一个。但是写好之后发现有两个很严重的问题,希望各位大哥给点意见或者思路去解决。
问题一:启动服务端,同时也启动客户端,客户端传输数据服务器正常接收,但是断开客户端后,再启动客户端,服务器就收不到任何客户端发送的消息,好像是服务器关闭了UDP一样,但是重启服务器后(重新打开UDP)客户端既可以发送信息过来。
问题二:多个客户端。第一个客户端连接上后,第二个客户端怎么也链接不上了。即使关闭了第一个客户端也一样。
如下是代码:
package com.gateway.socket;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import org.apache.log4j.Logger;
public class UDPEchoServerSelector extends Thread {
private static final Logger log = Logger.getLogger(ServerSocket.class);
//
private InetSocketAddress inetSocketAddress;
// socket处理类
private UDPSocketHandler handler = new UDPSocketHandler();
// 注册的接受服务
private SocketReceiver receiver = null;
/**
* 初始化socket
*
* @param receiver
* @param hostname
* @param port
* @throws IOException
* @throws UnknownHostException
*/
public UDPEchoServerSelector(SocketReceiver receiver, String hostname,
int port) {
if (hostname.isEmpty()) {
inetSocketAddress = new InetSocketAddress(port);
} else {
inetSocketAddress = new InetSocketAddress(hostname, port);
}
this.receiver = receiver;
}
@Override
public void run() {
try {
Selector selector = Selector.open(); // 创建选择器,可以处理多路通道。
DatagramChannel serverSocketChannel = DatagramChannel.open(); // 打开通道
serverSocketChannel.configureBlocking(false); // 非阻塞
serverSocketChannel.socket().bind(inetSocketAddress);
/*
* 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_READ事件,注册该事件后,
* 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
*/
serverSocketChannel.register(selector, SelectionKey.OP_READ,
new ClientData());
log.info("Server: socket server started.");
/*
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
*/
while (true) { // 轮询
// 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
int nKeys = selector.select();
if (nKeys == 0) {
continue;
}
// 得到选择键列表
Set Keys = selector.selectedKeys();
Iterator it = Keys.iterator();
while (it.hasNext()) {
SelectionKey key = null;
key = (SelectionKey) it.next(); // 键为位掩码
it.remove();
// 客户端请求连接事件
if (key.isValid() && key.isWritable()) {
log.info("Server: SelectionKey is acceptable.");
handler.handleWrite(key);
}
if (key.isReadable()) {// 获得了可读的事件
log.info("Server: SelectionKey is readable.");
handler.receiveMsg(key, receiver);
}
}
Keys.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static class ClientData {
public SocketAddress clientAddress;
public ByteBuffer buffer = ByteBuffer.allocate(255);
}
}
package com.gateway.socket;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import org.apache.log4j.Logger;
import com.gateway.common.DeviceDataTools;
import com.gateway.common.data.HexUtils;
import com.gateway.socket.UDPEchoServerSelector.ClientData;
/**
*/
public class UDPSocketHandler {
private static Logger log = Logger.getLogger(UDPSocketHandler.class);
/**
@throws IOException
*/
public void handleWrite(SelectionKey key) {
try {
DatagramChannel channel = (DatagramChannel) key.channel();
ClientData clntDat = (ClientData) key.attachment();
clntDat.buffer.flip(); // 从起始位置开始发送
int bytesSent;
bytesSent = channel.send(clntDat.buffer, clntDat.clientAddress);
if (bytesSent != 0) {
key.interestOps(SelectionKey.OP_READ); // 关注客户端发送数据
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
@throws IOException
*/
public void receiveMsg(SelectionKey key, SocketReceiver receiver) {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.clear();
DatagramChannel socketChannel = (DatagramChannel) key.channel();
//非阻塞
try {
socketChannel.configureBlocking(false);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("channel code:" + socketChannel.hashCode());
try {
while (true) {
InetSocketAddress client = (InetSocketAddress) socketChannel
.receive(byteBuffer);
byteBuffer.flip();
// byteBuffer中传过来的是10进制的bytep[]
byte[] dst = new byte[byteBuffer.limit()];
byteBuffer.get(dst);
// 将10进制的byte[]转化成16进制字符串
String data = HexUtils.converBytesToHex(dst);
System.out.println(data);
log.info("Server: data1 = " + data);
byteBuffer.clear();
receiver.udpreceive(socketChannel, data, client);
break;
}
} catch (java.io.IOException e) {
//e.printStackTrace();
//this.closeChannel(key, socketChannel);
} catch (Exception e) {
//e.printStackTrace();
//this.closeChannel(key, socketChannel);
}
}
/**
/**
@throws IOException
*/
public static boolean send(String socketKey, String data)
throws IOException {
DatagramChannel socketChannel = SocketChannelMapper
.getUDPChannel(socketKey);
if (socketChannel == null || !socketChannel.isOpen()) {
return false;
}
InetSocketAddress client = SocketChannelMapper
.getUDPInetSocketAddress(socketKey + "address");
boolean f = socketChannel.isConnected();
ByteBuffer byteBuffer = ByteBuffer.wrap(DeviceDataTools.hex2Byte(data));
if (f) {
socketChannel.write(byteBuffer);
} else {
socketChannel.connect(new InetSocketAddress(client.getAddress(),
client.getPort()));
socketChannel.send(byteBuffer, client);
}
return true;
}
/**
@throws IOException
*/
public static boolean send(DatagramChannel socketChannel, String data,
InetSocketAddress client) throws IOException {
if (socketChannel == null) {
return false;
}
System.out.println("#########################ADDRESS"
+ client.getAddress());
System.out.println("#########################PORT" + client.getPort());
boolean f = socketChannel.isConnected();
ByteBuffer byteBuffer = ByteBuffer.wrap(DeviceDataTools.hexStr2ByteArray(data));
if (f) {
socketChannel.write(byteBuffer);
} else {
socketChannel.connect(new InetSocketAddress(client.getAddress(),
client.getPort()));
socketChannel.send(byteBuffer, client);
}
return true;
}
}
建议楼主建一个服务器,多个客户端测试一下
@模范青蛙,请问一下代码有没有问题?我目前就是将本机作为服务器来测试的