在做关于NIO TCP编程小案例时遇到无法监听write的问题,没想到只是我的if语句的位置放错了位置,哎,看了半天没看出来

贴下课堂笔记:

在Java中使用NIO进行网络TCP套接字编程主要以下几个类:

ServerSocketChannel: 服务端套接字通道,主要监听接收客户端请求

Selector:通道选择器,主要用于管理服务端通道和所有客户端通道(监听通道中发生的事件),也就说是一个多路通道复用器。

SelectorKey: 事件选择键

SocketChannel: 套接字通道(客户端)

这篇文章《NIO编程中的SelectionKey.interestOps方法中的逻辑运算》解决了我一些疑问,地址:https://blog.csdn.net/woaiqianzhige/article/details/78696188

NIO 套接字服务端开发步骤:

  1. 创建选择器
  2. 启动服务端通道
  3. 设置服务端通道为非阻塞模式
  4. 将服务端通道注册到选择器
  5. 轮训通道事件
  6. 处理通道事件
  7. 关闭通道(可选)

案例:服务端接收客户端发送的短信息,服务端回复已收到。

服务端代码:

 import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set; public class Server {
private Selector selector;
private ServerSocketChannel serverSocketChannel;
private ByteBuffer byteBuffer = ByteBuffer.allocate(8192); /**
* 构造方法 启动服务器
*
* @param port
* @throws IOException
*/
public Server() {
try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(10086));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server start successful with port: 10086");
} catch (ClosedChannelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) throws Exception {
new Server().start();
} private void start() {
while (true) {
try {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (!key.isValid()) {
continue;
}
if (key.isAcceptable()) {
accept(key);
}
if (key.isReadable()) {
receive(key);
}
if (key.isWritable()) {
reply(key);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
} private void reply(SelectionKey key) {
try {
SocketChannel socketChannel = (SocketChannel) key.channel();
byteBuffer.clear();
String message = "receive success";
byteBuffer.put(message.getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
System.out.println("reply:" + message);
byteBuffer.clear();
key.interestOps(SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
} private void receive(SelectionKey key) {
try {
SocketChannel socketChannel = (SocketChannel) key.channel();
byteBuffer.clear();
int flag = socketChannel.read(byteBuffer);
if (flag == -1) {
key.channel().close();
key.cancel();
return;
}
byteBuffer.flip();
byte[] buf = new byte[byteBuffer.remaining()];
byteBuffer.get(buf);
String message = new String(buf);
System.out.println("receive message:" + message);
byteBuffer.clear();
key.interestOps(SelectionKey.OP_WRITE);
} catch (IOException e) {
e.printStackTrace();
}
} private void accept(SelectionKey key) {
try {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
System.out.println(Thread.currentThread().getName() + ": create client channel.");
} catch (ClosedChannelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

客户端代码:

 import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner; public class Client {
private Selector selector;
private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
private SocketChannel socketChannel; public Client() {
try {
selector = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
socketChannel.connect(new InetSocketAddress("127.0.0.1", 10086));
System.out.println("Client start successful");
} catch (ClosedChannelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
new Client().start();
} private void start() {
while (true) {
try {
selector.select();
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (!key.isValid()) {
continue;
}
if (key.isConnectable()) {
if (socketChannel.finishConnect()) {
key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
System.out.println("Client connect server success");
}
}
if (key.isReadable()) {
receive(key);
}
if (key.isWritable()) {
reply(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
} private void reply(SelectionKey key) {
try {
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
byteBuffer.clear();
System.out.println("please input message:");
String message = scanner.next();
byteBuffer.put(message.getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteBuffer.clear();
System.out.println("send message:" + message);
key.interestOps(SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
} private void receive(SelectionKey key) {
try {
byteBuffer.clear();
socketChannel.read(byteBuffer);
byteBuffer.flip();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
String message = new String(bytes).trim();
System.out.println("receive message: " + message);
byteBuffer.clear();
key.interestOps(SelectionKey.OP_WRITE);
} catch (IOException e) {
e.printStackTrace();
}
}
}

真是粗心大意了。。。特发此博文给我自己涨涨记性

在做关于NIO TCP编程小案例时遇到无法监听write的问题,没想到只是我的if语句的位置放错了位置,哎,看了半天没看出来的更多相关文章

  1. vue学习-day05 -- 案例:名字合并(监听data数据的改变)

    1.案例:名字合并(监听data数据的改变) 使用keyup事件监听data数据的改变 <!DOCTYPE html> <html> <head> <titl ...

  2. java Socket(TCP)编程小项目

    package 服务器端相关操作; import java.io.Serializable; /* * 创建存储需要传输信息的对象,方便客户端向服务器端传送数据 */ public class Cli ...

  3. 微信小程序实现watch属性监听数据变化

    Vue 提供了一种通用的方式来观察和响应 Vue 实例上的数据变动:监听属性 watch. 虽然watch的滥用会导致性能不佳,但在一些情况下我们还是需要watch,使得代码更加简洁.逻辑更加清晰(其 ...

  4. Scratch编程小案例:愤怒的小牛

    愤怒的小鸟曾经很热门,网上还说他是程序员最喜欢玩的游戏.最先我是WIKIOI的评测页面看到他的,后来在2014年全国信息学奥林匹克联赛第一天第三题飞扬的小鸟也看到了它.因此,突然想做一个类似愤怒的小鸟 ...

  5. 《java入门第一季》之UDP协议下的网络编程小案例

    需求,一台电脑发送数据,其他电脑都可以收到该数据.使用广播地址. 发送端: import java.io.BufferedReader; import java.io.IOException; imp ...

  6. 小程序组件中有bindinput监听报异常

    真机上有问题,ide上是没问题的,   组件有处理函数,结果异常说页面没有处理函数,加上处理函数后就不报异常了.

  7. 广播接收者案例_sd卡状态监听

    (1)定义广播接收者 import android.content.BroadcastReceiver; import android.content.Context; import android. ...

  8. 《java入门第一季》之类小案例(模拟用户登录)

    首先是做一个用户登录的小案例.在此基础上加入其它逻辑. import java.util.Scanner; /* * 模拟登录,给三次机会,并提示还有几次.如果登录成功,就可以玩猜数字小游戏了. * ...

  9. 第13章 TCP编程(3)_基于自定义协议的多进程模型

    5. 自定义协议编程 (1)自定义协议:MSG //自定义的协议(TLV:Type length Value) typedef struct{ //协议头部 ];//TLV中的T unsigned i ...

随机推荐

  1. 一个基于原生JavaScript开发的、轻量的验证码生成插件

    Vcode.js 一个基于原生JavaScript开发的.轻量的验证码生成插件 V: 1.0.0 DEMO:https://jofunliang.github.io/Vcode.js/example. ...

  2. 浅谈通信网络(三)——TCP/IP协议

    简介 Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议.In ...

  3. 解决window.showModalDialog在Firefox无法支持

    在网页程序中,有时我们会希望使用者按下按钮后开启一个保持在原窗口前方的子窗口,而在IE中,我们可以使用showModalDialog来达成,语法如下 : vReturnValue = window.s ...

  4. Windows Server 2008取消登录前的Ctrl+Alt+Delete组合键操作

    前言: 在Windows Server 2008服务器中,为了防止人们登录服务器时错误的将账户和密码输入其他地方导致信息泄漏,所以在我们登录Windows Server 2008服务器操作系统时会要求 ...

  5. org.springframework.web.servlet.PageNotFound

    2017-07-11 16:36:13.489 WARN [http-nio-8032-exec-16]org.springframework.web.servlet.PageNotFound -Re ...

  6. 值得注意的CSS属性

    文本TEXT letter-spacing 字符间距 word-spacing 字间距 line-height 行高 text-decoration 修饰(下划线) text-indent 首行缩进 ...

  7. fastdfs group通过添加硬盘扩容

    通过给group的机器添加硬盘的方式,实现某个group的扩容. fastdfs在一台服务器支持多个store_path,每个store_path指向一个存储路径.url "M00/3F/E ...

  8. app后端设计(6)-- LBS

    在LBS的应用中,一个基本的需求是查找附近的用户,现在有两种做法: 1. 使用mysql的空间数据库,具体做法参考:http://blog.sina.com.cn/s/blog_a48af8c0010 ...

  9. golang map的判断,删除

    http://blog.sina.com.cn/s/blog_9e14446a01018q8p.html map是一种key-value的关系,一般都会使用make来初始化内存,有助于减少后续新增操作 ...

  10. Java 读书笔记 (八) 修饰符

    Java语言提供了很多修饰符,主要分为以下两类: 访问修饰符 非访问修饰符 访问控制修饰符 default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符.使用对象.类.接口.变量.方法. ...