└── common
├── .classpath
├── .gitignore
├── .project
├── .settings
├── org.eclipse.core.resources.prefs
├── org.eclipse.jdt.core.prefs
├── org.eclipse.jdt.ui.prefs
└── org.eclipse.m2e.core.prefs
├── doc
├── README.md
├── p2p开发项目.xls
└── 聊天开发项目.xls
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── son
│ └── chat
│ └── common
│ ├── net
│ ├── config
│ │ └── SocketChannelConfig.java
│ ├── core
│ │ ├── coder
│ │ │ ├── ICoder.java
│ │ │ ├── ICoderCtx.java
│ │ │ ├── ICoderParserManager.java
│ │ │ ├── IHandle.java
│ │ │ ├── IPackageCoder.java
│ │ │ └── impl
│ │ │ │ ├── CoderParser.java
│ │ │ │ ├── CoderParserManager.java
│ │ │ │ └── CoderResult.java
│ │ ├── handle
│ │ │ ├── AbstractSocketHandle.java
│ │ │ ├── ClientManagerHandle.java
│ │ │ ├── EmptyHandle.java
│ │ │ ├── HeartHandle.java
│ │ │ ├── ISocketHandle.java
│ │ │ ├── PipeHandle.java
│ │ │ └── SessionHandle.java
│ │ ├── session
│ │ │ ├── ISession.java
│ │ │ ├── ISessionFactory.java
│ │ │ ├── Key.java
│ │ │ ├── Session.java
│ │ │ ├── SessionFactory.java
│ │ │ └── SessionKey.java
│ │ └── socket
│ │ │ ├── IChannel.java
│ │ │ ├── IClientSocketService.java
│ │ │ ├── IPipeChannel.java
│ │ │ ├── IServerSocketService.java
│ │ │ ├── ISocketChannel.java
│ │ │ ├── ISocketPool.java
│ │ │ ├── ISocketService.java
│ │ │ └── impl
│ │ │ ├── AbstractISocketChannel.java
│ │ │ ├── ClientPipeChannel.java
│ │ │ ├── ClientSocket.java
│ │ │ ├── ServerSocket.java
│ │ │ ├── SocketChannelCtx.java
│ │ │ └── SocketPool.java
│ ├── exception
│ │ ├── CoderException.java
│ │ └── NetException.java
│ └── util
│ │ ├── ByteHelper.java
│ │ ├── IpUtil.java
│ │ ├── NamedThreadFactory.java
│ │ └── NioUtil.java
│ └── protocol
│ ├── ChatHandle.java
│ └── PackageDefaultCoder.java
└── test
└── java
└── org
└── son
└── chat
└── common
├── ChatTestServerHandle.java
├── TestByteBuffer.java
├── TestNioClient.java
├── TestNioServer.java
└── TestSelector.java
/common/.classpath:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /log
--------------------------------------------------------------------------------
/common/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | common
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.m2e.core.maven2Builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.m2e.core.maven2Nature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/common/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=utf-8
3 | encoding//src/test/java=utf-8
4 | encoding/=UTF-8
5 |
--------------------------------------------------------------------------------
/common/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
3 | org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
4 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
5 | org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
6 | org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
7 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
8 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
9 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
10 | org.eclipse.jdt.core.compiler.compliance=1.7
11 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
12 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
13 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
14 | org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
15 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
16 | org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
17 | org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
18 | org.eclipse.jdt.core.compiler.problem.deadCode=warning
19 | org.eclipse.jdt.core.compiler.problem.deprecation=warning
20 | org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
21 | org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
22 | org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
23 | org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
24 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
25 | org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
26 | org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
27 | org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
28 | org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
29 | org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
30 | org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
31 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
32 | org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
33 | org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
34 | org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
35 | org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
36 | org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
37 | org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
38 | org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
39 | org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
40 | org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
41 | org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
42 | org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
43 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
44 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
45 | org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
46 | org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
47 | org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
48 | org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
49 | org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
50 | org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
51 | org.eclipse.jdt.core.compiler.problem.nullReference=warning
52 | org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
53 | org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
54 | org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
55 | org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
56 | org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
57 | org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
58 | org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
59 | org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
60 | org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
61 | org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
62 | org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
63 | org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
64 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
65 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
66 | org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
67 | org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
68 | org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
69 | org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
70 | org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
71 | org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
72 | org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
73 | org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
74 | org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
75 | org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
76 | org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
77 | org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
78 | org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
79 | org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
80 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
81 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
82 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
83 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
84 | org.eclipse.jdt.core.compiler.problem.unusedImport=warning
85 | org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
86 | org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
87 | org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
88 | org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
89 | org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
90 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
91 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
92 | org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
93 | org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
94 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
95 | org.eclipse.jdt.core.compiler.source=1.7
96 | org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
97 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
98 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
99 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
100 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
101 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
102 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
103 | org.eclipse.jdt.core.formatter.alignment_for_assignment=0
104 | org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
105 | org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
106 | org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
107 | org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
108 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
109 | org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
110 | org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
111 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
112 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
113 | org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
114 | org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
115 | org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
116 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
117 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
118 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
119 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
120 | org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
121 | org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
122 | org.eclipse.jdt.core.formatter.blank_lines_after_package=1
123 | org.eclipse.jdt.core.formatter.blank_lines_before_field=0
124 | org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
125 | org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
126 | org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
127 | org.eclipse.jdt.core.formatter.blank_lines_before_method=1
128 | org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
129 | org.eclipse.jdt.core.formatter.blank_lines_before_package=0
130 | org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
131 | org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
132 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
133 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
134 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
135 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
136 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
137 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
138 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
139 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
140 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
141 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
142 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
143 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
144 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
145 | org.eclipse.jdt.core.formatter.comment.format_block_comments=true
146 | org.eclipse.jdt.core.formatter.comment.format_header=false
147 | org.eclipse.jdt.core.formatter.comment.format_html=true
148 | org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
149 | org.eclipse.jdt.core.formatter.comment.format_line_comments=true
150 | org.eclipse.jdt.core.formatter.comment.format_source_code=true
151 | org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
152 | org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
153 | org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
154 | org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
155 | org.eclipse.jdt.core.formatter.comment.line_length=80
156 | org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
157 | org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
158 | org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
159 | org.eclipse.jdt.core.formatter.compact_else_if=true
160 | org.eclipse.jdt.core.formatter.continuation_indentation=2
161 | org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
162 | org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
163 | org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
164 | org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
165 | org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
166 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
167 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
168 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
169 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
170 | org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
171 | org.eclipse.jdt.core.formatter.indent_empty_lines=false
172 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
173 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
174 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
175 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
176 | org.eclipse.jdt.core.formatter.indentation.size=4
177 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
178 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
179 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
180 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
181 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
182 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
183 | org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
184 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
185 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
186 | org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
187 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
188 | org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
189 | org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
190 | org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
191 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
192 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
193 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
194 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
195 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
196 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
197 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
198 | org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
199 | org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
200 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
201 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
202 | org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
203 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
204 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
205 | org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
206 | org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
207 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
208 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
209 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
210 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
211 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
212 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
213 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
214 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
215 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
216 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
217 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
218 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
219 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
220 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
221 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
222 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
223 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
224 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
225 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
226 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
227 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
228 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
229 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
230 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
231 | org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
232 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
233 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
234 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
235 | org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
236 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
237 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
238 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
239 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
240 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
241 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
242 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
243 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
244 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
245 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
246 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
247 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
248 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
249 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
250 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
251 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
252 | org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
253 | org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
254 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
255 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
256 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
257 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
258 | org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
259 | org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
260 | org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
261 | org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
262 | org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
263 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
264 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
265 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
266 | org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
267 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
268 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
269 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
270 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
271 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
272 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
273 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
274 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
275 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
276 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
277 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
278 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
279 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
280 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
281 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
282 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
283 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
284 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
285 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
286 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
287 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
288 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
289 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
290 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
291 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
292 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
293 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
294 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
295 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
296 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
297 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
298 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
299 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
300 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
301 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
302 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
303 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
304 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
305 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
306 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
307 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
308 | org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
309 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
310 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
311 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
312 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
313 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
314 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
315 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
316 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
317 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
318 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
319 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
320 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
321 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
322 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
323 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
324 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
325 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
326 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
327 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
328 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
329 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
330 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
331 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
332 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
333 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
334 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
335 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
336 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
337 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
338 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
339 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
340 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
341 | org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
342 | org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
343 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
344 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
345 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
346 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
347 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
348 | org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
349 | org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
350 | org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
351 | org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
352 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
353 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
354 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
355 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
356 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
357 | org.eclipse.jdt.core.formatter.join_lines_in_comments=true
358 | org.eclipse.jdt.core.formatter.join_wrapped_lines=true
359 | org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
360 | org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
361 | org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
362 | org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
363 | org.eclipse.jdt.core.formatter.lineSplit=200
364 | org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
365 | org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
366 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
367 | org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
368 | org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
369 | org.eclipse.jdt.core.formatter.tabulation.char=mixed
370 | org.eclipse.jdt.core.formatter.tabulation.size=8
371 | org.eclipse.jdt.core.formatter.use_on_off_tags=false
372 | org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
373 | org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
374 | org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
375 | org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
376 |
--------------------------------------------------------------------------------
/common/.settings/org.eclipse.jdt.ui.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | formatter_profile=_test
3 | formatter_settings_version=12
4 | org.eclipse.jdt.ui.javadoc=false
5 | org.eclipse.jdt.ui.text.custom_code_templates=/**\r\n * @return the ${bare_field_name}\r\n *//**\r\n * @param ${param} the ${bare_field_name} to set\r\n *//**\r\n * ${tags}\r\n *//**\r\n * \r\n *//**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n *//**\r\n * \r\n *//**\r\n * ${tags}\r\n *//* (non-Javadoc)\r\n * ${see_to_overridden}\r\n *//**\r\n * ${tags}\r\n * ${see_to_target}\r\n */${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}\r\n\r\n\r\n\r\n// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();// ${todo} Auto-generated method stub\r\n${body_statement}${body_statement}\r\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
6 |
--------------------------------------------------------------------------------
/common/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/common/doc/README.md:
--------------------------------------------------------------------------------
1 | * 链式编/解码
2 | * 链路层链式处理
3 | * 管道管理socket
4 | * 多协议处理非常方便
5 | * 仿netty NioEventLoop 单线程串行处理
6 |
7 | ========
8 | 侍加功能 :
9 | * 自动化编/解码
10 | * rpc 接口增强使用
11 |
12 | 简单聊天例子
13 | ========
14 |
15 | server
16 | ======
17 | TestNioServer
18 | ```
19 | //创建session管理工厂
20 | ISessionFactory sessionFactory = new SessionFactory();
21 | //创建编/解码管理
22 | ICoderParserManager coderParserManager = new CoderParserManager();
23 | //注册包编/解码,处理业务
24 | coderParserManager.register(CoderParser.valueOf("server chat", PackageDefaultCoder.valueOf(), new ChatTestServerHandle()));
25 | //创建ServerSocket 实例
26 | ServerSocket serverSocket=ServerSocket.valueOf(SocketChannelConfig.valueOf(6969), 10,20,coderParserManager, sessionFactory);
27 |
28 | //启动服务
29 | serverSocket.start();
30 | //阻塞当前线程
31 | serverSocket.sync();
32 | //关闭处理
33 | serverSocket.stop();
34 |
35 | ```
36 | client
37 | ======
38 | TestNioClient
39 | 传统方式连接
40 | ```
41 | //创建编/解码管理
42 | ICoderParserManager coderParserManager = new CoderParserManager();
43 | //注册包编/解码,处理业务
44 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
45 | //创建ClientSocket 实例
46 | final ClientSocket clientSocket = ClientSocket.valueOf(SocketChannelConfig.valueOf(6969), new SocketPool("client", null), coderParserManager, new EmptyHandle());
47 |
48 | //模拟连接之后发送消息
49 | Timer timer = new Timer();
50 | timer.schedule(new TimerTask() {
51 |
52 | @Override
53 | public void run() {
54 | clientSocket.send("连接服务器成功");
55 | System.out.println("send ");
56 | this.cancel();
57 | }
58 | }, 1000);
59 |
60 | //启动服务
61 | clientSocket.start();
62 | //阻塞当前线程
63 | clientSocket.sync();
64 | //关闭处理
65 | clientSocket.stop();
66 | ```
67 |
68 | 服务器方式连接
69 | ```
70 | //创建session管理工厂
71 | ISessionFactory sessionFactory = new SessionFactory();
72 | //创建编/解码管理
73 | ICoderParserManager coderParserManager = new CoderParserManager();
74 | //注册包编/解码,处理业务
75 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
76 | //创建ClientSocket 实例
77 | final ServerSocket serverSocket = ServerSocket.valueOf(SocketChannelConfig.valueOf(8888), 10, 20, coderParserManager, sessionFactory);
78 |
79 | //模拟连接之后发送消息
80 | Timer timer = new Timer();
81 | timer.schedule(new TimerTask() {
82 |
83 | @Override
84 | public void run() {
85 | System.out.println("registerClientSocket");
86 | //主动连接服务器
87 | ClientSocket clientSocket = serverSocket.registerClient(SocketChannelConfig.valueOf(6969));
88 | clientSocket.send("连接服务器成功");
89 | this.cancel();
90 | }
91 | }, 1000);
92 |
93 | //启动服务
94 | serverSocket.start();
95 | //阻塞当前线程
96 | serverSocket.sync();
97 | //关闭处理
98 | serverSocket.stop();
99 | ```
100 |
101 |
102 |
103 | 源码实现过程
104 | ========
105 | 链式编/解码
106 |
107 | * 由 多个 ICoder 输入/输出转换处理
108 | * CoderParser 类组装多个 ICoder
109 | * 编/码处理器 注意优先级
110 | * nio read -> packageCoder -> link coders -> handle
111 | * handle write -> link coders -> packageCoder -> nio write
112 | * 由 ICoderParserManager 管理调用处理
113 |
114 | ```
115 | public interface ICoderParserManager {
116 |
117 | /**
118 | * 解码处理
119 | *
120 | * @return CoderResult
121 | * */
122 | CoderResult decode(ByteBuffer buffer, ICoderCtx ctx);
123 |
124 | /**
125 | * 编码处理
126 | * */
127 | ByteBuffer encode(Object message, ICoderCtx ctx);
128 |
129 | void error(ByteBuffer buffer, ICoderCtx ctx);
130 |
131 | /** 注册 编/码处理器 */
132 | void register(CoderParser coderParser);
133 | }
134 | ```
135 |
136 | 其中核心
137 | decode
138 | encode
139 | ```
140 | @Override
141 | public CoderResult decode(ByteBuffer buffer, ICoderCtx ctx) {
142 | final SocketChannelCtx socketChannelCtx = (SocketChannelCtx) ctx;
143 | final ClientSocket clientSocket = socketChannelCtx.getClientSocket();
144 |
145 | for (CoderParser coderParser : coderParsers.values()) {
146 | final IPackageCoder packageCoder = coderParser.getPackageCoder();
147 | final ICoder, ?>[] linkCoders = coderParser.getCoders();
148 | final IHandle handle = coderParser.getHandle();
149 | Object value = null;
150 | synchronized (buffer) {
151 | // 已解析完
152 | if (socketChannelCtx.getCurrPackageIndex() >= buffer.limit()) {
153 | return CoderResult.valueOf(ResultValue.UNFINISHED);
154 | }
155 | // 包协议处理
156 | if (!packageCoder.verify(buffer, ctx)) {
157 | continue;
158 | }
159 | // 包解析
160 | value = packageCoder.decode(buffer, ctx);
161 | if (value == null) {
162 | // 包未读完整
163 | return CoderResult.valueOf(ResultValue.UNFINISHED);
164 | }
165 | }
166 | // 链式处理
167 | if (linkCoders != null) {
168 | for (ICoder coder : linkCoders) {
169 | value = coder.decode(value, ctx);
170 | if (value == null) {
171 | throw new CoderException("解码出错 : " + coder.getClass());
172 | }
173 | }
174 | }
175 | // 业务解码处理
176 | value = handle.decode(value, ctx);
177 | clientSocket.readBefore(socketChannelCtx, value);
178 | handle.handle(value, ctx);
179 | clientSocket.readAfter(socketChannelCtx, value);
180 |
181 | return CoderResult.valueOf(ResultValue.SUCCEED);
182 | }
183 | return CoderResult.valueOf(ResultValue.NOT_FIND_CODER);
184 | }
185 |
186 | @Override
187 | public ByteBuffer encode(Object message, ICoderCtx ctx) {
188 |
189 | for (CoderParser coderParser : coderParsers.values()) {
190 | final IPackageCoder packageCoder = coderParser.getPackageCoder();
191 | final ICoder, ?>[] linkCoders = coderParser.getCoders();
192 | final IHandle handle = coderParser.getHandle();
193 | // 业务检查
194 | if (!handle.verify(message, ctx)) {
195 | continue;
196 | }
197 | // 业务编码处理
198 | Object value = handle.encode(message, ctx);
199 | // 链式处理
200 | if (linkCoders != null) {
201 | for (int i = linkCoders.length - 1; i >= 0; i--) {
202 | ICoder coder = linkCoders[i];
203 | value = coder.encode(value, ctx);
204 | if (value == null) {
205 | throw new CoderException("编码出错 : " + coder.getClass());
206 | }
207 | }
208 | }
209 | // 打包消息处理
210 | value = packageCoder.encode(value, ctx);
211 | if (value != null) {
212 | return (ByteBuffer) value;
213 | }
214 | throw new CoderException("编码出错 :" + packageCoder.getClass());
215 | }
216 |
217 | throw new CoderException("未找到编/解码处理器 ");
218 | }
219 |
220 | ```
221 |
222 | * 半包/帖包处理 : AbstractISocketChannel doRead方法摘要,根据解码返回的状态做处理。
223 | * 半包:当不是完成状态时,继续解码,从最后一次包索引开始处理
224 | * 帖包:当完成包解码移动包索引,等侍下轮解码处理
225 | ```
226 | boolean run = true;
227 | // 粘包处理
228 | while (run) {
229 | ByteBuffer cpbuffer = socketChannelCtx.coderBegin();
230 | cpbuffer.mark();
231 | CoderResult coderResult = coderParserManager.decode(cpbuffer, socketChannelCtx);
232 | switch (coderResult.getValue()) {
233 | case SUCCEED:
234 | break;
235 | case NOT_FIND_CODER:
236 | final int readySize = socketChannelCtx.getWriteIndex() - socketChannelCtx.getCurrPackageIndex();
237 | final int headLimit = 255;
238 | if (readySize >= headLimit) {
239 | throw new CoderException("未找到编/解码处理器 ");
240 | }
241 | run = false;
242 | break;
243 | case UNFINISHED:
244 | case UNKNOWN:
245 | case ERROR:
246 | default:
247 | run = false;
248 | // TODO throw
249 | break;
250 | }
251 | }
252 | ```
253 |
254 | 未完侍加
--------------------------------------------------------------------------------
/common/doc/p2p开发项目.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solq360/common/20bc6709a4012e1f7e78c8b74c5a1803ae60ca3b/common/doc/p2p开发项目.xls
--------------------------------------------------------------------------------
/common/doc/聊天开发项目.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solq360/common/20bc6709a4012e1f7e78c8b74c5a1803ae60ca3b/common/doc/聊天开发项目.xls
--------------------------------------------------------------------------------
/common/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | org.con.chat
6 | common
7 | 1.0
8 | jar
9 | common
10 | http://maven.apache.org
11 |
12 |
13 | UTF-8
14 |
15 |
16 |
17 |
18 | junit
19 | junit
20 | 4.10
21 | test
22 |
23 |
24 |
25 |
26 |
27 |
28 | org.apache.maven.plugins
29 | maven-compiler-plugin
30 |
31 | 1.7
32 | 1.7
33 | utf-8
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/config/SocketChannelConfig.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.config;
2 |
3 | import java.net.InetSocketAddress;
4 | import java.net.SocketAddress;
5 |
6 | import org.son.chat.common.net.util.IpUtil;
7 |
8 | /**
9 | * @author solq
10 | */
11 | public class SocketChannelConfig {
12 | private InetSocketAddress address;
13 |
14 | public static SocketChannelConfig valueOf(int remotePort) {
15 | SocketChannelConfig result = new SocketChannelConfig();
16 | result.address = new InetSocketAddress(remotePort);
17 | return result;
18 | }
19 |
20 | public static SocketChannelConfig valueOf(String remoteHost, int remotePort) {
21 | SocketChannelConfig result = new SocketChannelConfig();
22 | result.address = new InetSocketAddress(remoteHost, remotePort);
23 | return result;
24 | }
25 |
26 | public static SocketChannelConfig valueOf(SocketAddress remoteAddress) {
27 | SocketChannelConfig result = new SocketChannelConfig();
28 | result.address = (InetSocketAddress) remoteAddress;
29 | return result;
30 | }
31 |
32 | public String toIp() {
33 | return IpUtil.getIp(address);
34 | }
35 |
36 | // getter
37 |
38 | public InetSocketAddress getAddress() {
39 | return address;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/ICoder.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder;
2 |
3 | /**
4 | * 编/解码处理器
5 | *
6 | * @author solq
7 | */
8 | public interface ICoder {
9 |
10 | /** 编码 */
11 | public OUT encode(INPUT value, ICoderCtx ctx);
12 |
13 | /** 解码 */
14 | public INPUT decode(OUT value, ICoderCtx ctx);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/ICoderCtx.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder;
2 |
3 | /**
4 | * @author solq
5 | */
6 | public interface ICoderCtx {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/ICoderParserManager.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.son.chat.common.net.core.coder.impl.CoderParser;
6 | import org.son.chat.common.net.core.coder.impl.CoderResult;
7 |
8 | /**
9 | * 编/码处理器管理
10 | *
11 | * @author solq
12 | */
13 | public interface ICoderParserManager {
14 |
15 | /**
16 | * 解码处理
17 | *
18 | * @return CoderResult
19 | * */
20 | CoderResult decode(ByteBuffer buffer, ICoderCtx ctx);
21 |
22 | /**
23 | * 编码处理
24 | * */
25 | ByteBuffer encode(Object message, ICoderCtx ctx);
26 |
27 | void error(ByteBuffer buffer, ICoderCtx ctx);
28 |
29 | /** 注册 编/码处理器 */
30 | void register(CoderParser coderParser);
31 | }
32 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/IHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder;
2 |
3 | /**
4 | * @author solq
5 | */
6 | public interface IHandle extends ICoder {
7 | /** 回写验证 */
8 | public boolean verify(Object value, ICoderCtx ctx);
9 |
10 | /** 业务处理 */
11 | public void handle(INPUT value, ICoderCtx ctx);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/IPackageCoder.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder;
2 |
3 | /**
4 | * @author solq
5 | */
6 | public interface IPackageCoder extends ICoder {
7 | /** 包验证 */
8 | public boolean verify(OUT value, ICoderCtx ctx);
9 | }
10 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/impl/CoderParser.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder.impl;
2 |
3 | import org.son.chat.common.net.core.coder.ICoder;
4 | import org.son.chat.common.net.core.coder.IHandle;
5 | import org.son.chat.common.net.core.coder.IPackageCoder;
6 |
7 | /**
8 | * 编/码处理器 注意优先级
9 | * nio read -> packageCoder -> link coders -> handle
10 | * handle write -> link coders -> packageCoder -> nio write
11 | *
12 | * @author solq
13 | */
14 | public class CoderParser {
15 |
16 | /** 业务处理分发 **/
17 | private IHandle, ?> handle;
18 | /** 网络包编/解码 **/
19 | private IPackageCoder, ?> packageCoder;
20 | /** 链式编/解码 **/
21 | private ICoder, ?>[] coders;
22 | /** 名称标识 **/
23 | private String name;
24 |
25 | public static CoderParser valueOf(String name, IPackageCoder, ?> packageCoder, IHandle, ?> handle, ICoder, ?>... coders) {
26 | CoderParser result = new CoderParser(name, packageCoder, handle, coders);
27 | return result;
28 | }
29 |
30 | private CoderParser(String name, IPackageCoder, ?> packageCoder, IHandle, ?> handle, ICoder, ?>... coders) {
31 | this.packageCoder = packageCoder;
32 | this.coders = coders;
33 | this.handle = handle;
34 | this.name = name;
35 | }
36 |
37 | // getter
38 |
39 | public ICoder, ?>[] getCoders() {
40 | return coders;
41 | }
42 |
43 | public String getName() {
44 | return name;
45 | }
46 |
47 | public IHandle, ?> getHandle() {
48 | return handle;
49 | }
50 |
51 | public IPackageCoder, ?> getPackageCoder() {
52 | return packageCoder;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/impl/CoderParserManager.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder.impl;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.util.LinkedHashMap;
5 |
6 | import org.son.chat.common.net.core.coder.ICoder;
7 | import org.son.chat.common.net.core.coder.ICoderCtx;
8 | import org.son.chat.common.net.core.coder.ICoderParserManager;
9 | import org.son.chat.common.net.core.coder.IHandle;
10 | import org.son.chat.common.net.core.coder.IPackageCoder;
11 | import org.son.chat.common.net.core.coder.impl.CoderResult.ResultValue;
12 | import org.son.chat.common.net.core.socket.impl.ClientSocket;
13 | import org.son.chat.common.net.core.socket.impl.SocketChannelCtx;
14 | import org.son.chat.common.net.exception.CoderException;
15 |
16 | /**
17 | * @author solq
18 | */
19 | @SuppressWarnings({ "unchecked", "rawtypes" })
20 | public class CoderParserManager implements ICoderParserManager {
21 |
22 | private LinkedHashMap coderParsers = new LinkedHashMap<>();
23 |
24 | @Override
25 | public CoderResult decode(ByteBuffer buffer, ICoderCtx ctx) {
26 | final SocketChannelCtx socketChannelCtx = (SocketChannelCtx) ctx;
27 | final ClientSocket clientSocket = socketChannelCtx.getClientSocket();
28 |
29 | for (CoderParser coderParser : coderParsers.values()) {
30 | final IPackageCoder packageCoder = coderParser.getPackageCoder();
31 | final ICoder, ?>[] linkCoders = coderParser.getCoders();
32 | final IHandle handle = coderParser.getHandle();
33 | Object value = null;
34 | synchronized (buffer) {
35 | // 已解析完
36 | if (socketChannelCtx.getCurrPackageIndex() >= buffer.limit()) {
37 | return CoderResult.valueOf(ResultValue.UNFINISHED);
38 | }
39 | // 包协议处理
40 | if (!packageCoder.verify(buffer, ctx)) {
41 | continue;
42 | }
43 | // 包解析
44 | value = packageCoder.decode(buffer, ctx);
45 | if (value == null) {
46 | // 包未读完整
47 | return CoderResult.valueOf(ResultValue.UNFINISHED);
48 | }
49 | }
50 | // 链式处理
51 | if (linkCoders != null) {
52 | for (ICoder coder : linkCoders) {
53 | value = coder.decode(value, ctx);
54 | if (value == null) {
55 | throw new CoderException("解码出错 : " + coder.getClass());
56 | }
57 | }
58 | }
59 | // 业务解码处理
60 | value = handle.decode(value, ctx);
61 | clientSocket.readBefore(socketChannelCtx, value);
62 | handle.handle(value, ctx);
63 | clientSocket.readAfter(socketChannelCtx, value);
64 |
65 | return CoderResult.valueOf(ResultValue.SUCCEED);
66 | }
67 | return CoderResult.valueOf(ResultValue.NOT_FIND_CODER);
68 | }
69 |
70 | @Override
71 | public ByteBuffer encode(Object message, ICoderCtx ctx) {
72 |
73 | for (CoderParser coderParser : coderParsers.values()) {
74 | final IPackageCoder packageCoder = coderParser.getPackageCoder();
75 | final ICoder, ?>[] linkCoders = coderParser.getCoders();
76 | final IHandle handle = coderParser.getHandle();
77 | // 业务检查
78 | if (!handle.verify(message, ctx)) {
79 | continue;
80 | }
81 | // 业务编码处理
82 | Object value = handle.encode(message, ctx);
83 | // 链式处理
84 | if (linkCoders != null) {
85 | for (int i = linkCoders.length - 1; i >= 0; i--) {
86 | ICoder coder = linkCoders[i];
87 | value = coder.encode(value, ctx);
88 | if (value == null) {
89 | throw new CoderException("编码出错 : " + coder.getClass());
90 | }
91 | }
92 | }
93 | // 打包消息处理
94 | value = packageCoder.encode(value, ctx);
95 | if (value != null) {
96 | return (ByteBuffer) value;
97 | }
98 | throw new CoderException("编码出错 :" + packageCoder.getClass());
99 | }
100 |
101 | throw new CoderException("未找到编/解码处理器 ");
102 | }
103 |
104 | @Override
105 | public void error(ByteBuffer buffer, ICoderCtx ctx) {
106 |
107 | }
108 |
109 | @Override
110 | public synchronized void register(CoderParser coderParser) {
111 | if (coderParsers.containsKey(coderParser.getName())) {
112 | throw new CoderException("已注册编/解码处理器 : " + coderParser.getName());
113 | }
114 | coderParsers.put(coderParser.getName(), coderParser);
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/coder/impl/CoderResult.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.coder.impl;
2 |
3 | /**
4 | * @author solq
5 | */
6 | public class CoderResult {
7 |
8 | public static enum ResultValue {
9 | /** 成功 **/
10 | SUCCEED,
11 | /** 未完成 半包/帖包状态 **/
12 | UNFINISHED,
13 | /** 非法数据 **/
14 | ERROR,
15 | /** 未知错误 **/
16 | UNKNOWN,
17 | /** 未找到编/解码 **/
18 | NOT_FIND_CODER;
19 | }
20 |
21 | /** 处理后返回内容 **/
22 | private Object content;
23 |
24 | /** 处理结果 **/
25 | private ResultValue value;
26 |
27 | // getter
28 |
29 | public Object getContent() {
30 | return content;
31 | }
32 |
33 | public ResultValue getValue() {
34 | return value;
35 | }
36 |
37 | public static CoderResult valueOf(ResultValue resule) {
38 | CoderResult result = new CoderResult();
39 | result.value = resule;
40 | return result;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/AbstractSocketHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | import org.son.chat.common.net.core.coder.ICoderCtx;
4 | import org.son.chat.common.net.core.session.ISession;
5 | import org.son.chat.common.net.core.socket.impl.ClientSocket;
6 | import org.son.chat.common.net.core.socket.impl.SocketChannelCtx;
7 |
8 | /**
9 | * @author solq
10 | * */
11 | public abstract class AbstractSocketHandle implements ISocketHandle {
12 |
13 | protected static ClientSocket getClientSocket(ICoderCtx ctx){
14 | return ((SocketChannelCtx) ctx).getClientSocket();
15 | }
16 |
17 | protected static ISession getSession(ICoderCtx ctx){
18 | return getClientSocket(ctx).getSession();
19 | }
20 |
21 | @Override
22 | public void openBefore(ICoderCtx ctx) {
23 |
24 | }
25 |
26 | @Override
27 | public void openAfter(ICoderCtx ctx) {
28 |
29 | }
30 |
31 | @Override
32 | public void closeBefore(ICoderCtx ctx) {
33 |
34 | }
35 |
36 | @Override
37 | public void closeAfter(ICoderCtx ctx) {
38 |
39 | }
40 |
41 | @Override
42 | public void readBefore(ICoderCtx ctx, Object request) {
43 |
44 | }
45 |
46 | @Override
47 | public void readAfter(ICoderCtx ctx, Object request) {
48 |
49 | }
50 |
51 | @Override
52 | public void writeBefore(ICoderCtx ctx, Object response) {
53 |
54 | }
55 |
56 | @Override
57 | public void writeAfter(ICoderCtx ctx, Object response) {
58 |
59 | }
60 |
61 | @Override
62 | public void openError(ICoderCtx ctx) {
63 |
64 | }
65 |
66 | @Override
67 | public void writeError(ICoderCtx ctx, Object response) {
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/ClientManagerHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | import org.son.chat.common.net.core.coder.ICoderCtx;
4 | import org.son.chat.common.net.core.socket.impl.ClientPipeChannel;
5 |
6 | /**
7 | * @author solq
8 | * */
9 | public class ClientManagerHandle extends AbstractSocketHandle {
10 | private ClientPipeChannel channelClients;
11 |
12 | public ClientManagerHandle(ClientPipeChannel channelClients) {
13 | this.channelClients = channelClients;
14 | }
15 |
16 | @Override
17 | public void openAfter(ICoderCtx ctx) {
18 | this.channelClients.join(ClientPipeChannel.DEFAULT_CLIENT_CHANNEL, getClientSocket(ctx));
19 | }
20 |
21 | @Override
22 | public void closeAfter(ICoderCtx ctx) {
23 | this.channelClients.eixt(getClientSocket(ctx));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/EmptyHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | /**
4 | * 无实现处理
5 | *
6 | * @author solq
7 | * */
8 | public class EmptyHandle extends AbstractSocketHandle {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/HeartHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | import java.util.Date;
4 | import java.util.concurrent.Future;
5 | import java.util.concurrent.ScheduledThreadPoolExecutor;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | import org.son.chat.common.net.core.coder.ICoderCtx;
9 | import org.son.chat.common.net.core.session.ISession;
10 | import org.son.chat.common.net.core.session.Key;
11 | import org.son.chat.common.net.core.session.SessionKey;
12 | import org.son.chat.common.net.core.socket.impl.ClientSocket;
13 | import org.son.chat.common.net.util.NamedThreadFactory;
14 |
15 | /**
16 | * 心跳管理
17 | *
18 | * @author solq
19 | * */
20 | public class HeartHandle extends AbstractSocketHandle {
21 |
22 | private final static ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("Heart"));
23 |
24 | private long delayTime;
25 |
26 | public HeartHandle(long delayTime) {
27 | this.delayTime = delayTime;
28 | }
29 |
30 | @Override
31 | public void openAfter(ICoderCtx ctx) {
32 | record(ctx, SessionKey.KEY_CONNECT_TIME);
33 | }
34 |
35 | @Override
36 | public void readAfter(ICoderCtx ctx, Object request) {
37 | record(ctx, SessionKey.KEY_READ_TIME);
38 | }
39 |
40 | @Override
41 | public void writeAfter(ICoderCtx ctx, Object response) {
42 | record(ctx, SessionKey.KEY_SEND_TIME);
43 | }
44 |
45 | private void record(ICoderCtx ctx, Key key) {
46 | final Date now = new Date();
47 | ISession session = getSession(ctx);
48 | key.setAttr(session, now);
49 | SessionKey.KEY_HEART_TIME.setAttr(session, now);
50 |
51 | Future> preTask = SessionKey.KEY_HEART_TASK.getAttr(session);
52 | if (preTask != null) {
53 | return;
54 | }
55 |
56 | synchronized (session) {
57 | preTask = SessionKey.KEY_HEART_TASK.getAttr(session);
58 | if (preTask != null) {
59 | return;
60 | }
61 | final long endTime = System.currentTimeMillis() + delayTime;
62 | final HeartTask task = new HeartTask(ctx, endTime);
63 | Future> future = scheduled.schedule(task, delayTime, TimeUnit.MILLISECONDS);
64 | SessionKey.KEY_HEART_TASK.setAttr(session, future);
65 | }
66 | }
67 |
68 | private final class HeartTask implements Runnable {
69 | private ICoderCtx ctx;
70 | private long endTime;
71 |
72 | public HeartTask(ICoderCtx ctx, long endTime) {
73 | this.ctx = ctx;
74 | this.endTime = endTime;
75 | }
76 |
77 | @Override
78 | public void run() {
79 | final ISession session = getSession(ctx);
80 | final Date time = SessionKey.KEY_HEART_TIME.getAttr(session);
81 | final ClientSocket clientSocket = getClientSocket(ctx);
82 | if (clientSocket.isClose()) {
83 | return;
84 | }
85 | // close
86 | if (time == null || time.getTime() < this.endTime) {
87 | clientSocket.stop();
88 | return;
89 | }
90 | // 下次触发时间-当前时间 = 延时执行偏移时间
91 | long delay = time.getTime() + getDelayTime() - System.currentTimeMillis();
92 | if (delay <= 0) {
93 | clientSocket.stop();
94 | return;
95 | }
96 | this.endTime = System.currentTimeMillis() + delay;
97 | Future> future = scheduled.schedule(new HeartTask(ctx, endTime), delay, TimeUnit.MILLISECONDS);
98 | SessionKey.KEY_HEART_TASK.setAttr(session, future);
99 | }
100 | }
101 |
102 | // getter
103 | public long getDelayTime() {
104 | return delayTime;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/ISocketHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | import org.son.chat.common.net.core.coder.ICoderCtx;
4 |
5 | /**
6 | * socket 链路逻辑处理
7 | *
8 | * @author solq
9 | */
10 | public interface ISocketHandle {
11 | /**
12 | * 建立连接之前
13 | * */
14 | void openBefore(ICoderCtx ctx);
15 |
16 | /**
17 | * 成功建立连接之后
18 | * */
19 | void openAfter(ICoderCtx ctx);
20 |
21 | /**
22 | * 建立连接失败
23 | * */
24 | void openError(ICoderCtx ctx);
25 |
26 | /**
27 | * 关闭连接之前
28 | * */
29 | void closeBefore(ICoderCtx ctx);
30 |
31 | /**
32 | * 关闭连接之后
33 | * */
34 | void closeAfter(ICoderCtx ctx);
35 |
36 | /**
37 | * socket read 之后,编码之前
38 | * */
39 | void readBefore(ICoderCtx ctx, Object request);
40 |
41 | /**
42 | * socket read 之后,编码之后
43 | * */
44 | void readAfter(ICoderCtx ctx, Object request);
45 |
46 | /**
47 | * socket write 之后,编码之前
48 | * */
49 | void writeBefore(ICoderCtx ctx, Object response);
50 |
51 | /**
52 | * socket write 之后,编码之后
53 | * */
54 | void writeAfter(ICoderCtx ctx, Object response);
55 |
56 | /**
57 | * socket write 失败
58 | * */
59 | void writeError(ICoderCtx ctx, Object response);
60 | }
61 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/PipeHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | import java.util.LinkedList;
4 |
5 | import org.son.chat.common.net.core.coder.ICoderCtx;
6 |
7 | /**
8 | * @author solq
9 | * */
10 | public class PipeHandle extends AbstractSocketHandle {
11 |
12 | private LinkedList pipe = new LinkedList<>();
13 |
14 | public synchronized void register(ISocketHandle... handles) {
15 | for (ISocketHandle handle : handles) {
16 | pipe.add(handle);
17 | }
18 | }
19 |
20 | @Override
21 | public void openBefore(ICoderCtx ctx) {
22 | for (ISocketHandle handle : pipe) {
23 | handle.openBefore(ctx);
24 | }
25 | }
26 |
27 | @Override
28 | public void openAfter(ICoderCtx ctx) {
29 | for (ISocketHandle handle : pipe) {
30 | handle.openAfter(ctx);
31 | }
32 | }
33 |
34 | @Override
35 | public void closeBefore(ICoderCtx ctx) {
36 | for (ISocketHandle handle : pipe) {
37 | handle.closeBefore(ctx);
38 | }
39 | }
40 |
41 | @Override
42 | public void closeAfter(ICoderCtx ctx) {
43 | for (ISocketHandle handle : pipe) {
44 | handle.closeAfter(ctx);
45 | }
46 | }
47 |
48 | @Override
49 | public void readBefore(ICoderCtx ctx, Object request) {
50 | for (ISocketHandle handle : pipe) {
51 | handle.readBefore(ctx, request);
52 | }
53 | }
54 |
55 | @Override
56 | public void readAfter(ICoderCtx ctx, Object request) {
57 | for (ISocketHandle handle : pipe) {
58 | handle.readAfter(ctx, request);
59 | }
60 | }
61 |
62 | @Override
63 | public void writeBefore(ICoderCtx ctx, Object response) {
64 | for (ISocketHandle handle : pipe) {
65 | handle.writeBefore(ctx, response);
66 | }
67 | }
68 |
69 | @Override
70 | public void writeAfter(ICoderCtx ctx, Object response) {
71 | for (ISocketHandle handle : pipe) {
72 | handle.writeAfter(ctx, response);
73 | }
74 | }
75 |
76 | @Override
77 | public void openError(ICoderCtx ctx) {
78 | for (ISocketHandle handle : pipe) {
79 | handle.openError(ctx);
80 | }
81 | }
82 |
83 | @Override
84 | public void writeError(ICoderCtx ctx, Object response) {
85 | for (ISocketHandle handle : pipe) {
86 | handle.writeError(ctx, response);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/handle/SessionHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.handle;
2 |
3 | import org.son.chat.common.net.core.coder.ICoderCtx;
4 | import org.son.chat.common.net.core.session.ISessionFactory;
5 | import org.son.chat.common.net.core.socket.impl.ClientSocket;
6 | import org.son.chat.common.net.core.socket.impl.SocketChannelCtx;
7 |
8 | /**
9 | * 会话处理
10 | *
11 | * @author solq
12 | * */
13 | public class SessionHandle extends AbstractSocketHandle {
14 |
15 | private ISessionFactory sessionFactory;
16 |
17 | public SessionHandle(ISessionFactory sessionFactory) {
18 | this.sessionFactory = sessionFactory;
19 | }
20 |
21 | @Override
22 | public void openAfter(ICoderCtx ctx) {
23 | if (!(ctx instanceof SocketChannelCtx)) {
24 | return;
25 | }
26 | ClientSocket clientSocket = getClientSocket(ctx);
27 | clientSocket.setSession(sessionFactory.createSession());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/session/ISession.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.session;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * @author solq
7 | * */
8 | public interface ISession {
9 | public String getId();
10 | public void replace(ISession session);
11 |
12 | public ISession setAttr(String key,Object value);
13 | public ISession removeAttr(String key);
14 |
15 | public T getAttr(String key);
16 | public Map getAttr();
17 | }
18 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/session/ISessionFactory.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.session;
2 |
3 | /**
4 | * 会话对象管理
5 | *
6 | * @author solq
7 | * */
8 | public interface ISessionFactory {
9 | public ISession createSession();
10 |
11 | public void destroySession(ISession session);
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/session/Key.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.session;
2 |
3 | /**
4 | * session attr 托管
5 | * @author solq
6 | * */
7 | public class Key {
8 | private String key;
9 |
10 | public Key(String key) {
11 | this.key = key;
12 | }
13 |
14 | public Key setAttr(ISession session, T value) {
15 | session.setAttr(key, value);
16 | return this;
17 | }
18 |
19 | public T getAttr(ISession session) {
20 | return session.getAttr(key);
21 | }
22 | }
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/session/Session.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.session;
2 |
3 | import java.util.Map;
4 | import java.util.Map.Entry;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | /**
8 | * 会话对象
9 | *
10 | * @author solq
11 | * */
12 | public class Session implements ISession {
13 |
14 | public static Session valueOf(String id) {
15 | Session result = new Session();
16 | result.id = id;
17 | return result;
18 | }
19 |
20 | private String id;
21 |
22 | private Map attr = new ConcurrentHashMap<>();
23 |
24 | @Override
25 | public String getId() {
26 | return id;
27 | }
28 |
29 | @Override
30 | public void replace(ISession session) {
31 | for(Entry entry : session.getAttr().entrySet()){
32 | attr.put(entry.getKey(), entry.getValue());
33 | }
34 | }
35 |
36 | @Override
37 | public ISession setAttr(String key, Object value) {
38 | attr.put(key, value);
39 | return this;
40 | }
41 |
42 | @SuppressWarnings("unchecked")
43 | @Override
44 | public T getAttr(String key) {
45 | return (T) attr.get(key);
46 | }
47 |
48 | @Override
49 | public final Map getAttr() {
50 | return attr;
51 | }
52 |
53 | @Override
54 | public ISession removeAttr(String key) {
55 | attr.remove(key);
56 | return this;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/session/SessionFactory.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.session;
2 |
3 | import java.util.concurrent.atomic.AtomicLong;
4 |
5 | /**
6 | * 会话工厂
7 | *
8 | * @author solq
9 | * */
10 | public class SessionFactory implements ISessionFactory {
11 |
12 | private final static AtomicLong NUM = new AtomicLong();
13 |
14 | @Override
15 | public ISession createSession() {
16 | Session result = Session.valueOf(buildId());
17 | return result;
18 | }
19 |
20 | @Override
21 | public void destroySession(ISession session) {
22 |
23 | }
24 |
25 | private static String buildId() {
26 | long value = NUM.getAndIncrement();
27 | if (value > 10000000L) {
28 | synchronized (NUM) {
29 | if (NUM.getAndIncrement() > 10000000L) {
30 | NUM.set(0);
31 | }
32 | }
33 | }
34 | return String.valueOf(value);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/session/SessionKey.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.session;
2 |
3 | import java.util.Date;
4 | import java.util.concurrent.Future;
5 |
6 | /***
7 | * 会话属性 key
8 | *
9 | * @author solq
10 | * */
11 | public interface SessionKey {
12 |
13 | /*** 心跳时间 **/
14 | public final static String HEART_TIME = "HEART_TIME";
15 |
16 | /*** 最后发送数据时间 **/
17 | public final static String SEND_TIME = "SEND_TIME";
18 |
19 | /*** 最后读取数据时间 **/
20 | public final static String READ_TIME = "READ_TIME";
21 |
22 | /*** 最后连接数据时间 **/
23 | public final static String CONNECT_TIME = "CONNECT_TIME";
24 |
25 | public final static Key KEY_HEART_TIME = new Key<>(HEART_TIME);
26 | public final static Key KEY_SEND_TIME = new Key<>(SEND_TIME);
27 | public final static Key KEY_READ_TIME = new Key<>(READ_TIME);
28 | public final static Key KEY_CONNECT_TIME = new Key<>(CONNECT_TIME);
29 | public final static Key> KEY_HEART_TASK = new Key<>("KEY_HEART_TASK");
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/IChannel.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | /**
4 | * 管道接口
5 | *
6 | * @author solq
7 | */
8 | public interface IChannel {
9 | public void setChannelName(String nameChannel);
10 |
11 | public String getChannelName();
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/IClientSocketService.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | import java.net.SocketAddress;
4 | import java.nio.ByteBuffer;
5 |
6 | import org.son.chat.common.net.core.handle.ISocketHandle;
7 | import org.son.chat.common.net.core.session.ISession;
8 |
9 | /**
10 | * 客户端socket服务 抽象
11 | *
12 | * @author solq
13 | */
14 | public interface IClientSocketService extends ISocketHandle {
15 |
16 | public boolean isClose();
17 |
18 | public boolean isConected();
19 |
20 | public SocketAddress getLocalAddress();
21 | public SocketAddress getRemoteAddress();
22 |
23 | public void buildAddress();
24 |
25 | public void setSession(ISession session);
26 | public ISession getSession();
27 |
28 | // //////////////////消息处理行为//////////////////////////
29 | public void send(Object message);
30 |
31 | public void send(Object message, ByteBuffer byteBuffer);
32 | }
33 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/IPipeChannel.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | /**
4 | * @author solq
5 | * */
6 | public interface IPipeChannel {
7 |
8 | /***
9 | * 加入管道
10 | *
11 | * @param channelName
12 | * 管道名称
13 | * @param e
14 | * 元素
15 | * */
16 | void join(String channelName, E e);
17 |
18 | /**
19 | * 退出管道
20 | *
21 | * @param e
22 | * */
23 | void eixt(E e);
24 |
25 | /***
26 | * 替换管道
27 | *
28 | * @param newChannelName
29 | * 管道名称
30 | * @param e
31 | * 元素
32 | * */
33 | void replace(String newChannelName,E e);
34 | }
35 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/IServerSocketService.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.son.chat.common.net.config.SocketChannelConfig;
6 | import org.son.chat.common.net.core.handle.ISocketHandle;
7 | import org.son.chat.common.net.core.session.ISession;
8 | import org.son.chat.common.net.core.socket.impl.ClientSocket;
9 |
10 | /**
11 | * 服务端 socket 服务接口
12 | *
13 | * @author solq
14 | */
15 | public interface IServerSocketService {
16 |
17 | // /////////////// 客户端发送消息处理////////////////////////
18 | public void sendAll(Object message);
19 |
20 | public void send(String channelName, Object message);
21 |
22 | public void send(ClientSocket clientSocket, Object message);
23 |
24 | public void send(ClientSocket clientSocket, Object message, ByteBuffer byteBuffer);
25 |
26 | // ///////////////客户端注册处理////////////////////////
27 |
28 | public ClientSocket registerClient(SocketChannelConfig config);
29 |
30 | public ISession createSession();
31 |
32 | public ISocketPool getNextPool();
33 |
34 | public ISocketPool[] getGroupPool();
35 |
36 | // /////////////// 监控处理////////////////////////
37 |
38 | public void registerHandle(ISocketHandle... handleArray);
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/ISocketChannel.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | import java.nio.channels.SelectionKey;
4 |
5 | import org.son.chat.common.net.config.SocketChannelConfig;
6 | import org.son.chat.common.net.core.coder.ICoderParserManager;
7 |
8 | /**
9 | * 顶级接口抽象原则,必须的处理行为。细分的行为/属性不做抽象声明
10 | * socket 管理接口抽象 针对两socket 绑定处理
11 | *
12 | * @author solq
13 | */
14 | public interface ISocketChannel {
15 |
16 | // ////////////////配置属性////////////////////////
17 | public SocketChannelConfig getSocketChannelConfig();
18 | public void setCoderParserManager(ICoderParserManager coderParserManager);
19 | public ISocketPool getPool();
20 |
21 | public void doAccept(SelectionKey key);
22 | public void doConnect(SelectionKey key);
23 | public void doWrite(SelectionKey key);
24 | public void doRead(SelectionKey key);
25 | public void doClose(SelectionKey key);
26 | public boolean isClose();
27 | }
28 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/ISocketPool.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | import java.nio.channels.Selector;
4 |
5 | /**
6 | * socket 逻辑处理池子
7 | *
8 | * @author solq
9 | */
10 | public interface ISocketPool {
11 |
12 | public void init();
13 | /** 执行任务 **/
14 | public void execute(Runnable task);
15 |
16 | /** 关闭处理 **/
17 | public void shutdown();
18 |
19 | /** 是否运行 **/
20 | public boolean isRun();
21 |
22 | /** 任务数 **/
23 | public int taskCount();
24 |
25 | /** select **/
26 | public Selector getSelector();
27 |
28 | /** 触发select **/
29 | public void select();
30 | }
31 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/ISocketService.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket;
2 |
3 | /**
4 | * socket 服务接口
5 | *
6 | * @author solq
7 | */
8 | public interface ISocketService {
9 | public void init();
10 |
11 | public void start();
12 |
13 | public void stop();
14 |
15 | public void sync();
16 | }
17 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/impl/AbstractISocketChannel.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket.impl;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.channels.SelectionKey;
5 | import java.nio.channels.Selector;
6 | import java.nio.channels.SocketChannel;
7 |
8 | import org.son.chat.common.net.config.SocketChannelConfig;
9 | import org.son.chat.common.net.core.coder.ICoderParserManager;
10 | import org.son.chat.common.net.core.coder.impl.CoderResult;
11 | import org.son.chat.common.net.core.handle.ISocketHandle;
12 | import org.son.chat.common.net.core.socket.ISocketChannel;
13 | import org.son.chat.common.net.core.socket.ISocketPool;
14 | import org.son.chat.common.net.core.socket.ISocketService;
15 | import org.son.chat.common.net.exception.CoderException;
16 | import org.son.chat.common.net.exception.NetException;
17 | import org.son.chat.common.net.util.NioUtil;
18 |
19 | /**
20 | * socketchannel 模板
21 | *
22 | * @author solq
23 | */
24 | public abstract class AbstractISocketChannel implements ISocketChannel, ISocketService {
25 |
26 | protected boolean close = true;
27 | protected boolean init = false;
28 |
29 | protected ICoderParserManager coderParserManager;
30 | protected SocketChannelConfig socketChannelConfig;
31 | protected ISocketHandle handle;
32 | protected ISocketPool pool;
33 |
34 | /**
35 | * 读写分离 参考 : http://developer.51cto.com/art/201112/306532.htm
36 | * 也可以参考netty
37 | */
38 | @Override
39 | public void start() {
40 | if (!init) {
41 | init();
42 | }
43 | // TODO
44 | // while (!close) {
45 | // Selector selector = getSelector();
46 | // try {
47 | // // TODO 占用CPU 处理
48 | // // 参考 : http://xw-z1985.iteye.com/blog/1928244
49 | // // http://www.tuicool.com/articles/36zimq
50 | // // http://xw-z1985.iteye.com/blog/1748660
51 | // int n = selector .select(10);
52 | // if (n < 0) {
53 | // continue;
54 | // }
55 | // } catch (IOException e) {
56 | // e.printStackTrace();
57 | // break;
58 | // }
59 | // for (Iterator i = selector.selectedKeys().iterator();
60 | // i.hasNext();) {
61 | // // 得到下一个Key
62 | // SelectionKey key = i.next();
63 | // try {
64 | // handle(key);
65 | // } catch (Exception e) {
66 | // e.printStackTrace();
67 | // }
68 | // i.remove();
69 | // }
70 | // }
71 | // stop();
72 | }
73 |
74 | @Override
75 | public void stop() {
76 | init = false;
77 | close = true;
78 | handle = null;
79 | socketChannelConfig = null;
80 | coderParserManager = null;
81 | // selector = null;
82 | }
83 |
84 | @Override
85 | public void doConnect(SelectionKey key) {
86 | System.out.println(" doConnect ");
87 | NioUtil.clearOps(key, SelectionKey.OP_CONNECT);
88 | NioUtil.setOps(key, SelectionKey.OP_READ);
89 | }
90 |
91 | @Override
92 | public void doClose(SelectionKey key) {
93 | System.out.println(" doClose ");
94 | this.stop();
95 | }
96 |
97 | @Override
98 | public void doAccept(SelectionKey key) {
99 | System.out.println(" doAccept ");
100 | }
101 |
102 | @Override
103 | public void doWrite(SelectionKey key) {
104 | System.out.println(" doWrite ");
105 | // 服务端读到东西后,注册写事件。等写完东西后取消写事件的注册。
106 | NioUtil.clearOps(key, SelectionKey.OP_WRITE);
107 | }
108 |
109 | @Override
110 | public void doRead(SelectionKey key) {
111 | System.out.println(" doRead ");
112 | final SocketChannel clientChannel = (SocketChannel) key.channel();
113 | final ClientSocket clientSocket = (ClientSocket) key.attachment();
114 | final SocketChannelCtx socketChannelCtx = clientSocket.getCtx();
115 |
116 | ByteBuffer buffer = null;
117 | long bytesRead = -1;
118 | try {
119 | buffer = socketChannelCtx.readBegin();
120 | bytesRead = clientChannel.read(buffer);
121 | socketChannelCtx.readEnd(bytesRead);
122 | } catch (Exception e) {
123 | // 链路关闭,不清理读操作会造成死循环
124 | NioUtil.clearOps(key, SelectionKey.OP_READ);
125 | coderParserManager.error(buffer, socketChannelCtx);
126 | key.cancel();
127 | clientSocket.stop();
128 | throw new NetException("读取Socket数据异常 : ", e);
129 | }
130 |
131 | // 编码处理
132 | if (bytesRead == -1) {
133 | // 链路关闭,不清理读操作会造成死循环
134 | NioUtil.clearOps(key, SelectionKey.OP_READ);
135 | coderParserManager.error(buffer, socketChannelCtx);
136 | key.cancel();
137 | clientSocket.stop();
138 | } else {
139 | boolean run = true;
140 | // 粘包处理
141 | while (run) {
142 | ByteBuffer cpbuffer = socketChannelCtx.coderBegin();
143 | cpbuffer.mark();
144 | CoderResult coderResult = coderParserManager.decode(cpbuffer, socketChannelCtx);
145 | switch (coderResult.getValue()) {
146 | case SUCCEED:
147 | break;
148 | case NOT_FIND_CODER:
149 | final int readySize = socketChannelCtx.getWriteIndex() - socketChannelCtx.getCurrPackageIndex();
150 | final int headLimit = 255;
151 | if (readySize >= headLimit) {
152 | throw new CoderException("未找到编/解码处理器 ");
153 | }
154 | run = false;
155 | break;
156 | case UNFINISHED:
157 | case UNKNOWN:
158 | case ERROR:
159 | default:
160 | run = false;
161 | // TODO throw
162 | break;
163 | }
164 | }
165 | }
166 | }
167 |
168 | // getter
169 | @Override
170 | public SocketChannelConfig getSocketChannelConfig() {
171 | return socketChannelConfig;
172 | }
173 |
174 | @Override
175 | public void setCoderParserManager(ICoderParserManager coderParserManager) {
176 | this.coderParserManager = coderParserManager;
177 | }
178 |
179 | @Override
180 | public boolean isClose() {
181 | return close;
182 | }
183 |
184 | public boolean isInit() {
185 | return init;
186 | }
187 |
188 | public ISocketHandle getHandle() {
189 | return handle;
190 | }
191 |
192 | @Override
193 | public ISocketPool getPool() {
194 | return this.pool;
195 | }
196 |
197 | public void register(ISocketPool pool) {
198 | this.pool = pool;
199 | }
200 |
201 | public Selector getSelector() {
202 | return this.pool.getSelector();
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/impl/ClientPipeChannel.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket.impl;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.concurrent.ConcurrentHashMap;
7 |
8 | import org.son.chat.common.net.core.socket.IPipeChannel;
9 | import org.son.chat.common.net.exception.NetException;
10 | import org.son.chat.common.net.util.IpUtil;
11 |
12 | /**
13 | * 客房端管道
14 | * */
15 | public class ClientPipeChannel implements IPipeChannel {
16 |
17 | public final static String DEFAULT_CLIENT_CHANNEL = "DEFAULT_CLIENT_CHANNEL";
18 | /** 已连接的客户端 */
19 | private ConcurrentHashMap ipMapClients = new ConcurrentHashMap<>();
20 | private ConcurrentHashMap> channelMapClients = new ConcurrentHashMap<>();
21 |
22 | @Override
23 | public void join(String channelName, ClientSocket e) {
24 | e.buildAddress();
25 | final String ip = IpUtil.getAddress(e.getRemoteAddress());
26 | if (ip == null) {
27 | throw new NetException("ClientSocket 远程IP 未找到");
28 | }
29 |
30 | if (null != e.getChannelName()) {
31 | replace(channelName, e);
32 | return;
33 | }
34 |
35 | e.setChannelName(channelName);
36 | Map channelClients = channelMapClients.get(channelName);
37 | if (channelClients == null) {
38 | ConcurrentHashMap newChannelClients = new ConcurrentHashMap();
39 | ConcurrentHashMap now = channelMapClients.putIfAbsent(channelName, newChannelClients);
40 | channelClients = now != null ? now : newChannelClients;
41 | }
42 |
43 | ipMapClients.put(ip, e);
44 | channelClients.put(ip, e);
45 |
46 | }
47 |
48 | @Override
49 | public void eixt(ClientSocket e) {
50 | final String ip = IpUtil.getAddress(e.getRemoteAddress());
51 | if (ip == null) {
52 | return;
53 | }
54 | ipMapClients.remove(ip);
55 |
56 | final String channle = e.getChannelName();
57 | if (null == channle) {
58 | return;
59 | }
60 |
61 | ConcurrentHashMap channels = channelMapClients.get(channle);
62 | if (channels != null) {
63 | channels.remove(ip);
64 | }
65 | e.setChannelName(null);
66 | }
67 |
68 | @Override
69 | public void replace(String newChannelName, ClientSocket e) {
70 | eixt(e);
71 | join(newChannelName, e);
72 | }
73 |
74 | public List getAllClinetSockets() {
75 | List result = new LinkedList();
76 | return result;
77 | }
78 |
79 | public List getChannelClinetSockets(String channelName) {
80 | List result = new LinkedList();
81 | return result;
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/impl/ClientSocket.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket.impl;
2 |
3 | import java.io.IOException;
4 | import java.net.SocketAddress;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.SelectionKey;
7 | import java.nio.channels.SocketChannel;
8 |
9 | import org.son.chat.common.net.config.SocketChannelConfig;
10 | import org.son.chat.common.net.core.coder.ICoderCtx;
11 | import org.son.chat.common.net.core.coder.ICoderParserManager;
12 | import org.son.chat.common.net.core.handle.ISocketHandle;
13 | import org.son.chat.common.net.core.session.ISession;
14 | import org.son.chat.common.net.core.socket.IChannel;
15 | import org.son.chat.common.net.core.socket.IClientSocketService;
16 | import org.son.chat.common.net.core.socket.ISocketPool;
17 | import org.son.chat.common.net.exception.NetException;
18 | import org.son.chat.common.net.util.NioUtil;
19 |
20 | /**
21 | * @author solq
22 | */
23 | public class ClientSocket extends AbstractISocketChannel implements IClientSocketService, IChannel {
24 |
25 | public static ClientSocket valueOf(SocketChannelConfig socketChannelConfig, ISocketPool pool, ICoderParserManager coderParserManager, ISocketHandle socketHandle) {
26 | ClientSocket clientSocket = new ClientSocket();
27 | clientSocket.pool = pool;
28 | clientSocket.socketChannelConfig = socketChannelConfig;
29 | clientSocket.coderParserManager = coderParserManager;
30 | clientSocket.handle = socketHandle;
31 | clientSocket.ctx = SocketChannelCtx.valueOf(clientSocket);
32 | return clientSocket;
33 | }
34 |
35 | public static ClientSocket valueOfServer(SocketChannelConfig socketChannelConfig, SocketChannel channel, ISocketPool pool, ICoderParserManager coderParserManager, ISocketHandle socketHandle) {
36 | ClientSocket clientSocket = new ClientSocket();
37 | clientSocket.pool = pool;
38 | clientSocket.handle = socketHandle;
39 | clientSocket.channel = channel;
40 | clientSocket.coderParserManager = coderParserManager;
41 | clientSocket.socketChannelConfig = socketChannelConfig;
42 | clientSocket.connected = true;
43 | clientSocket.close = false;
44 | clientSocket.serverMode = true;
45 | clientSocket.ctx = SocketChannelCtx.valueOf(clientSocket);
46 | return clientSocket;
47 | }
48 |
49 | private SocketAddress localAddress;
50 | private SocketAddress remoteAddress;
51 | private SocketChannel channel;
52 |
53 | private SocketChannelCtx ctx;
54 | private SelectionKey selectionKey;
55 | private ISession session;
56 |
57 | private boolean connected = false;
58 | private String nameChannel;
59 | private boolean serverMode = false;
60 |
61 | @Override
62 | public void send(Object message) {
63 | ByteBuffer byteBuffer = coderParserManager.encode(message, ctx);
64 | byteBuffer.flip();
65 | send(message, byteBuffer);
66 | }
67 |
68 | /**
69 | * nio channel 发送真恶心....
70 | * 发送数据参考 http://ericbaner.iteye.com/blog/1821798
71 | */
72 | @Override
73 | public void send(final Object message, final ByteBuffer byteBuffer) {
74 | getPool().execute(new Runnable() {
75 |
76 | @Override
77 | public void run() {
78 | try {
79 | if (ClientSocket.this.close) {
80 | return;
81 | }
82 | ClientSocket.this.writeBefore(ctx, message);
83 | while (byteBuffer.hasRemaining()) {
84 | int len = ClientSocket.this.channel.write(byteBuffer);
85 |
86 | if (len < 0) {
87 | throw new NetException("发送消息出错 :" + len);
88 | }
89 |
90 | // 写半包处理
91 | if (len == 0) {
92 | System.out.println("写半包");
93 | NioUtil.setOps(selectionKey, SelectionKey.OP_WRITE);
94 | // selector.wakeup();
95 | break;
96 | }
97 | ClientSocket.this.writeAfter(ctx, message);
98 | }
99 | } catch (IOException e) {
100 | ClientSocket.this.writeError(ClientSocket.this.ctx, message);
101 | coderParserManager.error(byteBuffer, ClientSocket.this.ctx);
102 | throw new NetException("发送消息出错 :", e);
103 | }
104 | }
105 | });
106 | }
107 |
108 | @Override
109 | public void init() {
110 | try {
111 | this.init = true;
112 | this.openBefore(ctx);
113 | channel = SocketChannel.open(this.socketChannelConfig.getAddress());
114 | channel.configureBlocking(false);
115 | this.connected = channel.isConnected();
116 | if (!this.connected) {
117 | // this.channel.register(this.selector,
118 | // SelectionKey.OP_CONNECT);
119 | // TODO 定时检查连接
120 | } else {
121 | finishConnect();
122 | }
123 |
124 | } catch (IOException e) {
125 | e.printStackTrace();
126 | this.openError(ctx);
127 | stop();
128 | }
129 | }
130 |
131 | private void finishConnect() throws IOException {
132 |
133 | while (!channel.finishConnect()) {
134 | // TODO 超时处理
135 | }
136 |
137 | selectionKey = channel.register(getSelector(),0, this);
138 | NioUtil.clearOps(this.selectionKey, SelectionKey.OP_ACCEPT);
139 | NioUtil.setOps(this.selectionKey, SelectionKey.OP_READ);
140 | this.close = false;
141 | this.openAfter(this.ctx);
142 | // NioUtil.setOps(selectionKey, SelectionKey.OP_WRITE);
143 | this.pool.init();
144 | }
145 |
146 | @Override
147 | public synchronized void stop() {
148 | if (channel != null) {
149 | try {
150 | // 业务层通知
151 | this.closeBefore(ctx);
152 | if (channel.isConnected()) {
153 | channel.close();
154 | }
155 | this.closeAfter(ctx);
156 |
157 | } catch (IOException e) {
158 | e.printStackTrace();
159 | }
160 | }
161 |
162 | if (!serverMode) {
163 | try {
164 | getPool().shutdown();
165 | } catch (Exception e) {
166 | e.printStackTrace();
167 | }
168 | }
169 |
170 | ctx = null;
171 | channel = null;
172 | selectionKey = null;
173 | session = null;
174 | super.stop();
175 | }
176 |
177 | @Override
178 | public void start() {
179 | if (serverMode) {
180 | return;
181 | }
182 | super.start();
183 | }
184 |
185 | @Override
186 | public void openBefore(ICoderCtx ctx) {
187 | handle.openBefore(ctx);
188 | }
189 |
190 | @Override
191 | public void openAfter(ICoderCtx ctx) {
192 | handle.openAfter(ctx);
193 | }
194 |
195 | @Override
196 | public void closeBefore(ICoderCtx ctx) {
197 | handle.closeBefore(ctx);
198 | }
199 |
200 | @Override
201 | public void closeAfter(ICoderCtx ctx) {
202 | handle.closeAfter(ctx);
203 | }
204 |
205 | @Override
206 | public void readBefore(ICoderCtx ctx, Object request) {
207 | handle.readBefore(ctx, request);
208 | }
209 |
210 | @Override
211 | public void readAfter(ICoderCtx ctx, Object request) {
212 | handle.readAfter(ctx, request);
213 | }
214 |
215 | @Override
216 | public void writeBefore(ICoderCtx ctx, Object response) {
217 | handle.writeBefore(ctx, response);
218 | }
219 |
220 | @Override
221 | public void writeAfter(ICoderCtx ctx, Object response) {
222 | handle.writeAfter(ctx, response);
223 | }
224 |
225 | @Override
226 | public void openError(ICoderCtx ctx) {
227 | handle.openError(ctx);
228 |
229 | }
230 |
231 | @Override
232 | public void writeError(ICoderCtx ctx, Object response) {
233 | handle.writeError(ctx, response);
234 | }
235 |
236 | // getter
237 |
238 | public SelectionKey getSelectionKey() {
239 | return selectionKey;
240 | }
241 |
242 | public void setSelectionKey(SelectionKey selectionKey) {
243 | this.selectionKey = selectionKey;
244 | }
245 |
246 | public boolean isConnected() {
247 | return connected;
248 | }
249 |
250 | @Override
251 | public boolean isClose() {
252 | return this.close;
253 | }
254 |
255 | @Override
256 | public boolean isConected() {
257 | return this.connected;
258 | }
259 |
260 | public SocketChannelCtx getCtx() {
261 | return ctx;
262 | }
263 |
264 | @Override
265 | public void buildAddress() {
266 | this.localAddress = getLocalAddress();
267 | this.remoteAddress = getRemoteAddress();
268 | }
269 |
270 | @Override
271 | public SocketAddress getLocalAddress() {
272 | if (localAddress != null) {
273 | return localAddress;
274 | }
275 | try {
276 | return channel.getLocalAddress();
277 | } catch (IOException e) {
278 | return null;
279 | }
280 | }
281 |
282 | @Override
283 | public SocketAddress getRemoteAddress() {
284 | if (remoteAddress != null) {
285 | return remoteAddress;
286 | }
287 | try {
288 | return channel.getRemoteAddress();
289 | } catch (IOException e) {
290 | return null;
291 | }
292 | }
293 |
294 | @Override
295 | public void setChannelName(String nameChannel) {
296 | this.nameChannel = nameChannel;
297 | }
298 |
299 | @Override
300 | public String getChannelName() {
301 | return nameChannel;
302 | }
303 |
304 | @Override
305 | public void setSession(ISession session) {
306 | this.session = session;
307 | }
308 |
309 | @Override
310 | public ISession getSession() {
311 | return session;
312 | }
313 |
314 | public void openServerMode() {
315 | this.serverMode = true;
316 | }
317 |
318 | @Override
319 | public void sync() {
320 | while (pool.isRun()) {
321 | try {
322 | Thread.sleep(5000);
323 | } catch (InterruptedException e) {
324 | e.printStackTrace();
325 | }
326 | }
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/impl/ServerSocket.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket.impl;
2 |
3 | import java.io.IOException;
4 | import java.nio.ByteBuffer;
5 | import java.nio.channels.SelectionKey;
6 | import java.nio.channels.ServerSocketChannel;
7 | import java.nio.channels.SocketChannel;
8 | import java.util.List;
9 |
10 | import org.son.chat.common.net.config.SocketChannelConfig;
11 | import org.son.chat.common.net.core.coder.ICoderParserManager;
12 | import org.son.chat.common.net.core.handle.ClientManagerHandle;
13 | import org.son.chat.common.net.core.handle.ISocketHandle;
14 | import org.son.chat.common.net.core.handle.PipeHandle;
15 | import org.son.chat.common.net.core.session.ISession;
16 | import org.son.chat.common.net.core.session.ISessionFactory;
17 | import org.son.chat.common.net.core.socket.IServerSocketService;
18 | import org.son.chat.common.net.core.socket.ISocketPool;
19 | import org.son.chat.common.net.exception.NetException;
20 | import org.son.chat.common.net.util.NioUtil;
21 |
22 | /**
23 | * 服务端socket 是一个管理多个 客户端 socket 处理
24 | * 客户端socket 是一个对一个 socket 处理
25 | * 所以我认为 服务端socket其实是维护管理 多个 客户端 socket 这样就大量简化编写
26 | *
27 | * @author solq
28 | */
29 | public class ServerSocket extends AbstractISocketChannel implements IServerSocketService {
30 |
31 | public static ServerSocket valueOf(SocketChannelConfig socketChannelConfig, int minPoolSize, int maxPoolSize, ICoderParserManager coderParserManager, ISessionFactory sessionFactory) {
32 | ServerSocket serverSocket = new ServerSocket();
33 | serverSocket.minPoolSize = minPoolSize;
34 | serverSocket.maxPoolSize = maxPoolSize;
35 | serverSocket.socketChannelConfig = socketChannelConfig;
36 | serverSocket.coderParserManager = coderParserManager;
37 | serverSocket.sessionFactory = sessionFactory;
38 | return serverSocket;
39 | }
40 |
41 | private ServerSocketChannel socketChannel;
42 | private ISessionFactory sessionFactory;
43 | private ClientPipeChannel channelClients = new ClientPipeChannel();
44 | private Thread shutdownHook;
45 |
46 | private int count;
47 | private int minPoolSize;
48 | private int maxPoolSize;
49 | private ISocketPool[] groupPool;
50 |
51 | @Override
52 | public void init() {
53 | try {
54 | groupPool = new SocketPool[minPoolSize];
55 | for (int i = 0; i < minPoolSize; i++) {
56 | groupPool[i] = new SocketPool("server : " + i, null);
57 | }
58 | pool = new SocketPool("server accept", this);
59 | socketChannel = ServerSocketChannel.open();
60 | socketChannel.configureBlocking(false);
61 | socketChannel.bind(socketChannelConfig.getAddress());
62 | socketChannel.register(getSelector(), SelectionKey.OP_ACCEPT);
63 | handle = new PipeHandle();
64 | ((PipeHandle) handle).register(new ClientManagerHandle(channelClients));
65 | this.close = false;
66 | this.init = true;
67 | pool.init();
68 | registerShutdownHook();
69 | } catch (IOException e) {
70 | throw new NetException("初始化 NIO服务器异常 :", e);
71 | }
72 | }
73 |
74 | @Override
75 | public void doAccept(SelectionKey key) {
76 | System.out.println(" handleAccept ");
77 | ClientSocket clientSocket = null;
78 | try {
79 | SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
80 | clientChannel.configureBlocking(false);
81 | ISocketPool pool = getNextPool();
82 | clientSocket = ClientSocket.valueOfServer(SocketChannelConfig.valueOf(clientChannel.getRemoteAddress()), clientChannel,pool, coderParserManager, handle);
83 |
84 | final SocketChannelCtx ctx = clientSocket.getCtx();
85 | clientSocket.openBefore(ctx);
86 | // 必须是新注册的 SelectionKey
87 | SelectionKey sk = clientChannel.register(pool.getSelector(), 0, clientSocket);
88 | clientSocket.setSelectionKey(sk);
89 | NioUtil.setOps(sk, SelectionKey.OP_READ);
90 | clientSocket.openAfter(ctx);
91 | pool.init();
92 |
93 | } catch (IOException e) {
94 | if (clientSocket != null) {
95 | clientSocket.openError(clientSocket.getCtx());
96 | }
97 | throw new NetException("Socket连接异常 : ", e);
98 | }
99 | }
100 |
101 | @Override
102 | public synchronized void stop() {
103 | if (socketChannel != null) {
104 | try {
105 | // 业务层通知
106 | List clients = channelClients.getAllClinetSockets();
107 | for (ClientSocket client : clients) {
108 | client.stop();
109 | }
110 | socketChannel.close();
111 | } catch (IOException e) {
112 | e.printStackTrace();
113 | }
114 | }
115 | pool.shutdown();
116 | socketChannel = null;
117 | super.stop();
118 | }
119 |
120 | @Override
121 | public void sendAll(Object message) {
122 | ByteBuffer byteBuffer = coderParserManager.encode(message, null);
123 | List clients = channelClients.getAllClinetSockets();
124 | for (ClientSocket client : clients) {
125 | send(client, byteBuffer);
126 | }
127 | }
128 |
129 | @Override
130 | public void send(String channelName, Object message) {
131 | ByteBuffer byteBuffer = coderParserManager.encode(message, null);
132 | List clients = channelClients.getChannelClinetSockets(channelName);
133 | for (ClientSocket client : clients) {
134 | send(client, message, byteBuffer);
135 | }
136 | }
137 |
138 | @Override
139 | public void send(ClientSocket clientSocket, Object message) {
140 | clientSocket.send(message);
141 | }
142 |
143 | @Override
144 | public void send(ClientSocket clientSocket, Object message, ByteBuffer byteBuffer) {
145 | clientSocket.send(message, byteBuffer);
146 | }
147 |
148 | @Override
149 | public ClientSocket registerClient(SocketChannelConfig config) {
150 | System.out.println(" registerClient ");
151 | try {
152 | ClientSocket clientSocket = ClientSocket.valueOf(config, getNextPool(), this.coderParserManager, this.handle);
153 | clientSocket.openServerMode();
154 | clientSocket.init();
155 | return clientSocket;
156 | } catch (Exception e) {
157 | throw new NetException("Socket连接异常 : ", e);
158 | }
159 | }
160 |
161 | @Override
162 | public void registerHandle(ISocketHandle... handleArray) {
163 | for (ISocketHandle handle : handleArray) {
164 | ((PipeHandle) this.handle).register(handle);
165 | }
166 | }
167 |
168 | @Override
169 | public ISession createSession() {
170 | return sessionFactory.createSession();
171 | }
172 |
173 | private void registerShutdownHook() {
174 | if (this.shutdownHook == null) {
175 | this.shutdownHook = new Thread() {
176 | @Override
177 | public void run() {
178 | ServerSocket.this.stop();
179 | }
180 | };
181 | Runtime.getRuntime().addShutdownHook(this.shutdownHook);
182 | }
183 | }
184 |
185 | @Override
186 | public ISocketPool getNextPool() {
187 | ISocketPool pool = getGroupPool()[count++ % getGroupPool().length];
188 | return pool;
189 | }
190 |
191 | @Override
192 | public ISocketPool[] getGroupPool() {
193 | return groupPool;
194 | }
195 |
196 | public int getMinPoolSize() {
197 | return minPoolSize;
198 | }
199 |
200 | public int getMaxPoolSize() {
201 | return maxPoolSize;
202 | }
203 |
204 | @Override
205 | public void sync() {
206 | while (pool.isRun()) {
207 | try {
208 | Thread.sleep(5000);
209 | } catch (InterruptedException e) {
210 | e.printStackTrace();
211 | }
212 | }
213 | while (true) {
214 | boolean sleep = false;
215 | for (ISocketPool sp : groupPool) {
216 | if (sp.isRun()) {
217 | sleep = true;
218 | break;
219 | }
220 | }
221 | if(!sleep){
222 | break;
223 | }
224 | try {
225 | Thread.sleep(5000);
226 | } catch (InterruptedException e) {
227 | e.printStackTrace();
228 | }
229 | }
230 |
231 | }
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/impl/SocketChannelCtx.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket.impl;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.son.chat.common.net.core.coder.ICoderCtx;
6 |
7 | /**
8 | * 主要负责记录读取包索引,会话数据等
9 | *
10 | * @author solq
11 | */
12 | public class SocketChannelCtx implements ICoderCtx {
13 |
14 | public static SocketChannelCtx valueOf(ClientSocket clientSocket) {
15 | SocketChannelCtx result = new SocketChannelCtx();
16 | result.clientSocket = clientSocket;
17 | result.readBuffer = result.createByteBuffer(result.maxReadBufferSize);
18 | return result;
19 | }
20 |
21 | /******** jdk nio byteBuffer ************/
22 | private ByteBuffer readBuffer;
23 |
24 | private ClientSocket clientSocket;
25 | private int maxReadBufferSize = 1024 * 20;
26 | private int minReadBufferSize = 1024 * 8;
27 |
28 | private final static int MIN_MUT = 1422;
29 | private final static int DOUBLE_MUT = MIN_MUT * 2;
30 | /** socket read 索引 */
31 | private int writeIndex = 0;
32 |
33 | /** 包索引 */
34 | private int currPackageIndex = 0;
35 |
36 | public void send(Object message) {
37 | clientSocket.send(message);
38 | }
39 |
40 | public void close() {
41 | clientSocket.stop();
42 | }
43 |
44 | /**
45 | * 更改下个数据包索引
46 | */
47 | public synchronized void nextPackageIndex(long len) {
48 | if (len > 0) {
49 | currPackageIndex += len;
50 | }
51 | }
52 |
53 | /**
54 | * 准备开始读数据处理
55 | */
56 | public synchronized ByteBuffer readBegin() {
57 | readBuffer.clear();
58 | readBuffer.position(writeIndex);
59 |
60 | final int unUseSize = readBuffer.capacity() - writeIndex;
61 | boolean isExt = false;
62 | int bufferSize = maxReadBufferSize;
63 |
64 | // 剩余容量低于最少边界
65 | if (DOUBLE_MUT > unUseSize) {
66 | // 2倍方式扩容
67 | final int usePackageSize = writeIndex - this.currPackageIndex;
68 | final int doubleUsePackageSize = usePackageSize * 2;
69 | if (doubleUsePackageSize > readBuffer.capacity()) {
70 | bufferSize = readBuffer.capacity() << 1;
71 | } else {
72 | bufferSize = Math.max(doubleUsePackageSize, maxReadBufferSize);
73 | }
74 | isExt = true;
75 |
76 | } else if (unUseSize > maxReadBufferSize) { // 剩余容量高于最大边界 缩容处理
77 | final int usePackageSize = writeIndex - this.currPackageIndex;
78 | final int doubleUsePackageSize = usePackageSize * 2;
79 | if (maxReadBufferSize > doubleUsePackageSize) {
80 | bufferSize = maxReadBufferSize;
81 | isExt = true;
82 | }
83 | }
84 |
85 | if (isExt) {
86 | extendByteBuffer(bufferSize);
87 | }
88 |
89 | return readBuffer;
90 | }
91 |
92 | private void extendByteBuffer(int bufferSize) {
93 | ByteBuffer newReadBuffer = createByteBuffer(bufferSize);
94 | // 从最后包标记开始复制
95 | newReadBuffer.put(readBuffer.array(), this.currPackageIndex, this.writeIndex - this.currPackageIndex);
96 | writeIndex = 0;
97 | currPackageIndex = 0;
98 | readBuffer = newReadBuffer;
99 | }
100 |
101 | public synchronized ByteBuffer coderBegin() {
102 | readBuffer.clear().position(currPackageIndex).limit(writeIndex);
103 | return readBuffer.asReadOnlyBuffer();
104 | }
105 |
106 | // 模拟socket read
107 | public synchronized int readBuffer(ByteBuffer buffer) {
108 | buffer.flip();
109 | readBuffer.clear();
110 | readBuffer.position(writeIndex);
111 | readBuffer.put(buffer);
112 | return buffer.limit();
113 | }
114 |
115 | /**
116 | * 更改NIO 每次读索引
117 | */
118 | public synchronized void readEnd(long len) {
119 | if (len > 0) {
120 | writeIndex += len;
121 | readBuffer.limit(writeIndex);
122 | }
123 | }
124 |
125 | private ByteBuffer createByteBuffer(int maxReadBufferSize) {
126 | return ByteBuffer.allocate(maxReadBufferSize);
127 | }
128 |
129 | // getter
130 |
131 | public int getWriteIndex() {
132 | return writeIndex;
133 | }
134 |
135 | public int getMaxReadBufferSize() {
136 | return maxReadBufferSize;
137 | }
138 |
139 | public int getMinReadBufferSize() {
140 | return minReadBufferSize;
141 | }
142 |
143 | public int getCurrPackageIndex() {
144 | return currPackageIndex;
145 | }
146 |
147 | public ClientSocket getClientSocket() {
148 | return clientSocket;
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/core/socket/impl/SocketPool.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.core.socket.impl;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.CancelledKeyException;
5 | import java.nio.channels.SelectionKey;
6 | import java.nio.channels.Selector;
7 | import java.util.Iterator;
8 | import java.util.LinkedList;
9 | import java.util.concurrent.locks.ReentrantLock;
10 |
11 | import org.son.chat.common.net.core.socket.ISocketChannel;
12 | import org.son.chat.common.net.core.socket.ISocketPool;
13 |
14 | /**
15 | * 单线程,参考NETTY 单线程组串行处理
16 | *
17 | * @author solq
18 | */
19 | public class SocketPool implements ISocketPool, Runnable {
20 |
21 | private static final int SELECTOR_AUTO_REBUILD_THRESHOLD = 512;
22 | private Selector selector;
23 | private Thread thread;
24 | private LinkedList queue = new LinkedList<>();
25 | private ReentrantLock lock = new ReentrantLock();
26 |
27 | private ISocketChannel serverChannel;
28 |
29 | private String name;
30 | /** 执行标志 */
31 | private boolean run = false;
32 | private boolean init = false;
33 |
34 | private long lastExecutionTime;
35 | /** 每提交个任务,触发 {@link Selector#selectNow()} */
36 | private boolean needsToSelectAgain;
37 |
38 | public SocketPool(String name, ISocketChannel serverChannel) {
39 | this.serverChannel = serverChannel;
40 | this.name = name;
41 | try {
42 | selector = Selector.open();
43 | } catch (IOException e) {
44 | throw new RuntimeException(e);
45 | }
46 | }
47 |
48 | @Override
49 | public void execute(Runnable task) {
50 | if (!run) {
51 | return;
52 | }
53 | lock.lock();
54 | try {
55 | queue.add(task);
56 | } finally {
57 | lock.unlock();
58 | }
59 | if (needsToSelectAgain) {
60 | needsToSelectAgain = false;
61 | try {
62 | selector.selectNow();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | }
68 |
69 | private Runnable take() {
70 | lock.lock();
71 | try {
72 | if (queue.size() == 0) {
73 | return null;
74 | }
75 | return queue.removeFirst();
76 | } finally {
77 | lock.unlock();
78 | }
79 | }
80 |
81 | private void processNio() {
82 | select();
83 | processKeys();
84 | }
85 |
86 | private void processKeys() {
87 | for (Iterator i = selector.selectedKeys().iterator(); i.hasNext();) {
88 | // 得到下一个Key
89 | SelectionKey key = i.next();
90 | try {
91 | handle(key);
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 | }
95 | i.remove();
96 | }
97 | }
98 |
99 | /**
100 | * 参考 netty : NioEventLoop
101 | * */
102 | @Override
103 | public void select() {
104 | // select
105 | // http://goldendoc.iteye.com/blog/1152079
106 | // http://www.iteye.com/topic/650195
107 |
108 | try {
109 | int selectCnt = 0;
110 | long currentTimeNanos = System.nanoTime();
111 | long selectDeadLineNanos = currentTimeNanos+1000000L*1000;
112 | for (;;) {
113 | long timeoutMillis = (selectDeadLineNanos-currentTimeNanos + 500000L) / 1000000L;
114 | if (timeoutMillis <= 0) {
115 | if (selectCnt == 0) {
116 | //System.out.println("timeoutMillis : " +timeoutMillis + " name :" +this.name + " selectCnt :" + selectCnt);
117 |
118 | selector.selectNow();
119 | selectCnt = 1;
120 | }
121 | break;
122 | }
123 | //System.out.println("timeoutMillis : " +timeoutMillis + " name :" +this.name + " selectCnt :" + selectCnt);
124 | int selectedKeys = selector.select(timeoutMillis);
125 | selectCnt++;
126 | // || oldWakenUp || wakenUp.get() || hasTasks()
127 | if (selectedKeys != 0 || taskCount()>0) {
128 | break;
129 | }
130 |
131 | // cpu 100%处理
132 | if (SELECTOR_AUTO_REBUILD_THRESHOLD > 0 && selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {
133 |
134 | // rebuildSelector();
135 | // selector = this.selector;
136 | //
137 | // // Select again to populate selectedKeys.
138 | // selector.selectNow();
139 | // selectCnt = 1;
140 | // break;
141 | System.out.println("selectCnt 超过 SELECTOR_AUTO_REBUILD_THRESHOLD");
142 | }
143 |
144 | currentTimeNanos = System.nanoTime();
145 | }
146 | } catch (IOException e) {
147 | e.printStackTrace();
148 | }
149 |
150 | }
151 |
152 | private void handle(SelectionKey key) {
153 | ISocketChannel channel = (ISocketChannel) key.attachment();
154 | if (!key.isValid()) {
155 | System.out.println("error key");
156 | if (channel != null) {
157 | channel.doClose(key);
158 | }
159 | return;
160 | }
161 | // 可能存在一次在channel 注册多个操作 不能用 elseif
162 | try {
163 | if (key.isAcceptable()) {
164 | serverChannel.doAccept(key);
165 | }
166 | if (key.isConnectable()) {
167 | if (serverChannel != null) {
168 | serverChannel.doConnect(key);
169 | } else {
170 | channel.doConnect(key);
171 | }
172 | }
173 | if (key.isReadable()) {
174 | if (serverChannel != null) {
175 | serverChannel.doRead(key);
176 | } else {
177 | channel.doRead(key);
178 | }
179 | }
180 | // 不清楚直接 isWritable 会抛异常
181 | if (key.isValid() && key.isWritable()) {
182 | if (serverChannel != null) {
183 | serverChannel.doWrite(key);
184 | } else {
185 | channel.doWrite(key);
186 | }
187 | }
188 | } catch (CancelledKeyException e) { // key 消除事件
189 | e.printStackTrace();
190 | if (channel != null) {
191 | channel.doClose(key);
192 | }
193 | }
194 | }
195 |
196 | private void processTask(long timeoutNanos) {
197 | //System.out.println("processTask");
198 |
199 | // 处理任务计算器
200 | int count = 0;
201 | final long deadline = System.nanoTime() + timeoutNanos;
202 | while (true) {
203 | try {
204 | Runnable task = take();
205 | if (task == null) {
206 | break;
207 | }
208 | task.run();
209 | } catch (Exception e) {
210 | // logger.error("同步队列[" + key + "]处理线程出现未知错误", e);
211 | }
212 | // 延时退出
213 | if ((count++ % 255) == 0) {
214 | if (System.nanoTime() > deadline) {
215 | break;
216 | }
217 | }
218 | }
219 | this.lastExecutionTime = System.nanoTime();
220 | }
221 |
222 | /***
223 | * 参考 netty : NioEventLoop
224 | * */
225 | @Override
226 | public void run() {
227 | while (true) {
228 |
229 | /**
230 | * 优先级处理io任务 -> 非IO任务 -> 停服处理
231 | * 1.先判断是否有非IO任务 ? 马上映醒selectNow() : 阻塞 线程
232 | * 2.当连继出现 select(timeOut) ==0 超过512默认边界即认为出现 epoll的cpu 100% bug 进行
233 | * rebuild selector 处理
234 | * 3.计算执行IO任务时间,然后按比例预计非 io任务执行时间
235 | * 4.非io任务执行次数超过64 并且超过执行时间退出
236 | * */
237 | final long ioStartTime = System.nanoTime();
238 | processNio();
239 | needsToSelectAgain = false;
240 |
241 | final long ioTime = System.nanoTime() - ioStartTime;
242 | final int ioRatio = 50;
243 | // task 执行时间占nio 时间比
244 | final long taskTime = ioTime * (100 - ioRatio) / ioRatio;
245 | processTask(taskTime);
246 | // 判断关闭退出
247 | if (!run) {
248 | queue.clear();
249 | break;
250 | }
251 |
252 | }
253 | }
254 |
255 | @Override
256 | public void shutdown() {
257 | run = false;
258 | }
259 |
260 | @Override
261 | public Selector getSelector() {
262 | return selector;
263 | }
264 |
265 | @Override
266 | public int taskCount() {
267 | return queue.size();
268 | }
269 |
270 | @Override
271 | public boolean isRun() {
272 | return run;
273 | }
274 |
275 | @Override
276 | public void init() {
277 | if (this.init) {
278 | return;
279 | }
280 | synchronized (this) {
281 | if (this.init) {
282 | return;
283 | }
284 | this.init = true;
285 | run = true;
286 | thread = new Thread(this, name);
287 | thread.setDaemon(true);
288 | thread.start();
289 | }
290 | }
291 |
292 | }
293 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/exception/CoderException.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.exception;
2 |
3 | /**
4 | * 编/解码模块异常
5 | *
6 | * @author solq
7 | */
8 | public class CoderException extends RuntimeException {
9 |
10 | private static final long serialVersionUID = -5467773602825684956L;
11 |
12 | public CoderException(String message, Throwable cause) {
13 | super(message, cause);
14 | }
15 |
16 | public CoderException(Throwable cause) {
17 | super(cause);
18 | }
19 |
20 | public CoderException(String message) {
21 | super(message);
22 | }
23 |
24 | public CoderException() {
25 | super();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/exception/NetException.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.exception;
2 |
3 | /**
4 | * 网络模块异常
5 | *
6 | * @author solq
7 | */
8 | public class NetException extends RuntimeException {
9 |
10 | private static final long serialVersionUID = -8019221448806371216L;
11 |
12 | public NetException(String message, Throwable cause) {
13 | super(message, cause);
14 | }
15 |
16 | public NetException(Throwable cause) {
17 | super(cause);
18 | }
19 |
20 | public NetException(String message) {
21 | super(message);
22 | }
23 |
24 | public NetException() {
25 | super();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/util/ByteHelper.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.util;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * @author solq
7 | */
8 | public abstract class ByteHelper {
9 | public static byte[] int32Tobyte(int value) {
10 | byte[] bytes = new byte[4];
11 | bytes[0] = (byte) ((value >>> 24) & 0xff);
12 | bytes[1] = (byte) ((value >>> 16) & 0xff);
13 | bytes[2] = (byte) ((value >>> 8) & 0xff);
14 | bytes[3] = (byte) (value & 0xff);
15 | return bytes;
16 | }
17 |
18 | public static int byteToint32(byte[] bytes) {
19 | int result = (bytes[0] & 0xff) << 24;
20 | result |= (bytes[1] & 0xff) << 16;
21 | result |= (bytes[2] & 0xff) << 8;
22 | result |= bytes[3] & 0xff;
23 | return result;
24 | }
25 |
26 | public static byte[] int16Tobyte(int value) {
27 | byte[] bytes = new byte[2];
28 | bytes[0] = (byte) ((value >>> 8) & 0xff);
29 | bytes[1] = (byte) (value & 0xff);
30 | return bytes;
31 | }
32 |
33 | public static int byteToint16(byte[] bytes) {
34 | int result = (bytes[0] & 0xff) << 8;
35 | result |= bytes[1] & 0xff;
36 | return result;
37 | }
38 |
39 | public static byte[] readBytes(byte[] bytes, int start, int offSet) {
40 | byte[] result = new byte[offSet];
41 | System.arraycopy(bytes, start, result, 0, offSet);
42 | return result;
43 | }
44 |
45 | public static byte[] merge(List array) {
46 | int size = 0;
47 | int len = array.size();
48 | for (int i = 0; i < len; i++) {
49 | size += array.get(i).length;
50 | }
51 | byte[] result = new byte[size];
52 | int count = 0;
53 | for (int i = 0; i < len; i++) {
54 | System.arraycopy(array.get(i), 0, result, count, array.get(i).length);
55 | count += array.get(i).length;
56 | }
57 | return result;
58 | }
59 |
60 | public static byte[] merge(byte[]... array) {
61 | int size = 0;
62 | for (int i = 0; i < array.length; i++) {
63 | size += array[i].length;
64 | }
65 | byte[] result = new byte[size];
66 | int count = 0;
67 | for (int i = 0; i < array.length; i++) {
68 | System.arraycopy(array[i], 0, result, count, array[i].length);
69 | count += array[i].length;
70 | }
71 | return result;
72 | }
73 |
74 | public static final String bytesToHexString(byte[] bArray, int begin, int end) {
75 | StringBuffer sb = new StringBuffer(bArray.length);
76 | String sTemp;
77 | for (int i = begin; i < end; i++) {
78 | sTemp = Integer.toHexString(0xFF & bArray[i]);
79 | if (sTemp.length() < 2)
80 | sb.append(0);
81 | sb.append(sTemp.toUpperCase());
82 | sb.append(" ");
83 | }
84 | return sb.toString();
85 | }
86 |
87 | /**
88 | * @param ip
89 | * ip的字节数组形式
90 | * @return 字符串形式的ip
91 | */
92 | public static String byteToIp(byte[] ip) {
93 | StringBuilder sb = new StringBuilder();
94 | sb.append(ip[0] & 0xFF);
95 | sb.append('.');
96 | sb.append(ip[1] & 0xFF);
97 | sb.append('.');
98 | sb.append(ip[2] & 0xFF);
99 | sb.append('.');
100 | sb.append(ip[3] & 0xFF);
101 | return sb.toString();
102 | }
103 |
104 | /**
105 | * A 是否包含 B
106 | */
107 | public static boolean contains(byte[] A, byte[] B) {
108 | return indexOf(A, B) > -1;
109 | }
110 |
111 | public static int indexOf(byte[] A, byte[] B) {
112 | if (B.length > A.length) {
113 | return -1;
114 | }
115 | int result = 0;
116 | TO: for (int lastIndex = 0; lastIndex < A.length; lastIndex++) {
117 | result = lastIndex;
118 | if (B[0] == A[lastIndex]) {
119 | // next
120 | for (int n = 1; n < B.length; n++) {
121 | lastIndex++;
122 | if (lastIndex >= A.length) {
123 | return -1;
124 | }
125 | if (B[n] != A[lastIndex]) {
126 | continue TO;
127 | }
128 | }
129 | return result;
130 | }
131 | }
132 | return -1;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/util/IpUtil.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.util;
2 |
3 | import java.net.SocketAddress;
4 | import java.util.regex.Pattern;
5 |
6 | /**
7 | * @author solq
8 | * */
9 | public abstract class IpUtil {
10 | private static final int INDEX_NOT_FOUND = -1;
11 |
12 | /**
13 | * 获取会话的IP地址
14 | */
15 | public static String getIp(SocketAddress address) {
16 | if (address == null) {
17 | return null;
18 | }
19 | String ip = address.toString();
20 | return substringBetween(ip, "/", ":");
21 | }
22 |
23 | public static String getAddress(SocketAddress address) {
24 | if (address == null) {
25 | return null;
26 | }
27 | String ip = address.toString();
28 | if (ip == null) {
29 | return null;
30 | }
31 | int start = ip.indexOf("/");
32 | if (start != INDEX_NOT_FOUND) {
33 | return ip.substring(start + 1);
34 | }
35 | return null;
36 | }
37 |
38 | /*** ip地址正则配置 **/
39 | public final static Pattern ipPattern = Pattern.compile("^([0-9\\*]+\\.){3}[0-9\\*]+$");
40 |
41 | /**
42 | * 验证是否合法的IP
43 | */
44 | public static boolean isValidIp(String ip) {
45 | return ipPattern.matcher(ip).matches();
46 | }
47 |
48 | public static String substringBetween(String str, String open, String close) {
49 | if (str == null || open == null || close == null) {
50 | return null;
51 | }
52 | int start = str.indexOf(open);
53 | if (start != INDEX_NOT_FOUND) {
54 | int end = str.indexOf(close, start + open.length());
55 | if (end != INDEX_NOT_FOUND) {
56 | return str.substring(start + open.length(), end);
57 | }
58 | }
59 | return null;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/util/NamedThreadFactory.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.util;
2 |
3 | import java.util.concurrent.ThreadFactory;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | /**
7 | * 可命名线程
8 | *
9 | * @author solq
10 | */
11 | public class NamedThreadFactory implements ThreadFactory {
12 |
13 | private final String name;
14 | private final AtomicInteger count = new AtomicInteger();
15 |
16 | public NamedThreadFactory(String name) {
17 | this.name = name;
18 | }
19 |
20 | @Override
21 | public Thread newThread(Runnable r) {
22 | final String name = this.name + ":" + count.getAndIncrement();
23 | return new Thread(r, name);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/net/util/NioUtil.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.net.util;
2 |
3 | import java.nio.channels.ClosedChannelException;
4 | import java.nio.channels.SelectionKey;
5 | import java.nio.channels.Selector;
6 | import java.nio.channels.SocketChannel;
7 |
8 | /**
9 | * @author solq
10 | */
11 | public abstract class NioUtil {
12 | public static void registerSelectionKey(SelectionKey key, Selector selector, int ops) {
13 | SocketChannel channel = (SocketChannel) key.channel();
14 | try {
15 | channel.register(selector, ops);
16 | } catch (ClosedChannelException e) {
17 | e.printStackTrace();
18 | }
19 | }
20 |
21 | public static void registerSelectionKey(SocketChannel channel, Selector selector, int ops) {
22 | try {
23 | channel.register(selector, ops);
24 | } catch (ClosedChannelException e) {
25 | e.printStackTrace();
26 | }
27 | }
28 |
29 | /**
30 | * @param key
31 | * @param ops
32 | * {@link SelectionKey}
33 | */
34 | public static void setOps(SelectionKey key, int... ops) {
35 | final int interestOps = key.interestOps();
36 | for (int op : ops) {
37 | if ((interestOps & op) == 0) {
38 | key.interestOps(interestOps | op);
39 | }
40 | }
41 | }
42 |
43 | /***
44 | * 清除操作标志,让选择器不做处理
45 | */
46 | public static void clearOps(SelectionKey key, int... ops) {
47 | final int interestOps = key.interestOps();
48 | for (int op : ops) {
49 | if ((interestOps & op) != 0) {
50 | key.interestOps(interestOps & ~op);
51 | }
52 | }
53 | }
54 |
55 | public static void setOpWrite(SelectionKey key) {
56 | setOps(key, SelectionKey.OP_WRITE);
57 | }
58 |
59 | public static void clearOpWrite(SelectionKey key) {
60 | clearOps(key, SelectionKey.OP_WRITE);
61 | }
62 |
63 | public static void printlnOps(SelectionKey key) {
64 | final boolean acceptable = key.isAcceptable();
65 | final boolean connectable = key.isConnectable();
66 | final boolean readable = key.isReadable();
67 | final boolean writable = key.isWritable();
68 | System.out.println("acceptable : " + acceptable + " connectable : " + connectable + " readable : " + readable + " writable : " + writable);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/protocol/ChatHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.protocol;
2 |
3 | import java.io.UnsupportedEncodingException;
4 |
5 | import org.son.chat.common.net.core.coder.ICoderCtx;
6 | import org.son.chat.common.net.core.coder.IHandle;
7 |
8 | /**
9 | * 简单聊天业务处理
10 | * @author solq
11 | */
12 | public class ChatHandle implements IHandle {
13 |
14 | @Override
15 | public byte[] encode(String value, ICoderCtx ctx) {
16 | try {
17 | return value.getBytes("utf-8");
18 | } catch (UnsupportedEncodingException e) {
19 | e.printStackTrace();
20 | return null;
21 | }
22 | }
23 |
24 | @Override
25 | public String decode(byte[] value, ICoderCtx ctx) {
26 | try {
27 | return new String(value, "utf-8");
28 | } catch (UnsupportedEncodingException e) {
29 | e.printStackTrace();
30 | return null;
31 | }
32 | }
33 |
34 | @Override
35 | public boolean verify(Object value, ICoderCtx ctx) {
36 | // 测试不做验证
37 | return true;
38 | }
39 |
40 | @Override
41 | public void handle(String value, ICoderCtx ctx) {
42 | System.out.println("接收到信息 : " + value);
43 |
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/common/src/main/java/org/son/chat/common/protocol/PackageDefaultCoder.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common.protocol;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.son.chat.common.net.core.coder.ICoderCtx;
6 | import org.son.chat.common.net.core.coder.IPackageCoder;
7 | import org.son.chat.common.net.core.socket.impl.SocketChannelCtx;
8 | import org.son.chat.common.net.util.ByteHelper;
9 |
10 | /**
11 | * 包封装 [包头标识] + [包长度] + [包内容] 校验值暂时不处理
12 | *
13 | * @author solq
14 | */
15 | public class PackageDefaultCoder implements IPackageCoder {
16 |
17 | /** 包头标识 **/
18 | private byte[] HEAD_MARK = { 1, 0 };
19 | /** 请求包最大长度 **/
20 | private int MAX_REQUEST_LENGTH = 1024 * 1024 * 5;
21 |
22 | // //////////////////////静态构造//////////////////////////////
23 | public static PackageDefaultCoder valueOf() {
24 | PackageDefaultCoder result = new PackageDefaultCoder();
25 | return result;
26 | }
27 |
28 | public static PackageDefaultCoder valueOf(int maxRequestLength, byte[] headMak) {
29 | PackageDefaultCoder result = new PackageDefaultCoder();
30 | result.HEAD_MARK = headMak;
31 | result.MAX_REQUEST_LENGTH = maxRequestLength;
32 | return result;
33 | }
34 |
35 | /**
36 | * 将消息打包给NIO 发送
37 | */
38 | @Override
39 | public ByteBuffer encode(byte[] value, ICoderCtx ctx) {
40 | final int bufSize = HEAD_MARK.length + 4 + value.length;
41 | ByteBuffer bb = ByteBuffer.allocate(bufSize);
42 | bb.put(HEAD_MARK);
43 | bb.putInt(value.length);
44 | bb.put(value);
45 | return bb;
46 | }
47 |
48 | /**
49 | * 把包提取出消息给下一次解码器处理
50 | */
51 | @Override
52 | public byte[] decode(ByteBuffer value, ICoderCtx ctx) {
53 | SocketChannelCtx socketChannelCtx = (SocketChannelCtx) ctx;
54 | value.reset();
55 | // 包长度判断
56 | final int readSize = value.remaining() - HEAD_MARK.length;
57 | // 半包
58 | if (readSize <= 0) {
59 | return null;
60 | }
61 |
62 | // 草,getInt 不会移动索引
63 | final int bodyLen = value.getInt(value.position() + HEAD_MARK.length);
64 | // 半包
65 | if (bodyLen > readSize) {
66 | System.out.println("半包");
67 | return null;
68 | }
69 | // TODO
70 | if (bodyLen > MAX_REQUEST_LENGTH) {
71 | // TODO 非法请求
72 | }
73 |
74 | byte[] result = new byte[bodyLen];
75 | // 不同 ByteBuffer getBytes 的时候不会移动当前索引 真 恶心
76 | final int bodyPosition = value.position() + HEAD_MARK.length + 4;
77 | value.position(bodyPosition);
78 | value.get(result);
79 |
80 | final int used = HEAD_MARK.length + 4 + bodyLen;
81 | // 更新已读索引
82 | socketChannelCtx.nextPackageIndex(used);
83 | return result;
84 | }
85 |
86 | @Override
87 | public boolean verify(ByteBuffer value, ICoderCtx ctx) {
88 | value.reset();
89 | // 包长度判断
90 | final int readSize = value.remaining() - HEAD_MARK.length;
91 | // 半包
92 | if (readSize <= 0) {
93 | return false;
94 | }
95 | byte[] headMark = new byte[HEAD_MARK.length];
96 | value.get(headMark);
97 | // 头标识判断
98 | final boolean isRight = ByteHelper.contains(headMark, HEAD_MARK);
99 | return isRight;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/common/src/test/java/org/son/chat/common/ChatTestServerHandle.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common;
2 |
3 | import java.util.Date;
4 | import java.util.Timer;
5 | import java.util.TimerTask;
6 |
7 | import org.son.chat.common.net.core.coder.IHandle;
8 | import org.son.chat.common.net.core.coder.ICoderCtx;
9 | import org.son.chat.common.net.core.socket.impl.SocketChannelCtx;
10 |
11 | /**
12 | * 简单聊天业务处理
13 | *
14 | * @author solq
15 | */
16 | public class ChatTestServerHandle implements IHandle {
17 |
18 | @Override
19 | public byte[] encode(String value, ICoderCtx ctx) {
20 | return value.getBytes();
21 | }
22 |
23 | @Override
24 | public String decode(byte[] value, ICoderCtx ctx) {
25 | return new String(value);
26 | }
27 |
28 | @Override
29 | public boolean verify(Object value, ICoderCtx ctx) {
30 | // 测试不做验证
31 | return true;
32 | }
33 |
34 | @Override
35 | public void handle(String value, ICoderCtx ctx) {
36 | System.out.println("接收到信息 : ");
37 | final SocketChannelCtx socketChannelCtx = (SocketChannelCtx) ctx;
38 | // 回写自己处理
39 | Timer timer = new Timer();
40 | timer.scheduleAtFixedRate(new TimerTask() {
41 |
42 | private int sendCount = 0;
43 |
44 | @Override
45 | public void run() {
46 | sendCount++;
47 | for (int i = 0; i < 10; i++) {
48 | socketChannelCtx.send(" 发送数据 : " + i + " 次数 : " + sendCount);
49 | }
50 | System.out.println(" push message");
51 | }
52 | }, new Date(), 5000L);
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/common/src/test/java/org/son/chat/common/TestByteBuffer.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 | import org.son.chat.common.net.core.coder.impl.CoderParser;
8 | import org.son.chat.common.net.core.coder.impl.CoderParserManager;
9 | import org.son.chat.common.net.core.coder.impl.CoderResult;
10 | import org.son.chat.common.net.core.socket.impl.SocketChannelCtx;
11 | import org.son.chat.common.net.exception.CoderException;
12 | import org.son.chat.common.net.util.ByteHelper;
13 | import org.son.chat.common.protocol.ChatHandle;
14 | import org.son.chat.common.protocol.PackageDefaultCoder;
15 |
16 | /**
17 | * @author solq
18 | */
19 | public class TestByteBuffer {
20 |
21 | @Test
22 | public void testByteBuffer() {
23 | ByteBuffer bb = ByteBuffer.allocate(50);
24 | bb.put((byte) 1);
25 | bb.put((byte) 2);
26 | bb.put((byte) 3);
27 | bb.put((byte) 4);
28 | bb.put((byte) 5);
29 | Assert.assertEquals(3, bb.get(2));
30 | }
31 |
32 | @Test
33 | public void testAutoExtend() {
34 | ByteBuffer bb = ByteBuffer.allocate(1);
35 | bb.put((byte) 1);
36 | bb.put((byte) 2);
37 | bb.put((byte) 3);
38 | bb.put((byte) 4);
39 | bb.put((byte) 5);
40 | }
41 |
42 | @Test
43 | public void testSharedBuffer() {
44 | ByteBuffer bb = ByteBuffer.allocate(50);
45 | bb.put((byte) 1);
46 | bb.put((byte) 2);
47 | bb.put((byte) 3);
48 |
49 | ByteBuffer cloneBB = bb.asReadOnlyBuffer();
50 | bb.put((byte) 4);
51 |
52 | Assert.assertEquals(4, cloneBB.get(3));
53 | Assert.assertEquals(4, cloneBB.get(3));
54 |
55 | cloneBB.position(3);
56 | bb.position(5);
57 | Assert.assertEquals(4, cloneBB.get());
58 |
59 | }
60 |
61 | @Test
62 | public void testByteContains() {
63 | byte[] b1 = { 48, 1, 0, 0 };
64 | byte[] b2 = { 0, 1 };
65 | boolean flag = ByteHelper.contains(b2, b1);
66 | Assert.assertEquals(false, flag);
67 | }
68 |
69 | @Test
70 | public void testByteBufferPutInt() {
71 | String body = "发送数据 : 11";
72 | int bodyLength = body.getBytes().length;
73 | ByteBuffer bb = ByteBuffer.allocate(2 + 4 + bodyLength);
74 | bb.put((byte) 1);
75 | bb.put((byte) 2);
76 | bb.putInt(bodyLength);
77 | bb.put(body.getBytes());
78 |
79 | bb.flip();
80 |
81 | Assert.assertEquals(bodyLength, bb.getInt(2));
82 |
83 | }
84 |
85 | @Test
86 | public void testSend() throws InterruptedException {
87 | CoderParserManager coderParserManager = new CoderParserManager();
88 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
89 | SocketChannelCtx socketChannelCtx = SocketChannelCtx.valueOf(null);
90 |
91 | int count = 0;
92 | while (true) {
93 | count++;
94 | ByteBuffer sendBuffer = coderParserManager.encode("发送数据 : " + count, socketChannelCtx);
95 | ByteBuffer buffer = socketChannelCtx.readBegin();
96 | // 模拟socket read
97 | int writeSize = socketChannelCtx.readBuffer(sendBuffer);
98 | socketChannelCtx.readEnd(writeSize);
99 | boolean run = true;
100 | // 粘包处理
101 | while (run) {
102 | buffer = socketChannelCtx.coderBegin();
103 | buffer.mark();
104 | CoderResult coderResult = coderParserManager.decode(buffer, socketChannelCtx);
105 | switch (coderResult.getValue()) {
106 | case SUCCEED:
107 | break;
108 | case NOT_FIND_CODER:
109 | final int readySize = socketChannelCtx.getWriteIndex() - socketChannelCtx.getCurrPackageIndex();
110 | final int headLimit = 1024;
111 | if (readySize >= headLimit) {
112 | throw new CoderException("未找到编/解码处理器 ");
113 | }
114 | run = false;
115 |
116 | break;
117 | case UNFINISHED:
118 | case UNKNOWN:
119 | case ERROR:
120 | default:
121 | run = false;
122 | // TODO throw
123 | break;
124 | }
125 | }
126 |
127 | if (count % 500 == 0) {
128 | System.out.println("readBuffer capacity :" + buffer.capacity());
129 | Thread.sleep(200);
130 | }
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/common/src/test/java/org/son/chat/common/TestNioClient.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common;
2 |
3 | import java.util.Timer;
4 | import java.util.TimerTask;
5 |
6 | import org.junit.Test;
7 | import org.son.chat.common.net.config.SocketChannelConfig;
8 | import org.son.chat.common.net.core.coder.ICoderParserManager;
9 | import org.son.chat.common.net.core.coder.impl.CoderParser;
10 | import org.son.chat.common.net.core.coder.impl.CoderParserManager;
11 | import org.son.chat.common.net.core.handle.EmptyHandle;
12 | import org.son.chat.common.net.core.handle.HeartHandle;
13 | import org.son.chat.common.net.core.handle.SessionHandle;
14 | import org.son.chat.common.net.core.session.ISessionFactory;
15 | import org.son.chat.common.net.core.session.SessionFactory;
16 | import org.son.chat.common.net.core.session.SessionKey;
17 | import org.son.chat.common.net.core.socket.impl.ClientSocket;
18 | import org.son.chat.common.net.core.socket.impl.ServerSocket;
19 | import org.son.chat.common.net.core.socket.impl.SocketPool;
20 | import org.son.chat.common.net.util.IpUtil;
21 | import org.son.chat.common.protocol.ChatHandle;
22 | import org.son.chat.common.protocol.PackageDefaultCoder;
23 |
24 | public class TestNioClient {
25 |
26 | @Test
27 | public void normal() {
28 | ICoderParserManager coderParserManager = new CoderParserManager();
29 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
30 | final ClientSocket clientSocket = ClientSocket.valueOf(SocketChannelConfig.valueOf(6969), new SocketPool("client", null), coderParserManager, new EmptyHandle());
31 |
32 | Timer timer = new Timer();
33 | timer.schedule(new TimerTask() {
34 |
35 | @Override
36 | public void run() {
37 | clientSocket.send("连接服务器成功");
38 | System.out.println("send ");
39 | this.cancel();
40 | }
41 | }, 1000);
42 |
43 | clientSocket.start();
44 | clientSocket.sync();
45 | clientSocket.stop();
46 | }
47 |
48 | @Test
49 | public void serverMode() {
50 | ICoderParserManager coderParserManager = new CoderParserManager();
51 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
52 | ISessionFactory sessionFactory = new SessionFactory();
53 | final ServerSocket serverSocket = ServerSocket.valueOf(SocketChannelConfig.valueOf(8888), 10, 20, coderParserManager, sessionFactory);
54 |
55 | Timer timer = new Timer();
56 | timer.schedule(new TimerTask() {
57 |
58 | @Override
59 | public void run() {
60 | System.out.println("registerClientSocket");
61 | ClientSocket clientSocket = serverSocket.registerClient(SocketChannelConfig.valueOf(6969));
62 | clientSocket.send("连接服务器成功");
63 | this.cancel();
64 | }
65 | }, 1000);
66 |
67 | serverSocket.start();
68 | serverSocket.sync();
69 | serverSocket.stop();
70 | }
71 |
72 | @Test
73 | public void testGetIp() {
74 | ICoderParserManager coderParserManager = new CoderParserManager();
75 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
76 | ISessionFactory sessionFactory = new SessionFactory();
77 | final ServerSocket serverSocket = ServerSocket.valueOf(SocketChannelConfig.valueOf(8888), 10, 20, coderParserManager, sessionFactory);
78 |
79 | Timer timer = new Timer();
80 | timer.schedule(new TimerTask() {
81 |
82 | @Override
83 | public void run() {
84 | System.out.println("registerClientSocket");
85 | ClientSocket clientSocket = serverSocket.registerClient(SocketChannelConfig.valueOf(6969));
86 |
87 | clientSocket.stop();
88 | System.out.println(" ip : " + IpUtil.getAddress(clientSocket.getRemoteAddress()));
89 | this.cancel();
90 | }
91 | }, 1000);
92 |
93 | serverSocket.start();
94 | serverSocket.sync();
95 | serverSocket.stop();
96 | }
97 |
98 | @Test
99 | public void testHeart() {
100 | ICoderParserManager coderParserManager = new CoderParserManager();
101 | coderParserManager.register(CoderParser.valueOf("chat", PackageDefaultCoder.valueOf(), new ChatHandle()));
102 | ISessionFactory sessionFactory = new SessionFactory();
103 | final ServerSocket serverSocket = ServerSocket.valueOf(SocketChannelConfig.valueOf(8888), 10, 20, coderParserManager, sessionFactory);
104 | serverSocket.init();
105 | serverSocket.registerHandle(new SessionHandle(sessionFactory), new HeartHandle(5000));
106 |
107 | Timer timer = new Timer();
108 | timer.schedule(new TimerTask() {
109 |
110 | @Override
111 | public void run() {
112 | System.out.println("registerClientSocket");
113 | ClientSocket clientSocket = serverSocket.registerClient(SocketChannelConfig.valueOf(6969));
114 | clientSocket.send("连接服务器成功");
115 |
116 | System.out.println("heart time : " + SessionKey.KEY_HEART_TIME.getAttr(clientSocket.getSession()));
117 | this.cancel();
118 | }
119 | }, 1000);
120 |
121 | serverSocket.start();
122 | serverSocket.sync();
123 | serverSocket.stop();
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/common/src/test/java/org/son/chat/common/TestNioServer.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common;
2 |
3 | import org.junit.Test;
4 | import org.son.chat.common.net.config.SocketChannelConfig;
5 | import org.son.chat.common.net.core.coder.ICoderParserManager;
6 | import org.son.chat.common.net.core.coder.impl.CoderParser;
7 | import org.son.chat.common.net.core.coder.impl.CoderParserManager;
8 | import org.son.chat.common.net.core.session.ISessionFactory;
9 | import org.son.chat.common.net.core.session.SessionFactory;
10 | import org.son.chat.common.net.core.socket.impl.ServerSocket;
11 | import org.son.chat.common.protocol.PackageDefaultCoder;
12 |
13 | /**
14 | * @author solq
15 | */
16 | public class TestNioServer {
17 | @Test
18 | public void normal() {
19 | ISessionFactory sessionFactory = new SessionFactory();
20 |
21 | ICoderParserManager coderParserManager = new CoderParserManager();
22 | coderParserManager.register(CoderParser.valueOf("server chat", PackageDefaultCoder.valueOf(), new ChatTestServerHandle()));
23 | ServerSocket serverSocket=ServerSocket.valueOf(SocketChannelConfig.valueOf(6969), 10,20,coderParserManager, sessionFactory);
24 | serverSocket.start();
25 | serverSocket.sync();
26 | serverSocket.stop();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/common/src/test/java/org/son/chat/common/TestSelector.java:
--------------------------------------------------------------------------------
1 | package org.son.chat.common;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.channels.CancelledKeyException;
6 | import java.nio.channels.SelectionKey;
7 | import java.nio.channels.Selector;
8 | import java.nio.channels.ServerSocketChannel;
9 | import java.nio.channels.SocketChannel;
10 | import java.util.ConcurrentModificationException;
11 | import java.util.Iterator;
12 | import java.util.concurrent.atomic.AtomicBoolean;
13 |
14 | import org.junit.Test;
15 | import org.son.chat.common.net.core.socket.ISocketChannel;
16 | import org.son.chat.common.net.util.NioUtil;
17 |
18 | /**
19 | *
20 | * @author solq
21 | */
22 | public class TestSelector {
23 |
24 | /***
25 | * Selector: 获取键集 Set keys()
26 | * Set selectedKeys()
27 | * 以上方法返回选择器的不同键集。keys()方法返回当前已注册的所有键。
28 | * 返回的键集是不可修改的:任何对其进行直接修改的尝试(如,调用其remove()方法)
29 | * 都将抛出UnsupportedOperationException异常。
30 | * selectedKeys()方法用于返回上次调用select()方法时,被"选中"的已准备好进行I/O操作的键。
31 | * 重要提示:selectedKeys()方法返回的键集是可修改的,实际上在两次调用select()方法之间,都必须"手工"将其清空。
32 | * 换句话说,select方法只会在已有的所选键集上添加键,它们不会创建新的键集。
33 | *
34 | * @throws InterruptedException
35 | */
36 | @Test
37 | public void testResigter() throws IOException, InterruptedException {
38 | final Selector selector = Selector.open();
39 | Selector selector2 = Selector.open();
40 |
41 | ServerSocketChannel socketChannel = ServerSocketChannel.open();
42 | socketChannel.configureBlocking(false);
43 | socketChannel.bind(new InetSocketAddress(6969));
44 | socketChannel.register(selector, SelectionKey.OP_ACCEPT);
45 | new Thread(new Runnable() {
46 |
47 | @Override
48 | public void run() {
49 | while (true) {
50 | try {
51 | int n = selector.select();
52 | if (n <= 0) {
53 | System.out.println("xxxxxxxxxxxxx");
54 | continue;
55 | }
56 | for (Iterator i = selector.selectedKeys().iterator(); i.hasNext();) {
57 | // 得到下一个Key
58 | SelectionKey key = i.next();
59 |
60 | // 要手动移除 SelectionKey
61 | i.remove();
62 | NioUtil.printlnOps(key);
63 | }
64 | } catch (IOException e) {
65 | e.printStackTrace();
66 | }
67 |
68 | }
69 |
70 | }
71 | }).start();
72 | // socketChannel.register(selector2, SelectionKey.OP_ACCEPT);
73 | while (true) {
74 | Thread.sleep(5000);
75 | }
76 | }
77 |
78 | @Test
79 | public void testResigter1() throws IOException, InterruptedException {
80 | final Selector selector = Selector.open();
81 | new Thread(new Runnable() {
82 |
83 | @Override
84 | public void run() {
85 | while (true) {
86 | try {
87 | int n = selector.select();
88 | if (n < 0) {
89 | System.out.println(n);
90 | continue;
91 | }
92 | for (Iterator i = selector.selectedKeys().iterator(); i.hasNext();) {
93 | // 得到下一个Key
94 | SelectionKey key = i.next();
95 |
96 | // 要手动移除 SelectionKey
97 | i.remove();
98 | NioUtil.printlnOps(key);
99 | }
100 | } catch (IOException e) {
101 | e.printStackTrace();
102 | }
103 |
104 | }
105 | }
106 | }).start();
107 |
108 | SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(6969));
109 | socketChannel.configureBlocking(false);
110 | socketChannel.register(selector, 0);
111 | while (true) {
112 | Thread.sleep(5000);
113 | }
114 | }
115 |
116 | // 关服时执行 SelectionKey.cancel()
117 | // 关闭时 或者read 操作异常 也要执行
118 |
119 | /***
120 | * 通过Selector选择通道
121 | * 一旦向Selector注册了一或多个通道,就可以调用几个重载的select()方法。这些方法返回你所感兴趣的事件(如连接、接受、读或写)
122 | * 已经准备就绪的那些通道。
123 | * 换句话说,如果你对“读就绪”的通道感兴趣,select()方法会返回读事件已经就绪的那些通道。
124 | * 下面是select()方法:(该方法是阻塞方法)
125 | * int select()
126 | * int select(long timeout)
127 | * int selectNow()
128 | * select()阻塞到至少有一个通道在你注册的事件上就绪了。
129 | * select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。
130 | */
131 | /***
132 | * Selector.open();占用双TCP
133 | * http://developer.51cto.com/art/201112/306870.htm
134 | * http://zhhphappy.iteye.com/blog/2032893
135 | *
136 | * @throws IOException
137 | * @throws InterruptedException
138 | */
139 | @Test
140 | public void testSelector() throws IOException, InterruptedException {
141 | int count = 10;
142 | for (int i = 0; i < count; i++) {
143 | Selector.open();
144 | }
145 | Thread.sleep(30000);
146 | }
147 |
148 | @Test
149 | public void testCompareAndSet() {
150 | AtomicBoolean wakenUp = new AtomicBoolean();
151 | wakenUp.set(true);
152 | boolean result = wakenUp.compareAndSet(false, true);
153 | System.out.println("one : " + result);
154 |
155 | wakenUp.set(false);
156 | result = wakenUp.compareAndSet(false, true);
157 | System.out.println("two : " + result);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------