Java Socket编程实例(四)- NIO TCP实践
作者:kingxss 发布时间:2021-10-07 13:44:35
标签:Java,Socket,NIO,TCP
一、回传协议接口和TCP方式实现:
1.接口:
import java.nio.channels.SelectionKey;
import java.io.IOException;
public interface EchoProtocol {
void handleAccept(SelectionKey key) throws IOException;
void handleRead(SelectionKey key) throws IOException;
void handleWrite(SelectionKey key) throws IOException;
}
2.实现:
import java.nio.channels.*;
import java.nio.ByteBuffer;
import java.io.IOException;
public class TCPEchoSelectorProtocol implements EchoProtocol{
private int bufSize; // Size of I/O buffer
public EchoSelectorProtocol(int bufSize) {
this.bufSize = bufSize;
}
public void handleAccept(SelectionKey key) throws IOException {
SocketChannel clntChan = ((ServerSocketChannel) key.channel()).accept();
clntChan.configureBlocking(false); // Must be nonblocking to register
// Register the selector with new channel for read and attach byte buffer
clntChan.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufSize));
}
public void handleRead(SelectionKey key) throws IOException {
// Client socket channel has pending data
SocketChannel clntChan = (SocketChannel) key.channel();
ByteBuffer buf = (ByteBuffer) key.attachment();
long bytesRead = clntChan.read(buf);
if (bytesRead == -1) { // Did the other end close?
clntChan.close();
} else if (bytesRead > 0) {
// Indicate via key that reading/writing are both of interest now.
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
public void handleWrite(SelectionKey key) throws IOException {
/*
* Channel is available for writing, and key is valid (i.e., client channel
* not closed).
*/
// Retrieve data read earlier
ByteBuffer buf = (ByteBuffer) key.attachment();
buf.flip(); // Prepare buffer for writing
SocketChannel clntChan = (SocketChannel) key.channel();
clntChan.write(buf);
if (!buf.hasRemaining()) { // Buffer completely written?
//Nothing left, so no longer interested in writes
key.interestOps(SelectionKey.OP_READ);
}
buf.compact(); // Make room for more data to be read in
}
}
二、NIO TCP客户端:
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class TCPEchoClientNonblocking {
public static void main(String args[]) throws Exception {
String server = "127.0.0.1"; // Server name or IP address
// Convert input String to bytes using the default charset
byte[] argument = "0123456789abcdefghijklmnopqrstuvwxyz".getBytes();
int servPort = 5500;
// Create channel and set to nonblocking
SocketChannel clntChan = SocketChannel.open();
clntChan.configureBlocking(false);
// Initiate connection to server and repeatedly poll until complete
if (!clntChan.connect(new InetSocketAddress(server, servPort))) {
while (!clntChan.finishConnect()) {
System.out.print("."); // Do something else
}
}
ByteBuffer writeBuf = ByteBuffer.wrap(argument);
ByteBuffer readBuf = ByteBuffer.allocate(argument.length);
int totalBytesRcvd = 0; // Total bytes received so far
int bytesRcvd; // Bytes received in last read
while (totalBytesRcvd < argument.length) {
if (writeBuf.hasRemaining()) {
clntChan.write(writeBuf);
}
if ((bytesRcvd = clntChan.read(readBuf)) == -1) {
throw new SocketException("Connection closed prematurely");
}
totalBytesRcvd += bytesRcvd;
System.out.print("."); // Do something else
}
System.out.println("Received: " + // convert to String per default charset
new String(readBuf.array(), 0, totalBytesRcvd).length());
clntChan.close();
}
}
三、NIO TCP服务端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;
public class TCPServerSelector {
private static final int BUFSIZE = 256; // Buffer size (bytes)
private static final int TIMEOUT = 3000; // Wait timeout (milliseconds)
public static void main(String[] args) throws IOException {
int[] ports = {5500};
// Create a selector to multiplex listening sockets and connections
Selector selector = Selector.open();
// Create listening socket channel for each port and register selector
for (int port : ports) {
ServerSocketChannel listnChannel = ServerSocketChannel.open();
listnChannel.socket().bind(new InetSocketAddress(port));
listnChannel.configureBlocking(false); // must be nonblocking to register
// Register selector with channel. The returned key is ignored
listnChannel.register(selector, SelectionKey.OP_ACCEPT);
}
// Create a handler that will implement the protocol
TCPProtocol protocol = new TCPEchoSelectorProtocol(BUFSIZE);
while (true) { // Run forever, processing available I/O operations
// Wait for some channel to be ready (or timeout)
if (selector.select(TIMEOUT) == 0) { // returns # of ready chans
System.out.print(".");
continue;
}
// Get iterator on set of keys with I/O to process
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while (keyIter.hasNext()) {
SelectionKey key = keyIter.next(); // Key is bit mask
// Server socket channel has pending connection requests?
if (key.isAcceptable()) {
System.out.println("----accept-----");
protocol.handleAccept(key);
}
// Client socket channel has pending data?
if (key.isReadable()) {
System.out.println("----read-----");
protocol.handleRead(key);
}
// Client socket channel is available for writing and
// key is valid (i.e., channel not closed)?
if (key.isValid() && key.isWritable()) {
System.out.println("----write-----");
protocol.handleWrite(key);
}
keyIter.remove(); // remove from set of selected keys
}
}
}
}
0
投稿
猜你喜欢
- 前言研究表明,Java堆中对象占据最大比重的就是字符串对象,所以弄清楚字符串知识很重要,本文主要重点聊聊字符串常量池。Java中的字符串常量
- 背景Springboot 默认把异常的处理集中到一个ModelAndView中了,但项目的实际过程中,这样做,并不能满足我们的要求。具体的自
- 有时,通过Runtime.getRuntime().exec()执行命令的有效负载有时会失败。使用Web Shell,反序列化利用或通过其他
- 这两个update都是使用generator生成的mapper.xml文件中,对dao层的更新操作update更新传回数据的所有字段,没有传
- 一、demo简介1.效果展示如下图,我截了三个瞬间,但其实这是一个连续的动画,就是这个大圆不停地吞下小圆。2.这个动画可以拆分为两部分,首先
- ContentProvider是内容提供者,可以跨进程提供数据。大家都知道,ContentProvider的启动,是在Application
- TimeSpan 结构 表示一个时间间隔。命名空间:System 程序集:mscorlib(在 mscorlib.dll 中)说
- 本文讲述了Java开发人员需知的十大戒律。分享给大家供大家参考,具体如下:作为一个Java开发人员提高自己代码的质量,可维护性,是个恒久不变
- Java类之间的关系图在Java以及其他的面向对象设计模式中,类与类之间主要有6种关系,他们分别是:依赖、关联、聚合、组合、继承、实现。他们
- Servlet 实现文件上传所谓文件上传就是将本地的文件发送到服务器中保存。例如我们向百度网盘中上传本地的资源或者我们将写好的博客上传到服务
- 简介API Gateway,时系统的唯一对外的入口,介于客户端和服务端之间的中间层,处理非业务功能,提供路由请求,鉴权,监控,缓存,限流等功
- Java提供的数据类型主要分为两大类:基本数据类型和引用数据类型。Java中的基本数据类型名称大小取值范围byte型 (字节)8bit-12
- 双向循环链表定义相比于单链表,有两个指针,next指针指向下一个结点,prior指针指向上一个结点,最后一个结点的next指针指向头结点,头
- 正在尝试分配更低的访问权限?在进行Java编程时会给我们报出如下提示怎么办?这里我们将给大家介绍详细的解决方法。首先,查看,控制台给出的提示
- 今天突发奇想,想做一个智能拼图游戏来给哄女友。需要实现这些功能第一图片自定义第二宫格自定义,当然我一开始就想的是3*3 4*4 5*5,没有
- 一、lombok简介lombok 提供了使用注解的形式帮助简化消除java代码。在编写Java代码时,通过使用对应的注解,可以简化开发,同时
- 摘要本文主要介绍基于SpringBoot定时任务ScheduledTaskRegistrar的动态扩展,实现定时任务的动态新增和删除。Sch
- 在讲述这个模式之前,我们先看一个案例:游戏回档游戏的某个场景,一游戏角色有生命力、攻击力、防御力等数据,在打Boss前和后会不一样,我们允许
- 题目:给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路
- idea无法切换分支报错idea拉取项目后,master分支配置完项目基础配置后,生成.iml等文件不受git管理后无法检出其他分支报错如下