java中我想导入import java.nio.filecharset.StandardCharsets,但是不知道这个类属于那个jar包呢

当前访客身份:游客 [
当前位置:
本文转自:&
感谢原作者。
衡量每种分词的指标,内存消耗、CPU消耗,得到一个在Lucene中比较好的分词版本。
分词源代码介绍
paoding: 庖丁解牛最新版在&&中最多支持Lucene 3.0,且最新提交的代码在 ,在svn中最新也是2010年提交,已经过时,不予考虑。
mmseg4j:最新版已从&&移至&,支持Lucene 4.10,且在github中最新提交代码是2014年6月,从09年~14年一共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。
IK-analyzer: 最新版在/p/ik-analyzer/上,支持Lucene 4.10从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 但是也就是2012年12月后没有在更新。
ansj_seg:最新版本在&&tags仅有1.1版本,从2012年到2014年更新了大小6次,但是作者本人在日说明:“可能我以后没有精力来维护ansj_seg了”,现在由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个由CRF(条件随机场)算法所做的分词算法。
imdict-chinese-analyzer:最新版在&&, 最新更新也在2009年5月,下载源码,不支持Lucene 4.10 。是利用HMM(隐马尔科夫链)算法。
Jcseg:最新版本在,支持Lucene 4.10,作者有较高的活跃度。利用mmseg算法。
测试环境:
Ubuntu 14.04 64位, 内存 32GB, CPU Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz × 8
分词算法衡量指标及测试代码
黄金标准/Golden standard
评价一个分词器分词结果的好坏,必然要有一份“公认正确”的分词结果数据来作为参照。 SIGHAN(国际计算语言学会(ACL)中文语言处理小组)举办的国际中文语言处理竞赛Second International Chinese Word Segmentation Bakeoff(http://sighan.cs.uchicago.edu/bakeoff2005/)所提供的公开数据来评测,它包含了多个测试集以及对应的黄金标准分词结果。在所有分词器都使用同一标准来评测的情况下,也就会很公平,并不会影响到最终的结论,所以本文用此测评标准,并针对创建索引,做了些改动。
精度(Precision):精度表明了分词器分词的准确程度。
召回率(Recall):召回率也可认为是“查全率”。
F值(F-mesure):F值综合反映整体的指标。
错误率(Error Rate --ER)(带选项):分词器分词的错误程度。
公式参数说明
N:黄金标准分割的单词数; e:分词器错误标注的单词数; c:分词器正确标注的单词数.
总结:P、R、F越大越好,ER越小越好。一个完美的分词器的P、R、F值均为1,ER值为0。
正确及错误标注的计数算法
要先计算出e和c,才能计算出各指标值。e和c是按如下算法来统计的: 在“黄金标准”和“待评测的结果”中,理论上,除了分词后添加的空格之外,它们所有的文字都是相同的;唯一的不同就在于那些有差异的分词结果的位置上。例如,“计算机 是个 好东西”(黄金标准)与“计算机 是 个 好东西”(待评测的结果)的差异就在于“是个”与“是 个”的差异,其余分词结果都是相同的。因此,只需要找到这种差异的个数,就可以统计出分词器正确标注了多少个词、错误标注了多少个词。为了完成测试指标,同时,对应Lucene的检索实际需要对黄金标准的 *_test_gold和分词结果做了如下改动:
去掉标点符号
统一对一些虚词作停词处理
没有分开句子,结果都是一个比较集。
统一的perl处理代码
#!/usr/bin/perl
if (@ARGV != 2) {
print "No param which will be read!";
open (FpStopDir, $ARGV[0]) or die "The stopping dictionary($ARGV[0]) cannot open!$!\n";
%dict = ();
while(&FpStopDir&){
s/^\s*//;#remove start space char
s/\s*$//;#remove the space char in the end of string
$dict{$_} = 1;
close(FpStopDir);
open(FpDeal, $ARGV[1]) or die "The file ($ARGV[1]) which will be dealed cannot open! $!\n";
my@DealedW
while (&FpDeal&){
@Word = split /\s+/, $_;
foreach $AWord(@Word){
if(1 != $dict{$AWord}){
print "$AWord ";
close(FpDeal);
Java测试代码
package com.
import org.apache.lucene.analysis.A
import org.apache.lucene.analysis.TokenS
import org.apache.lucene.analysis.cjk.CJKA
import org.apache.lucene.analysis.core.SimpleA
import org.apache.lucene.analysis.standard.StandardA
import org.apache.lucene.analysis.tokenattributes.CharTermA
import org.lionsoul.jcseg.analyzer.JcsegAnalyzer4X;
import org.lionsoul.jcseg.core.*;
import org.wltea.analyzer.lucene.IKA
import com.chenlb.plexA
import java.io.*;
public class TestChineseAnalyzer {
private static int PER_TIME_READ_LEN = 1024;
//每次读入文件流长度
private TestChineseAnalyzer() {}
public static void printTerms(Analyzer analyzer, String content){
TokenStream ts = analyzer.tokenStream("content",
new StringReader(content));
CharTermAttribute term = ts.addAttribute(CharTermAttribute.class);
ts.reset();
StringBuffer buf = new StringBuffer();
while (ts.incrementToken()) {
buf.append(term.toString());
buf.append(" ");
System.out.println(buf.toString());
System.out.println(analyzer.getClass().getName() + " done\n");
}catch (IOException ex){
System.out.println("Segment word fail. " + ex.getMessage());
public static void main(String[] args){
if (0 == args.length){
System.err.println("No Inputing param");
System.exit(1);
FileInputStream in = new FileInputStream(new File(args[0]));
byte[] perRead = new byte[PER_TIME_READ_LEN];
String strContent = " ";
int rst = in.read(perRead, 0, PER_TIME_READ_LEN);
while (-1 != rst){
strContent = strContent.concat(new String(perRead));
rst = in.read(perRead, 0, PER_TIME_READ_LEN);
printTerms(new PLEX_MODE), strContent);
printTerms(new IKAnalyzer(true), strContent);
printTerms(new CJKAnalyzer(), strContent);
printTerms(new SimpleAnalyzer(), strContent);
printTerms(new StandardAnalyzer(), strContent);
printTerms(new ComplexAnalyzer(), strContent);
} catch (Exception ex) {
ex.printStackTrace();
运行Java通过重定向到一个txt文件,再将彼此分开,如上所示,没有看过Lucene本身的分词的烂,所以自己也查看了一下,果然很烂。 通过对结果的处理(用上面的Perl脚本,统一对标准和对结果的处理)。再利用 黄金标准中的Perl评分脚本。
此结果并没有按照黄金标准正确用法来用(主要没有用黄金标准来训练,且评分本身是一句一句的评分,最后是综合得分。 而本文是所有内容一起评分,会有一定误差)。同时:现在的分词,比较而言更加智能,能将数量词等(一位,同志们)分在一起,是以前可能没能想过的。 虽然,有诸多误差,但是本文只是比较相对值,只要在统一的相对正确的标准下也就能达到效果了。
分词算法内存和cup测试
在一个大的语料库中,所有文档加入Lucene索引的时间,测试内存使用情况,就将索引建立在磁盘中; 若是测试CPU使用情况,就将所以建立的内存中减小IO读写对CPU的影响。利用VisualVM查看CPU利用率、内存利用率,得到他们的时间序列图。
Java程序如下
package com.
import org.apache.lucene.store.RAMD
import org.lionsoul.jcseg.analyzer.JcsegAnalyzer4X;
import com.chenlb.plexA
import org.apache.lucene.document.*;
import org.apache.lucene.index.IndexW
import org.apache.lucene.index.IndexWriterC
import org.apache.lucene.index.T
import org.apache.lucene.store.D
import org.apache.lucene.store.FSD
import org.apache.lucene.util.V
import org.lionsoul.jcseg.core.JcsegTaskC
import org.wltea.analyzer.lucene.IKA
import java.io.*;
import java.nio.charset.StandardC
public class FileIndexTest {
private FileIndexTest() {}
private IndexWriterConfig conf =
public FileIndexTest(IndexWriterConfig conf) {
this.conf =
public void indexFilesInDir(String docsPath, String indexPath, boolean createIfNotExists){
final File docDir = new File(docsPath);
if (!docDir.exists() || !docDir.canRead()) {
System.out.println("Document directory '" +docDir.getAbsolutePath()+ "' does not exist or is not readable, please check the path");
System.exit(1);
long start = System.currentTimeMillis();
System.out.println("Indexing into directory '" + indexPath + "'...");
Directory dir = null != indexPath ? FSDirectory.open(new File(indexPath)): new RAMDirectory();
if (createIfNotExists) {
conf.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
conf.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
IndexWriter writer = new IndexWriter(dir, conf);
indexDocs(writer, docDir);
writer.close();
System.out.println(System.currentTimeMillis() - start + " total milliseconds");
} catch (IOException ex) {
ex.printStackTrace();
public static void indexDocs(IndexWriter writer, File file) throws IOException {
if (file.canRead()) {
if (file.isDirectory()) {
String[] files = file.list();
if (files != null) {
for (int i = 0; i & files. i++) {
indexDocs(writer, new File(file, files[i]));
FileInputS
fis = new FileInputStream(file);
} catch (FileNotFoundException fnfe) {
Document doc = new Document();
Field pathField = new StringField("path", file.getPath(), Field.Store.YES);
doc.add(pathField);
doc.add(new LongField("modified", file.lastModified(), Field.Store.NO));
doc.add(new TextField("contents", new BufferedReader(new InputStreamReader(fis, StandardCharsets.UTF_8))));
if (writer.getConfig().getOpenMode() == IndexWriterConfig.OpenMode.CREATE) {
// New index, so we just add the document (no old document can be there):
System.out.println("adding " + file);
writer.addDocument(doc);
System.out.println("updating " + file);
writer.updateDocument(new Term("path", file.getPath()), doc);
} finally {
fis.close();
public static void main(String[] args) {
String usage = "java org.apache.lucene.demo.IndexFiles"
+ " [-index INDEX_PATH] [-docs DOCS_PATH] [-update]\n\n"
+ "This indexes the documents in DOCS_PATH, creating a Lucene index"
+ "in INDEX_PATH that can be searched with SearchFiles";
String indexPath =
String docsPath =
boolean create =
for (int i = 0; i & args. i++) {
if ("-index".equals(args[i])) {
indexPath = args[i + 1];
} else if ("-docs".equals(args[i])) {
docsPath = args[i + 1];
} else if ("-update".equals(args[i])) {
if (docsPath == null) {
System.err.println("Usage: " + usage);
System.exit(1);
/*IKAnalyzer*/
FileIndexTest test = new FileIndexTest(new IndexWriterConfig(Version.LUCENE_4_10_2, new IKAnalyzer()));
test.indexFilesInDir(docsPath, indexPath, create);
FileIndexTest test1 = new FileIndexTest(new IndexWriterConfig(Version.LUCENE_4_10_2, new PLEX_MODE)));
test1.indexFilesInDir(docsPath, indexPath, create);
FileIndexTest test2 = new FileIndexTest(new IndexWriterConfig(Version.LUCENE_4_10_2, new ComplexAnalyzer()));
test2.indexFilesInDir(docsPath, indexPath, create);
如上所示:IK-analyzer、Jcseg、mmseg4j都是用统一接口,测试,就将其他两个给注释掉。 同时:当测试内存消耗量时, 我们需要将索引建立在磁盘中测试jar包的命令例子如下:
java -jar indexFile.jar -docs ~/resource/ -index ~/index/
当测试CPU消耗时,我们尽量减小IO的消耗,那么可以将索引建立在内存中,测试jar包的命令例子如下:
java -jar indexFile.jar -docs ~/resource/s
得到如下面所有图所示的结果:
Figure 1. IK-Analyzer分词消耗内存&
Figure 2. Jcseg分词消耗内存&
Figure 3. mmseg4j分词消耗内存&
Figure 4. IK-Analyzer分词CPU使用率&
Figure 5. Jcseg分词CPU使用率&
Figure 6. mmseg4j分词CPU使用率
从几个指标对比来看:IK-analyzer的准确度稍差,Jcseg的时间消耗稍差
时间消耗上:在索引创建1,003,057 items, totalling 2.8 GB的文件:
将其索引放入磁盘
Jcseg + Lucene建索引消耗:
516971 total milliseconds
mmseg4j + Lucene建索引消耗:
256805 total milliseconds
IK-Analyzer + Lucene建索引消耗:
445591 total milliseconds
Standard + Lucene建索引消耗:
184717 total milliseconds 内存消耗最大不过650M多 CPU消耗减小不大 (磁盘数据仅仅增加0.2G~0.3G左右)
将索引放在内存中
Jcseg + Lucene 建索引消耗:
510146 total milliseconds
mmseg4j + Lucene建索引消耗:
262682 total milliseconds
IK-Analyzer + Lucene建索引消耗:
436900 total milliseconds
Standard + Lucene建索引消耗:
183271 total milliseconds CUP的高峰值频率明显增多
综上所有因素:
准确率为:Jcseg & mmseg4j & IK-Analyzer。
内存消耗和CPU使用率上,几个都在一个数量级上,很难分出胜负。
但是在时间消耗上明显mmseg4j的优势非常突出。
从活跃度来看,mmseg4j的活跃度也是非常可喜的。
共有6个评论
<span class="a_vote_num" id="a_vote_num_
<span class="a_vote_num" id="a_vote_num_
<span class="a_vote_num" id="a_vote_num_
谢谢分享,正在为选择什么分词工具苦恼时,就看到了楼主的文章。
<span class="a_vote_num" id="a_vote_num_
<span class="a_vote_num" id="a_vote_num_
谢谢楼主。
<span class="a_vote_num" id="a_vote_num_
谢谢分享,正在为选择什么分词工具苦恼时,就看到了楼主的文章。
有什么技术问题吗?
狮子的魂的其他问题
类似的话题今天看啥 热点:
Java8读文件仅需一行代码,java8读一行代码
Java8读文件仅需一行代码JDK7中引入了新的文件操作类java.nio.file.File,它包含了很多有用的方法来操作文件,比如检查文件是否为隐藏文件,或者是检查文件是否为只读文件。开发者还可以使用Files.readAllBytes(Path)方法把整个文件读入内存,此方法返回一个字节数组,还可以把结果传递给String的构造器,以便创建字符串输出。此方法确保了当读入文件的所有字节内容时,文件属性是关闭的,否则就会出现IO异常或其它的未检查异常。这意味着在读文件到最后的块内容后,无需关闭文件。要注意,此方法不适合读取很大的文件,因为可能存在内存空间不足的问题。开发者还应该明确规定文件的字符编码,以避免任异常或解析错误。作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs如果你想读入文件作为字符串,那么你还可以使用readAllLines(Path path, Charset cs)方法,此方法与之前的方法相似,也是在读完文件后无需关闭文件。但是它返回的不是字节数组,而是字符串数组。而且,Java8重写了此方法,无需指定字符集,直接使用UTF-8编码进行字符串转换。如果你想一行一行的读入文件作为字符串,那么你可以使用Files.lines()方法,它会从读入的文件中返回字符串流,并使用UTF-8编码把字节转换成字符。使用forEach()方法,可以只用一行Java代码实现把文件的所有内容输出到控制台,如下面第三个代码片段。import java.io.IOE
import java.nio.charset.StandardC
import java.nio.file.F
import java.nio.file.P
import java.util.L
public class FileReadingTest {
public static void main(String[] args) throws IOException {
// Java 7 例子
// Files.readAllBytes默认以UTF-8编码读入文件,故文件的编码如果不是UTF-8,那么中文内容会出现乱字符
System.out.println(new String(Files.readAllBytes(Paths.get(&D:\\jd.txt&))));
// Java 8例子
List&String& lines = Files.readAllLines(Paths.get(&D:\\jd.txt&), StandardCharsets.UTF_8);
StringBuilder sb = new StringBuilder();
for(String line : lines){
sb.append(line);
String fromFile = sb.toString();
System.out.println(fromFile);
}如果使用的不是JDK7,而是JDK8,那么一行代码即可完成读文件。import static java.lang.System.
import static java.nio.file.Files.readAllB
import static java.nio.file.Paths.
import java.io.IOE
public class FileIntoString {
public static void main(String[] args) throws IOException {
// 一行代码搞定读文件,默认是UTF-8编码
out.println(new String(readAllBytes(get(&d:/jd.txt&))));
}如果使用JDK8,那么还可以使用流API来读写文件,这样代码更简洁、高效。下面的例子中,lines()方法返回字符串流,字符串使用的是UTF-8编码。如下:import java.io.IOE
import java.nio.charset.StandardC
import java.nio.file.F
import java.nio.file.P
public class Java8FileReader {
public static void main(String[] args) throws IOException {
// Java8用流的方式读文件,更加高效
Files.lines(Paths.get(&D:\\jd.txt&), StandardCharsets.UTF_8).forEach(System.out::println);
}上面的例子要注意几点:1)文件可能很大,可能会超出内存空间,使用前要做评估。2)要输出日志,记录为什么无法读取文件或者在阅读文件时遇到的任何错误。3)在把字节转换成字符时,应该指定字符编码。4)要处理文件不存在的情况。还要注意,如果读入的文件的编码是ANSI编码,那么上面的例子在读取文件内容时会报java.nio.charset.MalformedInputException: Input length = 1错误。
相关搜索:
相关阅读:
相关频道:
&&&&&&&&&&&&&&&&
WEB编程教程最近更新关于Apache Mina的文章,资料已经非常多了,我想再多一篇也不过为。另外Main现在3.x版本正在开发中,且已经有M2(里程碑)发布了。本文中主要针对Mina2.0.9(这个版本也是最后一个2.x版本了)来记录学习和使用的过程和体会。
Mina2.x的文档还算比较全面: http://mina.apache.org/mina-project/userguide/user-guide-toc.html (有些部分可能没有更新,未来讲更多关注和使用3.x)。
开发服务器和客户端网络应用 使用Mina开发,客户端连接器和服务端接收器有更多的相似之处,Mina在API设计的时候使用了更高的抽象如:IoService,对于创建服务器端接收器我们将关注IoAccepor,而客户端连接器则是IoConnector. 下面图1是关于Mina的基本使用的描述:
图1这里对图1做简单的说明:图1由大的三部分组成,通过颜色就很容易区分和理解器表示的意思。对于服务器(Server)和客户端(Client)而言它们都需要中间最大一块的组成部分,其中包含了配置(Configure),会话数据工厂(SessionDataFactory),过滤器链(FilterChina,由多个过滤器组成),监听器组(有多个Listener组成),处理器(IoHandler);第三部分则可以看出服务器对应的是绑定(bind),客户端对应的是连接(connect)由此区分了服务器和客户端。说了这么多,就中间部分而言,Mina框架最大程度的解放了开发过程要进行的会话管理,会话数据管理,服务监听处理,过滤器,服务配置等的实现,其都提供了默认实现,当然可以根据使用情况实现对应的接口来自行处理。2.过滤器Mina中的过滤器的顶层接口是IoFilter,其自身提供了多种过滤器,比如:LoggingFilter,ExecutorFilter,BlacklistFilter(请求地址黑名单过滤),SSLFilter,编码和解密过滤器等等(更多参考API http://mina.apache.org/mina-project/apidocs/index.html)。过滤器是Mina框架中极其重要和有价值的部分,其提供了日志,安全,权限控制,统计等过滤器,并且其是可插拔的,可以通过不同的过滤器以不同的顺序组成过滤器链将实现不同的功能。另外可以通过实现IoFilter接口或者继承IoFilterAdapter来创建更多具体业务中需要的IoFilter,当然这么做之前,可以仔细看看Mina的org.apache.mina.filter包下是否已经提供了实现。3.编码和解码编码和解码作为网络应用开发必须面对的问题,而Mina作为全功能的网络通讯框架,实现对数据报文的编码和解码自然是其分内之事,具体使用者可更多关注IoHandler,即具体处理接收和发送报文的相关业务。在org.apache.mina.filter.codec包下有更多的关于编码和解码的实现。关于编码其方式有很多种,比如Protobuf,serialization(对象序列化),JSON,BASE64等,而解码则涉及到字节流分割的问题,下图2是三种常用的字节流分割的方式:
图2 上面三种方式中2和3在Mina中都有对应的实现,比如3特殊字符结尾标记对应的实现有TextLineEncoder和TextLineDecoder,两者组成了TextLineCodecF 2固定字节的head表示数据字节数有PrefixedStringEncoder和PrefixedStringDecoder,两者组成了PrefixedStringCodecFactory。第一种固定长度字节数这种主要应用在传输命令的场景中,其传输的字节数是固定,应用中可以自己根据具体情况来实现对应的编码和解密类。4.一个具体案例来贯穿全文本案例通过客户端发送短信信息到服务器,然后服务器将其短信信息的发送者和接受者对调,短信内容设置&OK&,发回给客户端。4.1定义短信格式(protobuf):package secondriver.mina.bo. option java_package = &secondriver.mina.bo.protobuf&;option java_outer_classname = &SmsDataProtocal&; message Sms {required string protocol
= 1;required string sender
= 2;required string receiver
= 3;required string content
= 4;}使用protoc命令将定义个消息生成Java类(使用方式可以参考:)。4.2编写Sms对象的编码和解密类,这里我们直接编写编码解密工程类,其由编码和解密类组合而成。package secondriver.mina.bo.import java.nio.charset.Cimport java.nio.charset.StandardCimport org.apache.mina.core.buffer.IoBimport org.apache.mina.core.session.IoSimport org.apache.mina.filter.codec.CumulativeProtocolDimport org.apache.mina.filter.codec.ProtocolCodecFimport org.apache.mina.filter.codec.ProtocolDimport org.apache.mina.filter.codec.ProtocolDecoderOimport org.apache.mina.filter.codec.ProtocolEimport org.apache.mina.filter.codec.ProtocolEncoderAimport org.apache.mina.filter.codec.ProtocolEncoderOimport com.google.protobuf.ByteSimport secondriver.mina.bo.protobuf.SmsDataProtocal.Spublic class SmsDataCodecFactory implements ProtocolCodecFactory { private final Charset charset = StandardCharsets.UTF_8; private int prefixLength = 4; private int maxDataLength = 1024; @Override public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return new ProtocolEncoderAdapter() {
public void encode(IoSession session, Object message,
ProtocolEncoderOutput out) throws Exception {
Sms sms = (Sms)
String content = sms.toByteString().toStringUtf8();
IoBuffer buffer = IoBuffer.allocate(content.length())
.setAutoExpand(true);
buffer.putPrefixedString(content, prefixLength,
charset.newEncoder());
if (buffer.position() & maxDataLength) {
throw new IllegalArgumentException(&Data length: &
+ buffer.position());
buffer.flip();
out.write(buffer);
}; } @Override public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return new CumulativeProtocolDecoder() {
protected boolean doDecode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {
if (in.prefixedDataAvailable(prefixLength, maxDataLength)) {
String msg = in.getPrefixedString(prefixLength,
charset.newDecoder());
Sms sms = Sms.parseFrom(ByteString.copyFrom(msg,
charset.name()));
out.write(sms);
}; }}4.3参见文中1端来写服务端创建IoAccptor对象-&设置过滤器-&设置IoHandler-&配置-&绑定到指定IP和端口package secondriver.mina.import java.io.IOEimport java.net.InetSocketAimport java.util.concurrent.Eimport org.apache.mina.core.filterchain.DefaultIoFilterChainBimport org.apache.mina.core.service.IoAimport org.apache.mina.core.service.IoHandlerAimport org.apache.mina.core.session.IdleSimport org.apache.mina.core.session.IoSimport org.apache.mina.filter.codec.ProtocolCodecFimport org.apache.mina.filter.executor.ExecutorFimport org.apache.mina.filter.logging.LogLimport org.apache.mina.filter.logging.LoggingFimport org.apache.mina.transport.socket.nio.NioSocketAimport secondriver.mina.bo.protobuf.SmsDataCodecFimport secondriver.mina.bo.protobuf.SmsDataProtocal.Spublic class SmsServer { public static final int PORT = 9001; public static void main(String[] args) throws IOException {
IoAcceptor acceptor = new NioSocketAcceptor();
// 过滤器链
DefaultIoFilterChainBuilder builder = new DefaultIoFilterChainBuilder();
LoggingFilter loggingFilter = new LoggingFilter();
loggingFilter.setExceptionCaughtLogLevel(LogLevel.DEBUG);
builder.addLast(&logging&, loggingFilter);
builder.addLast(&codec&, new ProtocolCodecFilter(
new SmsDataCodecFactory()));
builder.addLast(&threadPool&,
new ExecutorFilter(Executors.newCachedThreadPool()));
acceptor.setFilterChainBuilder(builder);
// 设置处理器IoHandler
acceptor.setHandler(new IoHandlerAdapter() {
public void messageReceived(IoSession session, Object message)
throws Exception {
Sms sms = (Sms)
System.out.println(&客户端发来:&);
System.out.println(sms.toString());
// 服务器发送
Sms serverSms = Sms.newBuilder().setProtocol(sms.getProtocol())
.setContent(&OK&).setReceiver(sms.getSender())
.setSender(sms.getSender()).build();
session.write(serverSms);
// 配置服务器(IoAccptor)
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 绑定到指定IP和端口
acceptor.bind(new InetSocketAddress(PORT)); }}4.4 参见文中1端编写客户端package secondriver.mina.import java.net.InetSocketAimport java.util.Simport java.util.concurrent.Eimport java.util.concurrent.TimeUimport org.apache.mina.core.RuntimeIoEimport org.apache.mina.core.future.ConnectFimport org.apache.mina.core.service.IoCimport org.apache.mina.core.service.IoHandlerAimport org.apache.mina.core.session.IoSimport org.apache.mina.filter.codec.ProtocolCodecFimport org.apache.mina.filter.executor.ExecutorFimport org.apache.mina.transport.socket.nio.NioSocketCimport secondriver.mina.bo.protobuf.SmsDataCodecFimport secondriver.mina.bo.protobuf.SmsDataProtocal.Spublic class SmsClient { private static InetSocketAddress server = new InetSocketAddress(
&127.0.0.1&, 9001); public static void main(String[] args) throws InterruptedException {
// 客户端连接器
IoConnector connector = new NioSocketConnector();
connector.getFilterChain().addLast(&codec&,
new ProtocolCodecFilter(new SmsDataCodecFactory()));
connector.getFilterChain().addLast(&threadPool&,
new ExecutorFilter(Executors.newCachedThreadPool()));
connector.setHandler(new IoHandlerAdapter() {
public void sessionCreated(IoSession session) throws Exception {
public void messageReceived(IoSession session, Object message)
throws Exception {
System.out.println(&服务器响应:&);
System.out.println(((Sms) message).toString());
// 建立会话Session
IoSession session =
while (true) {
ConnectFuture future = connector.connect(server);
future.awaitUninterruptibly(100, TimeUnit.SECONDS);
session = future.getSession();
if (null != session) {
} catch (RuntimeIoException e) {
System.err.println(&Failed to connect with &
+ server.toString());
e.printStackTrace();
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
// 客户端输入
try (Scanner scanner = new Scanner(System.in);) {
while (true) {
String sender = &&;
System.out.println(&请输入收信息手机号:&);
String receiver = scanner.nextLine();
System.out.println(&请输入信息内容:&);
String content = scanner.nextLine();
Sms sms = Sms.newBuilder()
.setProtocol(& TC-C/2.0&)
.setSender(sender).setReceiver(receiver)
.setContent(content).build();
session.write(sms);
Thread.sleep(10000);
System.out.println(&是否继续,回车继续 , q or quit 退出:&);
String line = scanner.nextLine();
if (line.trim().equalsIgnoreCase(&q&)
|| line.trim().equalsIgnoreCase(&quit&)) {
session.close(false);
connector.dispose(); }}4.5 启动服务,启动客户端图3是运行的结果: 客户端信息:
服务器信息:
说明:上面客户端和服务器端的关于IoHandler直接使用了匿名类的方式对数据的接收做了相应的简单处理。Sms对象转换成UTF-8编码的字符串,采用了3端中编码和解密的第2中方式,并且传输的数据最大长度为1024byte(1k)。另外,Potobuf-java和Mina集成,mina3.x提供了对protobuf定义的消息的编码和解码提供了实现支持。为了需要更多关注Mina3.x,另外Netty的发展势头正旺,netty有种子承父业的感觉,也值得拥有!
另外关于使用Mina2.x的一个多客户端会话的示例见: https://code.csdn.net/snippets/546078.js
本文出自 “野马红尘” 博客,谢绝转载!

我要回帖

更多关于 charset utf 8 的文章

 

随机推荐