在做通信系统的开发过程中,经常需要使用Socket通信。java新的io机制给我提供了一个很好的异步socket通信方式,这段时间用java写了一个客户端用来连接server。发现运行效率还比较让人满意。下面是我实现的部分功能。
连接服务器的socket,多线程启动。如果连接失败就重连。
Java代码
public class CommonSocket extends Thread {
private SocketChannel socketChannel;
private boolean stop = false;
private int port = 0;
private String ip = "";
private Selector selector = null;
private SocketAddress socketAddress = null;
private Logger logger = Logger.getLogger(CommonSocket.class);
public CommonSocket() {
this.ip = SocketInfoUtils.TCP_IP;
this.port = SocketInfoUtils.TCP_PORT;
}
public void run() {
while (!stop) {
socketConnet();
try {
sleep(5000);
} catch (InterruptedException e) {
logger.error("SocketConnect run error: InterruptedException");
}
}
}
public void socketBuilder() {
try {
selector = Selector.open();
} catch (IOException e) {
e.printStackTrace();
logger.error("Open to selector failed: IOException");
}
}
private void openSocketChannel() {
try {
socketAddress = new InetSocketAddress(ip, port);
socketChannel = SocketChannel.open();
socketChannel.socket().setReuseAddress(true);
socketChannel.connect(socketAddress);
} catch (ClosedChannelException e) {
logger.warn("Channel is closed: ClosedChannelException");
} catch (IOException e) {
logger
.warn("Connet is failed or time out,the system will automatically re-connected : IOException");
}
}
/**
* do ClientBuilder if socket conncte success
*/
public void socketConnet() {
try {
openSocketChannel();
if (socketChannel.isOpen()) {
this.stop = true;
socketBuilder();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ
| SelectionKey.OP_WRITE);
PackageBuilder clientBuilder = new PackageBuilder(socketChannel,
selector);
clientBuilder.start();
logger.info("Has been successfully connected to " + ip
+ "and port: " + port);
} else {
socketChannel.close();
}
} catch (ClosedChannelException e) {
logger.warn("Channel is closed: ClosedChannelException");
} catch (IOException e) {
logger
.warn("Connet is failed or time out,the system will automatically re-connected : IOException");
}
}
}
发送和接收事件处理,NIO是基于事件的驱动模型,这个类就是专门处理收发的。
Java代码
public class PackageBuilder extends Thread{
private SocketChannel socketChannel = null;
private Selector selector = null;
private boolean stop = false;
private byte[] array = new byte[1024];
private ByteBuffer byteBuffer;
private PackageQueue packageQueue;
private Logger logger = Logger.getLogger(PackageBuilder.class);
public PackageBuilder(SocketChannel socketChannel,Selector selectore){
this.socketChannel = socketChannel;
this.selector = selectore;
packageQueue=new PackageQueue();
}
public void run(){
try {
while (!stop) {
Thread.sleep(1);
if(!socketChannel.isOpen()){
reconnect();//通道没打开或者断开执行重连工作(Channel did not open the work of the implementation of re-connection )
break;
}
if (selector.select(30) > 0) {
doSelector();
}
}
} catch (IOException e) {
logger.error("CameraBuilder run error: IOException");
} catch (InterruptedException e){
logger.error("CameraBuilder run error: InterruptedException");
}
}
public void doSelector(){
for(SelectionKey key:selector.selectedKeys()){
selector.selectedKeys().remove(key);
if(!key.isValid()){
continue;
}
doKeys(key);
}
}
public void doKeys(SelectionKey key){
SocketChannel channel = (SocketChannel)key.channel();
if(key.isReadable()){
readResponse(channel);
}
if(key.isWritable()){
sendRequest(channel);
}
}
private void readResponse(SocketChannel channel) {
byteBuffer=ByteBuffer.wrap(array);
byteBuffer.clear();
int count = 0;
try {
count = channel.read(byteBuffer);
} catch (IOException e) {
reconnect();//通道没打开或者断开执行重连工作(Channel did not open the work of the implementation of re-connection )
logger.error("Connection reset by peer: IOException");
}
if(count != -1){
byteBuffer.flip();
byte[] bs = new byte[count];
byteBuffer.get(bs);
ByteBuffer returnBuffer = ByteBuffer.allocate(count);
returnBuffer.clear();
returnBuffer.put(bs);
returnBuffer.flip();
PrintUtil.printBf(returnBuffer.array());
ParseBufferData parseData=new ParseBufferData(returnBuffer);
parseData.parseBuffer();
}
if(count
reconnect();
}
}
/**
* send pakcet of request
* @param channel
*/
public void sendRequest(SocketChannel channel){
byte[] array = packageQueue.takeMsgs();
if(array!=null){
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
try {
channel.write(byteBuffer);
} catch (IOException e) {
reconnect();//通道没打开或者断开执行重连工作(Channel did not open the work of the implementation of re-connection )
logger.warn("socket not connected or has been closed: IOException");
}
}
}
public void reconnect(){
stopClient();
logger.warn("socket not connected or has been closed");
ThreadPoolUtil.getExecutor().execute(new CameraSocket());
}
public void stopClient(){
this.stop = true;
if(socketChannel.isConnected() && !socketChannel.isOpen()){
try {
socketChannel.close();
logger.info("server_socket has connected");
} catch (IOException e) {
logger.warn("Channel closed to failed: IOException");
}
}
}
}
发送和接收数据存放在缓存中
Java代码
public class PackageQueue {
private static List queue = new ArrayList();
public PackageQueue(){
}
public void pushMsgs(byte[] array){
synchronized(queue){
queue.add(array);
}
}
public byte[] takeMsgs() {
synchronized (queue) {
byte[] sd=null;
if(queue != null){
if(queue.size() > 0){
sd = queue.get(0);
queue.remove(0);
}
}
return sd;
}
}
public static List getQueue() {
return queue;
}
public static void setQueue(List queue) {
PackageQueue.queue = queue;
}
}
public class CameraSocket extends Thread {
private int cmdPort = SocketInfoUtils.CMD_PORT; // 5554
private String host = SocketInfoUtils.HOST; // 172.16.163.38
ByteBuffer buffer = ByteBuffer.allocate(1024);
//DatagramChannel dataChannel;
DatagramChannel cmdChannel;
Selector selector;
CameraQueue cameraQueue;
public CameraSocket() throws Exception {
selector = Selector.open();
cameraQueue = new CameraQueue();
cmdChannel = DatagramChannel.open();
cmdChannel.configureBlocking(false);
SocketAddress target = new InetSocketAddress(host, cmdPort);
cmdChannel.connect(target);
cmdChannel.register(selector, SelectionKey.OP_WRITE);
}
@Override
public void run() {
boolean flag = true;
while (flag) {
try {
doSelector();
} catch (IOException e) {
flag = false;
e.printStackTrace();
}
}
}
private void doSelector() throws IOException {
if (selector.select(1000) > 0) {
for (SelectionKey key : selector.selectedKeys()) {
if (key.isWritable()) {
writeEvent(cmdChannel);
}
}
selector.selectedKeys().clear();
}
}
//private void readEvent(SelectionKey key) throws IOException {
//ByteBuffer buffer = ByteBuffer.allocate(1024);
//dataChannel.receive(buffer);
//buffer.flip();
//ParseBufferData parseBufferData=new ParseBufferData(buffer);
//parseBufferData.parseBuffer();
//}
private void writeEvent(DatagramChannel channel) throws IOException {
byte[] array = cameraQueue.takeMsgs();
if (array != null) {
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
try {
channel.write(byteBuffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class SocketInfoUtils {
public static Properties factory = SocketPropertiesFactory.getInstance().getBoundle();
public static String TCP_IP = factory.getProperty("tcp_ip");
public static int TCP_PORT = Integer.parseInt(factory.getProperty("tcp_port"));
public static int CAMERA_PORT=Integer.parseInt(factory.getProperty("camera_port"));
//public static int UDP_PORT = Integer.parseInt(factory.getProperty("udp_port"));
public static int HIS_UDP_PORT = Integer.parseInt(factory.getProperty("his_udp_port"));
public static int CMD_PORT = Integer.parseInt(factory.getProperty("cmd_port"));
public static int DATA_PORT = Integer.parseInt(factory.getProperty("data_port"));
public static final String HOST = factory.getProperty("host");
}
public class ThreadPoolUtil {
private static ThreadPoolExecutor executor;
static{
BlockingQueue queue = new ArrayBlockingQueue(1);
executor = new ThreadPoolExecutor(5,100,500,TimeUnit.MILLISECONDS,queue);
RejectedExecutionHandler rejected = new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println(String.format("======= Task %d rejected.======", r.hashCode()));
}
};
executor.setRejectedExecutionHandler(rejected);
}
public static ThreadPoolExecutor getExecutor() {
return executor;
}
public static void setExecutor(ThreadPoolExecutor executor) {
ThreadPoolUtil.executor = executor;
}
}
以上就是客户端连接、发送、接收的代码。希望对大家有所帮助