《图解设计模式》之简易UML类图

每一种设计模式都可以用UML类图来表示,能看懂UML类图,就能够对该设计模式有宏观上的认知和理解。单个类里面的简单格式以长方形表示类,长方形内部被分成3个区域,分别表示类名、属性名、方法名。格式含义斜体抽象类、抽象方法下
阅读更多

理解Servlet与Filter的关系与设计思路

什么是Servlet对一个HTTP请求的正常的处理流程是:发送HTTP请求服务端的HTTP服务器收到请求调用业务逻辑返回HTTP响应产生了下面3个问题:HTTP 服务器怎么知道要调用哪个业务逻辑,也就是 Java 类的哪个方法呢?HTTP服务器可以被设计成收到请求后,接续寻找该请求的处理逻辑,但是这
阅读更多

Spring系中常见注解用法说明

@PathVariable与@RequestParm在spring mvc中,有@requestparm, @requestbody和@pathvariable 三种注解来获得浏览器端的参数,其中@requestparm是取自url中“?”之后的a=b&c=d,@requestbody 来自
阅读更多

TCP协议的三次握手与四次挥手

TCP提供面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接。因此TCP是一种可靠的的运输服务,但是正因为这样,不可避免的增加了许多的开销,比如确认,流量控制等。字段含义序号seq,占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号。例如,一段报文的序号字段值是 301
阅读更多

MySQL备份记录

备份

命令行下具体用法如下:

mysqldump -u用戶名 -p密码 -d 数据库名 表名 > 脚本名;

导出整个数据库结构和数据
mysqldump -h localhost -uroot -p123456 database > dump.sql

导出单个数据表结构和数据
mysqldump -h localhost -uroot -p123456 database table > dump.sql

导出整个数据库结构(不包含数据)
mysqldump -h localhost -uroot -p123456 -d database > dump.sql

导出单个数据表结构(不包含数据)
mysqldump -h localhost -uroot -p123456 -d database table > dump.sql

数据还原

1、还原使用mysqldump命令备份的数据库的语法如下:
mysql -u root -p [dbname] < backup.sq

示例:
mysql -u root -p < C:\backup.sql

docker命令记录

安装及配置docker(基于Ubuntu)sasurai@ubuntu:~$ sudo apt install docker.iosasurai@ubuntu:~$ docker versionClient: Version: 19.03.2 API version:
阅读更多

JUC源码学习之AbstractQueuedSynchronizer

源码基于的Oracle JDK版本为:11.0.5什么是CLH队列简单理解是一个双向链表,链表中存放的是包含线程在内的信息,队首的是正在执行的线程,后面的是等待执行的线程,如下图所示:Node概述The wait queue is a variant of a "CLH" (Cr
阅读更多

leetcode回溯法题目解法若干

N皇后问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.util.ArrayList;
import java.util.List;

/*
* @lc app=leetcode id=51 lang=java
*
* [51] N-Queens
*/
public class Solution {

List<List<String>> result = new ArrayList<>();

private static int total = 0;

public List<List<String>> solveNQueens(int n) {
total = n;
int[][] board = new int[n][n];
backtrack(board, 1);
return result;
}

private void backtrack(int[][] board, int idx) {
if (idx > total) {
// ok
result.add(transform(board));
return;
}

for (int i = 0; i < total; i ++) {
if (isOk(board, idx - 1, i)) {
//
board[idx - 1][i] = 1;
backtrack(board, idx + 1);
board[idx - 1][i] = 0;
}
}
}

private boolean isOk(int[][] board, int xx, int yy) {
for (int i = 0; i < total; i++) {
if (board[xx][i] == 1) {
return false;
}
if (board[i][yy] == 1) {
return false;
}
}
int x = xx, y = yy;
while (x < total && y >= 0)
if (board[x ++][y --] == 1)
return false;
x = xx; y = yy;
while (x < total && y < total)
if (board[x ++][y ++] == 1)
return false;
x = xx; y = yy;
while (x >= 0 && y >= 0)
if (board[x --][y --] == 1)
return false;
x = xx; y = yy;
while (x >=0 && y < total)
if (board[x --][y ++] == 1)
return false;
// System.out.println("OK");
return true;
}

private List<String> transform(int[][] board) {
List<String> oneAnswer = new ArrayList<>();
for (int i = 0; i < board.length; i ++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < board[i].length; j ++) {
sb.append(board[i][j] == 0 ? '.' : 'Q');
}
oneAnswer.add(sb.toString());
}
// showAnswer(oneAnswer);
return oneAnswer;
}

private void showAnswer(List<String> answer) {
System.out.println();
for (String line : answer) {
System.out.println(line);
}
}

public static void main(String[] args) {
List<List<String>> result = new Solution().solveNQueens(4);
System.out.println(result.size());
}
}

Letter Combinations of a Phone Number

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.ArrayList;
import java.util.List;

/*
* @lc app=leetcode id=17 lang=java
*
* [17] Letter Combinations of a Phone Number
*/
class Solution {
private int[][] maps = {
{},
{},
{'a', 'b', 'c'},
{'d', 'e', 'f'},
{'g', 'h', 'i'},
{'j', 'k', 'l'},
{'m', 'n', 'o'},
{'p', 'q', 'r', 's'},
{'t', 'u', 'v'},
{'w', 'x', 'y', 'z'}
};
List<String> result = new ArrayList<>();
public List<String> letterCombinations(String digits) {
backtrack(digits, "", 0);
return result;
}
private void backtrack(String digits, String sb, int idx) {
if (idx >= digits.length()) {
if (sb.length() > 0)
result.add(sb.toString());
return;
}
int mapsIdx = digits.charAt(idx) - '0';
for (int i = 0; i < maps[mapsIdx].length; i ++) {
backtrack(digits, sb + (char) maps[mapsIdx][i], idx + 1);
}
}
}

Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

1
2
3
4
5
6
7
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
List<String> sets = new ArrayList<>();

// 22
public List<String> generateParenthesis(int n) {
produce(2 * n, 0, n, n, "");
return sets;
}

private void produce(int blank, int sum, int lcnt, int rcnt, String seq) {
if (sum < 0)
return;

if (blank == 0) {
sets.add(seq);
return;
}

if (lcnt > 0) {
produce(blank - 1, sum + 1, lcnt - 1, rcnt, seq + "(");
}

if (rcnt > 0) {
produce(blank - 1, sum - 1, lcnt, rcnt - 1, seq + ")");
}
}
}

Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

Each of the digits 1-9 must occur exactly once in each row.

Each of the digits 1-9 must occur exactly once in each column.

Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character ‘.’.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
* @lc app=leetcode id=37 lang=java
*
* [37] Sudoku Solver
*/
public class Solution {
private static class Point {
public int x, y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}

@Override
public String toString() {
return "<" + x + ", " + y + ">";
}
}

static char[][] data = {
{'5', '3', '.', '.', '7', '.', '.', '.', '.'},
{'6', '.', '.', '1', '9', '5', '.', '.', '.'},
{'.', '9', '8', '.', '.', '.', '.', '6', '.'},
{'8', '.', '.', '.', '6', '.', '.', '.', '3'},
{'4', '.', '.', '8', '.', '3', '.', '.', '1'},
{'7', '.', '.', '.', '2', '.', '.', '.', '6'},
{'.', '6', '.', '.', '.', '.', '2', '8', '.'},
{'.', '.', '.', '4', '1', '9', '.', '.', '5'},
{'.', '.', '.', '.', '8', '.', '.', '7', '9'}
};

public static void main(String[] args) {
new Solution().solveSudoku(data);
printBoard(data, "最终结果");
}

private static void printBoard(char[][] data, String msg) {
System.out.println("\n" + msg + ":");
for (int i = 0; i < data.length; i ++) {
for (int j = 0; j < data[i].length; j++) {
System.out.print(data[i][j] + " ");
}
System.out.println();
}
System.out.println();
}

boolean over = false;

public void solveSudoku(char[][] board) {
backtrack(board, nextPoint(board, new Point(0, 0)));
}

private void backtrack(char[][] board, Point focus) {
if (over || isOver(board)) {
over = true;
return;
}

if (focus == null) {
over = true;
return;
}

for (int val = 1; val <= 9 && !over; val++) {
board[focus.x][focus.y] = (char) ('0' + val);
if (isValid(board, focus, (char) ('0' + val))) {
backtrack(board, nextPoint(board, focus));
}
}
if (!over)
board[focus.x][focus.y] = '.';
}

private boolean isValid(char[][] board, Point p, char val) {
// 横向
for (int i = 0; i <= 8; i++) {
if (i != p.y && board[p.x][i] == val)
return false;
}
// 纵向
for (int i = 0; i <= 8; i++) {
if (i != p.x && board[i][p.y] == val)
return false;
}
// 方形
for (int i = (p.x / 3 * 3); i <= (p.x / 3 * 3) + 2; i++) {
for (int j = (p.y / 3 * 3); j <= (p.y / 3 * 3) + 2; j++) {
if (i != p.x && j != p.y && board[i][j] == val)
return false;
}
}
// printBoard(board, "位置" + p + ", 对值<" + (char)val + ">合适");
return true;
}

private boolean isOver(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == '.')
return false;
}
}
return true;
}

private Point nextPoint(char[][] board, Point p) {
Point returnPoint = null;
int x = p.x, y = p.y;
while (x <= 8 && returnPoint == null) {
for (int i = y; i <= 8; i++) {
if (board[x][i] == '.') {
returnPoint = new Point(x, i);
break;
}
}
y = 0;
x ++;
}
// System.out.println(p + " -> " + returnPoint);
return returnPoint;
}
}

Combination Sum

相关问题:Combination Sum II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

import java.util.ArrayList;
import java.util.List;

/*
* @lc app=leetcode id=39 lang=java
*
* [39] Combination Sum
*/
class Solution {

List<List<Integer>> result = new ArrayList();

private int maxInt = 0;

public List<List<Integer>> combinationSum(int[] candidates, int target) {
sort(candidates);
maxInt = candidates[candidates.length - 1] + 1;
backtrack(candidates, target, new ArrayList<>());
return result;
}

private void sort(int[] arr) {
for (int i = 0; i < arr.length; i ++) {
for (int j = i; j < arr.length; j ++) {
if (arr[i] > arr[j]) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}

private void backtrack(int[] candidates, int target, List<Integer> answer) {
if (target == 0) {
// find the answer
// showArray(answer);
if (!isDuplicated(result, answer, candidates))
result.add(new ArrayList<>(answer));
else {
// System.out.println("Duplicated");
}
} else if (target < 0) {
return;
}

for (int i = 0; i < candidates.length; i++) {
answer.add(candidates[i]);
backtrack(candidates, target - candidates[i] , answer);
answer.remove(answer.size() - 1);
}
}

private void showArray(List<Integer> arr) {
System.out.print("[");
for (int i = 0; i < arr.size(); i ++) {
System.out.print(String.valueOf(arr.get(i)) + (i == arr.size() - 1 ? "]" : ", "));
}
System.out.println();
}

private boolean isDuplicated(List<List<Integer>> result, List<Integer> oneAnswer, int[] candidates) {
for (List<Integer> r : result) {
if (r.size() == oneAnswer.size()) {
int[] sr = new int[maxInt];
int[] si = new int[maxInt];
for (int i = 0; i < r.size(); i ++) {
// System.out.println(r.get(i) + " + 1");
sr[r.get(i)] ++;
// System.out.println(oneAnswer.get(i) + " + 1");
si[oneAnswer.get(i)] ++;
}
boolean isDuplicatedWithThisResult = true;
for (int i = 0; i < candidates.length; i ++) {
// System.out.println(candidates[i] + "," + sr[candidates[i]] + "," + si[candidates[i]]);
if (sr[candidates[i]] != si[candidates[i]]) {
isDuplicatedWithThisResult = false;
continue;
}
}
if (isDuplicatedWithThisResult)
return true;
}
}
return false;
}

public static void main(String[] args) {
int [] arr = {8,7,4,3};
new Solution().combinationSum(arr, 11);
}
}

Permutations

相关问题:Permutations II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
List<List<Integer>> result = new ArrayList();

private boolean[] USAGE;

public List<List<Integer>> permute(int[] nums) {
USAGE = new boolean[nums.length];
List<Integer> answer = new ArrayList();
backtrack(nums, 0, answer);
return result;
}

private void backtrack(int[] nums, int idx, List<Integer> answer) {
if (idx >= nums.length) {
result.add(new ArrayList(answer));
return;
}
for (int i = 0; i < nums.length; i ++) {
if (!USAGE[i]) {
answer.add(nums[i]);USAGE[i] = true;
backtrack(nums, idx + 1, answer);
answer.remove(answer.size() - 1);USAGE[i] = false;
}
}
}
}

Permutation Sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
private boolean[] usage;
private String result;
private int targetIdx, currentIdx;
private boolean over = false;
public String getPermutation(int n, int k) {
targetIdx = k;
usage = new boolean[n + 1];
StringBuilder sb = new StringBuilder();
backtrack(n, 1, sb);
return result;
}

private void backtrack(int n, int idx, StringBuilder sb) {
if (over)
return;
if (idx > n) {
currentIdx ++;
if (currentIdx == targetIdx) {
result = sb.toString();
over = true;
}
return ;
}
for (int i = 1; i <= n; i ++) {
if (over)
break;
if (!usage[i]) {
sb.append(i);usage[i] = true;
backtrack(n, idx + 1, sb);
sb.deleteCharAt(sb.length() - 1);usage[i] = false;
}
}
}
}

Combinations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
private List<List<Integer>> result = new ArrayList();
private boolean[] USAGE;
private int depth;

public List<List<Integer>> combine(int n, int k) {
depth = k;
USAGE = new boolean[n + 1];
backtrack(1, n, 1, new ArrayList<>());
return result;
}

private void backtrack(int startIdx, int n, int idx, List<Integer> answer) {
if (idx > depth) {
result.add(new ArrayList(answer));
return;
}
for (int i = startIdx; i <= n; i ++) {
if (!USAGE[i]) {
answer.add(i);USAGE[i] = true;
backtrack(i + 1, n, idx + 1, answer);
answer.remove(answer.size() - 1);USAGE[i] = false;
}
}
}
}

SpringBoot启动logo配置

起始每次打开Spring Boot的应用的main方法时,都会出现下面如下所示Spring的Logo。之前没有注意过这个Logo的配置,直到看到一个Spring Cloud的开源示例项目时,看到了一个配置如下:有一个问题:为什么放在classpath下且名字为banner.txt就能够配置成功?源码
阅读更多

两个Netty入门用法Demo

大概一年多前,用过Netty做局域网内自动组网,但是当时的主要代码不是我写的,并且时间过了很久,忘得差不多了,然而发现Netty确实是一个很有意思的框架,值得去深入研究、学习。本文的例子,之前也看过、写过,在各种介绍Netty的书籍中都有看到,并且Netty的官方文档也有这样的例子。

EchoServer

Netty官方Echo例子,其实在源码中也有该例子。

EchoServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class EchoServer {

private int port;

public EchoServer(int port) {
this.port = port;
}

public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
try {
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}

public static void main(String[] args) {
new EchoServer(8888).run();
System.out.println("运行完毕");
}
}

EchoServerHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;

import java.util.Arrays;
import java.util.List;

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = ((ByteBuf) msg);
System.out.println("Server received : " + in.toString(CharsetUtil.UTF_8));
ctx.writeAndFlush(msg);
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}

EchoClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class EchoClient {

private static int port = 8888;

public static void main(String[] args) throws InterruptedException {
EventLoopGroup workGroup = new NioEventLoopGroup();

try {
Bootstrap b = new Bootstrap();
b.group(workGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture f = b.connect("localhost", port).sync();
f.channel().closeFuture().sync();
} finally {
workGroup.shutdownGracefully();
}
}
}

EchoClientHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("Hello world", CharsetUtil.UTF_8));
System.out.println("通道已打开");
}

// @Override
// public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// ByteBuf m = (ByteBuf) msg; // (1)
// try {
// System.out.println("Client received : " + ((ByteBuf) msg).toString(CharsetUtil.UTF_8));
// } finally {
// m.release();
// }
// }

@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("Client received: " + msg.toString(CharsetUtil.UTF_8));
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}

TimeServer

这个例子主要来自《Netty权威指南》,包括后面的粘包和拆包的例子都是基于此demo。

TimeServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class TimeServer {

public void bind(int port) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();

try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new TimeServerHandler());
}
});
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException var9) {
var9.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}

public static void main(String[] args) {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException var3) {
System.out.println("输入参数有误");
}
}
new TimeServer().bind(port);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Date;

public class TimeServerHandler extends ChannelInboundHandlerAdapter {

private int counter;

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String body = (String) msg;
System.out.println("The time server receive order : " + body + "; the counter is : " + ++counter);
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? (new Date()).toString() : "BAD ORDER";
currentTime = currentTime + System.getProperty("line.separator");
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.writeAndFlush(resp);
}

public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}

TimeClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

public class TimeClient {

public void connect(String host, int port) throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup();

try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new ChannelHandler[]{new TimeClientHandler()});
}
});
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}

public static void main(String[] args) throws Exception {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException var3) {
System.out.println("输入参数有误");
}
}

new TimeClient().connect("localhost", port);
}
}

TimeClientHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

@Slf4j
public class TimeClientHandler extends ChannelInboundHandlerAdapter {

private int counter;

private byte[] req;

public TimeClientHandler() {
req = ("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();
}

public void channelActive(ChannelHandlerContext ctx) throws Exception {
ByteBuf msg;
for (int i = 0; i < 100; i++) {
msg = Unpooled.buffer(req.length);
msg.writeBytes(req);
ctx.writeAndFlush(msg);
}
}

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String body = (String) msg;
System.out.println("Now is : " + body + "; the counter is : " + ++ counter);
}

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.info("Unexpected exception from downstream : " + cause.getMessage());
ctx.close();
}
}

这里的代码是已经处理好了粘包/拆包问题,如果要看粘包/拆包的现象,只需要将LineBasedFrameDecoderStringDecoder不加入到pipeline中即可。

参考:
https://netty.io/wiki/index.html
https://netty.io/wiki/user-guide-for-4.x.html