`

Java nio 客户端连接Server

阅读更多

在做通信系统的开发过程中,经常需要使用Socket通信。java新的io机制给我提供了一个很好的异步socket通信方式,这段时间用java写了一个客户端用来连接server。发现运行效率还比较让人满意。下面是我实现的部分功能。

连接服务器的socket,多线程启动。如果连接失败就重连。

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是基于事件的驱动模型,这个类就是专门处理收发的。

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 < 0){
			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");
			}
		}
	}
}

 发送和接收数据存放在缓存中

public class PackageQueue {
	private static  List<byte[]> queue = new ArrayList<byte[]>();
	
	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<byte[]> getQueue() {
		return queue;
	}

	public static void setQueue(List<byte[]> queue) {
		PackageQueue.queue = queue;
	}
}

 以上就是客户端连接、发送、接收的代码。希望对大家有所帮助

分享到:
评论
3 楼 charlotte 2012-05-14  
学习了!!!!!
2 楼 fokman 2011-08-17  
一江春水邀明月 写道
缺少SocketInfoUtils  ThreadPoolUtil CameraSocket  三个类的代码啊, 博主能把这三个类也贴一下吗? 谢谢了

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<Runnable> queue = new ArrayBlockingQueue<Runnable>(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;
}

}
1 楼 一江春水邀明月 2011-06-30  
缺少SocketInfoUtils  ThreadPoolUtil CameraSocket  三个类的代码啊, 博主能把这三个类也贴一下吗? 谢谢了

相关推荐

    JAVA NIO客户端服务端完整项目工程(ServerandClientNIOV1.0.zip)包下载.txt

    该JAVA NIO项目包含server服务端完整项目源码、client客户端项目工程源码。

    Java NIO实现多个客户端之间的消息互发,客户端与服务器完整代码

    在这个场景下,Java NIO能够帮助服务器有效地处理多个客户端连接,并实现客户端之间消息的互发。 首先,我们要理解Java NIO的基本组件。主要包括通道(Channels)、缓冲区(Buffers)和选择器(Selectors)。通道是...

    java nio im(server+client)

    在这个Java NIO IM(即时通讯)服务器和客户端的示例中,我们将探讨如何利用NIO进行双向通信,并理解其背后的机制。 1. **NIO基础概念** - **通道(Channel)**:在NIO中,数据是通过通道进行传输的。通道类似于流...

    java NIO实例

    在`NIOServer.java`中,可能会创建ServerSocketChannel监听客户端连接,然后通过accept()方法接收新连接,形成SocketChannel。 6. **Pipe**:在本地进程间通信(IPC)中使用,提供单向数据流。 7. **CharSet和...

    基于java NIO的socket通信demo

    首先,我们来看`NioServer.java`。这个文件中包含了一个基于NIO的服务器端实现。服务器的核心组件是`Selector`,它允许一个单独的线程监听多个套接字通道的状态变化。当客户端发起连接请求时,服务器会注册`...

    java_Nio_server_and_j2me_client.rar_J2ME SERVER_NIO_j2me_j2me ni

    而"TestNIO_client"和"TestNIO_server"这两个文件名很可能分别对应的是NIO客户端和服务器的源代码文件,用户可以通过这些源代码了解如何在J2ME和Java NIO之间建立有效的通信。 在实际应用中,J2ME客户端可能使用...

    Java NIO原理 图文分析及代码实现

    为了更好地理解Java NIO的使用方式,下面我们通过简单的代码示例来展示如何实现一个基本的NIO服务端和客户端。 **服务端代码实现** ```java package cn.nio; import java.io.IOException; import java.net....

    java nio Selector的使用-客户端

    以下是一个简单的Java NIO客户端示例,名为DownloadClient.java: ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey;...

    java nio聊天室源码

    Java NIO(New IO)是Java 1.4版本引入的一种新的I/O API,它提供了非阻塞I/O操作的能力,极大地提升了Java在处理网络通信和文件读写时的性能。在这个“java nio聊天室源码”项目中,我们可以看到如何使用NIO构建一...

    java ftp客户端,服务端

    在Java中,我们可以使用`java.net.Socket`类来创建客户端连接,它代表了两台机器之间的网络连接。Socket编程是基于TCP/IP协议的,确保了数据的可靠传输。要实现FTP客户端,首先需要创建一个Socket连接到FTP服务器,...

    java NIO 学习 聊天室程序 (3)

    1. **服务器端**:服务器端使用NIO的ServerSocketChannel监听客户端连接。当新的客户端连接请求到达时,服务器会创建一个新的SocketChannel来处理这个连接,而不是像阻塞IO那样阻塞等待。这样服务器就可以继续监听...

    java io 与java nio区别

    - **Java NIO**:能够有效地利用系统资源,支持更多的并发连接,因此在处理大量连接请求时性能更优。 #### 应用场景 - **Java IO**:适用于数据量较小且连接数较少的应用场景。 - **Java NIO**:适用于数据量大、...

    nioserver.rar_NIO_java nio

    在NIO中,服务器端通常使用Selector来监听多个客户端连接。当新的连接请求到达时,服务器会创建一个SocketChannel,并将其注册到Selector上,指定感兴趣的操作类型(如Accept、Read)。Selector会轮询所有注册的通道...

    NIO 服务器客户端例子

    **NIO客户端(TestClient.java)的关键知识点:** 1. **套接字通道(SocketChannel)**:客户端通过`SocketChannel.open()`创建通道,并用`socketChannel.connect(new InetSocketAddress(serverAddress, serverPort...

    java nio socket 例子

    本例包含服务器端和客户端,多线程,每线程多次发送,Eclipse工程,启动服务器使用 nu.javafaq.server.NioServer,启动客户端使用 nu.javafaq.client.NioClient。另本例取自javafaq.nv上的程序修改而成

    java NIO socket聊天室

    使用NIO socket不需要多线程来处理多个连接的请求,效率非常高 ...4,修改封装http做成短连接处理,就是一个小型的webserver,或者结合java2D和robot做远程监控 5,封装自己的协议可以做成自己需要的服务器端程序,

    JAVA NIO 异步通信模板服务端

    例如,可能有一个名为`NioServer`的主类,用于初始化ServerSocketChannel,注册选择器,以及处理接收到的连接和数据。还有可能包含`ThreadPool`类,用于管理线程池,以及`BufferHandler`类,负责处理缓冲区中的数据...

    NIOServer

    【文件】:“NIOServer.java”是整个项目的主文件,很可能包含了服务器的启动逻辑、NIO服务的配置以及客户端连接的处理。代码可能包括以下几个关键部分: 1. **服务器端套接字(ServerSocketChannel)**:服务器...

    基于Groovy的NIO框架,仅供学习Java NIO使用。.zip

    Java NIO(New IO)是Java 1.4版本引入的一个新特性,它提供了一种不同于传统IO(-blocking I/O)的I/O操作方式。传统的IO模型是基于流的,通常涉及阻塞式读写,而NIO则引入了通道(Channels)和缓冲区(Buffers)的...

    实现java网络与nio例子

    这个例子包含了NIO在网络通信中的应用,包括服务器端(Server)和客户端(Client)的实现。 在Java NIO中,核心组件有通道(Channels)、缓冲区(Buffers)和选择器(Selectors)。通道是数据传输的途径,如套接字...

Global site tag (gtag.js) - Google Analytics