首页 > Python基础教程 >
-
C#教程之吐槽net下没有靠谱的FastDFS的sdk之使用t
事情是这样的,在一个新项目中引入了fastdfs,用这玩意做一些小数据的存储还是很方便的,然后在nuget上就找到了一个FastDFS的sdk,如下图:
一眼就看到了这个top1的sdk,应该会比较靠谱。。。简单的在项目中应用了一下没啥问题就忽悠上线了,然后就悲剧了,测试那边反馈说上传了一个
人群,拉下来的时候少了几个人,我的使用方式是将一批customerid按照bitmap的形式存到byte[]数组传到fastdfs,最后硬着头皮追踪下来发现是这个所谓
的sdk在upload的时候在bytes数组处理上出了bug,这下无语了,哎,nuget上这写sdk的估计也就是个人写着玩玩丢上去的,哪里敢用到生产上,还好在测
试环境发现了,不然又得出什么乱子了。
一:解决办法
问题还得要解决,不过庆幸的是,fastdfs是阿里的一个大牛YuQing写的,那应该有java的sdk更靠谱一点,用maven的话更方便。
<dependency> <groupId>net.oschina.zcx7878</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27.0.0</version> </dependency>
pull下来以后,这个sdk果然是fastdfs的作者写的,这下子安全感暴增,测试了一下,那个bug用这个sdk果然就没有问题了。。。开心~~~~
然后流程图大概就变成了这个样子。
二:解决C# 和 JAVA的互通问题
互通方式比较多,除了走rest这种面向http的方式,还可以使用thrift,grpc这种tcp的模式,最后我决定还是采用thrift走一遭,目前最新的版本是0.11了。
网址:http://thrift.apache.org/。 看了一下C#的thrift sdk,貌似最高支持0.9.1,网址为:http://archive.apache.org/dist/thrift/0.9.1/ ,
有了这个thrift-0.9.1.exe之后,接下来就可以定义Thrift的DSL,这个DSL可以让thrift-0.9.1.exe 生成各个语言版本的sdk。
1. 定义Thrift DSL
service ThriftService { string Upload(1: binary data), binary Download(1: string path), bool Remove(1: string path) }
有人可能会问,这个DSL怎么写,这个大家可以看看官方的DSL的各个关键词描述的网址:http://thrift.apache.org/docs/idl 还是比较简单的,如果不清楚的
话,这个是示例大全: https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=test/ThriftTest.thrift;hb=HEAD ,然后保存为1.thrift。
2. 通过thrift生成 C# SDK
生成的方式可以参考一下官网的模板:
thrift --gen <language> <Thrift filename>
C:\Users\hxc>cd C:\java\lib\thrift C:\java\lib\thrift>thrift-0.9.1.exe -gen csharp C:\java\lib\thrift\1.thrift
可以看到,执行完之后,就多了一个gen-csharp文件夹,点进去看一下,会发现有一个文件名为DSL中定义的ThriftService.cs文件。
3. 通过thrift生成 JAVA SDK
执行完下面这条语句,你会发现你的文件夹又多了一份gen-java 。
C:\java\lib\thrift>thrift-0.9.1.exe -gen java C:\java\lib\thrift\1.thrift
三:SDK集成
改造之后,我们使用JAVA作为服务端,C#作客户端,服务端要做的事情就是通过JAVA来封装FastDFS,然后让C#来调用。
1. JAVA服务端
《1》使用fastDFS 和 Thrift的Maven地址:
<!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift --> <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.9.1</version> </dependency> <!-- https://mvnrepository.com/artifact/net.oschina.zcx7878/fastdfs-client-java --> <dependency> <groupId>net.oschina.zcx7878</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27.0.0</version> </dependency>
《2》 ThriftServiceImpl.java 实现类:
1 package com.datamip.thrift; 2 3 import java.io.IOException; 4 import java.nio.ByteBuffer; 5 import java.util.Date; 6 7 import org.apache.log4j.Logger; 8 import org.apache.thrift.TException; 9 import org.csource.common.MyException; 10 import org.csource.fastdfs.StorageClient; 11 12 import com.fasterxml.jackson.databind.ObjectMapper; 13 14 /* 15 * thrift 服务端 16 */ 17 public class ThriftServiceImpl implements ThriftService.Iface { 18 19 public static Logger logger1 = Logger.getLogger(App.class); 20 21 StorageClient client = null; 22 23 ObjectMapper objectMapper=new ObjectMapper(); 24 25 public ThriftServiceImpl() throws IOException, MyException { 26 client = new FastService().Create(); 27 } 28 29 //上传文件 30 public String Upload(ByteBuffer data) { 31 32 byte[] bytes = data.array(); 33 34 logger1.info("已成功接受到upload请求: bytes.length="+bytes.length); 35 36 if(bytes==null || bytes.length==0) return ""; 37 38 // 目前给的 “后缀名为 g1",以后可以动态变更,通过‘阿波罗’动态配置 39 String[] result = null; 40 41 try { 42 result = client.upload_file(bytes, "g1", null); 43 44 logger1.info("update 上传结果为: "+objectMapper.writeValueAsString(result)); 45 46 if (result.length < 2) return ""; 47 48 }catch (Exception e) { 49 logger1.error("upload异常",e); 50 } 51 52 return result[1]; 53 } 54 55 // 文件下载 56 public ByteBuffer Download(String path) throws TException { 57 58 logger1.info("已成功接受到download请求:"+path); 59 60 if (path == null || path == "") 61 return ByteBuffer.allocate(0); 62 63 String[] arr = path.split("\\."); 64 65 if (arr.length < 2) 66 return ByteBuffer.allocate(0); 67 68 String group_name = arr[1]; 69 70 try { 71 byte[] bytes = client.download_file(group_name, path); 72 73 logger1.info(String.format("根据path=%s,获取的bytes长度为:%s",path,bytes.length)); 74 75 return ByteBuffer.wrap(bytes); 76 77 }catch (Exception e) { 78 logger1.error("download异常",e); 79 } 80 81 // TODO Auto-generated method stub 82 return ByteBuffer.allocate(0); 83 } 84 85 // 删除文件 86 public boolean Remove(String path) throws TException { 87 88 logger1.info("已成功接受到remove请求:"+path); 89 90 if (path == null || path == "") return false; 91 92 String[] arr = path.split("\\."); 93 94 if(arr==null || arr.length<2) return false; 95 96 String group_name = arr[1]; 97 98 try { 99 int code = client.delete_file(group_name, path); 100 101 logger1.info(String.format("当前path=%s, groupname=%s,返回状态值=%s", 102 path,group_name,code)); 103 104 if(code==0) { 105 return true; 106 } 107 108 }catch (Exception e) { 109 logger1.error("Remove异常",e); 110 } 111 112 return false; 113 } 114 }
《3》 FastDFS的封装类
1 package com.datamip.thrift; 2 3 import java.io.IOException; 4 5 import org.csource.common.MyException; 6 import org.csource.fastdfs.ClientGlobal; 7 import org.csource.fastdfs.StorageClient; 8 import org.csource.fastdfs.StorageServer; 9 import org.csource.fastdfs.TrackerClient; 10 import org.csource.fastdfs.TrackerServer; 11 12 import com.datamip.utils.PropertiesUtils; 13 14 public class FastService { 15 16 public StorageClient Create() throws IOException, MyException { 17 18 //读取配置文件 19 String path = PropertiesUtils.getProperties("setting.properties","fastdfs"); 20 return this.Create(path); 21 } 22 23 public StorageClient Create(String host) throws IOException, MyException { 24 25 ClientGlobal.initByTrackers(host); 26 27 // 3、创建一个TrackerClient对象。 28 TrackerClient trackerClient = new TrackerClient(); 29 30 // 4、创建一个TrackerServer对象。 31 TrackerServer trackerServer = trackerClient.getConnection(); 32 33 // 5、声明一个StorageServer对象,null。 34 StorageServer storageServer = null; 35 36 // 6、获得StorageClient对象。 37 StorageClient storageClient = new StorageClient(trackerServer, storageServer); 38 39 return storageClient; 40 } 41 }
《4》最后就是AppMain,Thrift开启19999端口。
1 package com.datamip.thrift; 2 3 import java.io.IOException; 4 5 import org.apache.log4j.Logger; 6 import org.apache.thrift.TProcessor; 7 import org.apache.thrift.protocol.TBinaryProtocol; 8 import org.apache.thrift.server.TServer; 9 import org.apache.thrift.server.TSimpleServer; 10 import org.apache.thrift.transport.TServerSocket; 11 import org.apache.thrift.transport.TTransportException; 12 import org.csource.common.MyException; 13 14 public class App { 15 16 public static Logger logger1 = Logger.getLogger(App.class); 17 18 public static void main(String[] args) throws IOException, MyException { 19 20 try { 21 TProcessor tprocessor = new ThriftService.Processor<ThriftService.Iface>(new ThriftServiceImpl()); 22 23 TServerSocket serverTransport = new TServerSocket(9999); 24 TServer.Args tArgs = new TServer.Args(serverTransport); 25 26 tArgs.processor(tprocessor); 27 tArgs.protocolFactory(new TBinaryProtocol.Factory()); 28 29 logger1.debug("thrift 服务端开启,开放端口 19999"); 30 31 TServer server = new TSimpleServer(tArgs); 32 server.serve(); 33 } catch (TTransportException e) { 34 e.printStackTrace(); 35 } 36 } 37 }
2. C#客户端
《1》 从negut上把dll拉下来,然后把生成的ThriftService.cs引入到我们的解决方案中
《2》 封装一个简单的CURD操作
1 public class ThriftSHelper 2 { 3 private static string fastdfs = ConfigurationManager.AppSettings["fastdfs"]; 4 5 TTransport transport = null; 6 TProtocol protocol = null; 7 ThriftService.Client client = null; 8 9 public ThriftSHelper() 10 { 11 var arr = fastdfs.Split(':'); 12 var host = arr[0]; 13 var port = Convert.ToInt32(arr[1]); 14 15 transport = new TSocket(host, port); 16 protocol = new TBinaryProtocol(transport); 17 client = new ThriftService.Client(protocol); 18 } 19 20 public static ThriftSHelper Create() 21 { 22 return new ThriftSHelper(); 23 } 24 25 public string UploadFile(BitArray bit) 26 { 27 string path = string.Empty; 28 29 try 30 { 31 var bytes = new byte[Convert.ToInt32(Math.Ceiling((double)bit.Length / 8))]; 32 33 transport.Open(); 34 35 bit.CopyTo(bytes, 0); 36 37 path = client.Upload(bytes); 38 } 39 catch (Exception ex) 40 { 41 LogHelper.Error(ex); 42 } 43 finally 44 { 45 transport.Close(); 46 } 47 48 return path; 49 } 50 51 /// <summary> 52 /// 下载文件 53 /// </summary> 54 /// <param name="fileName"></param> 55 /// <returns></returns> 56 public BitArray DownloadFile(string fileName) 57 { 58 BitArray bitArray = null; 59 60 try 61 { 62 transport.Open(); 63 64 var bytes = client.Download(fileName); 65 66 return new BitArray(bytes); 67 } 68 catch (Exception ex) 69 { 70 LogHelper.WriteLog(fileName, ex); 71 } 72 finally 73 { 74 transport.Close(); 75 } 76 77 return bitArray; 78 } 79 80 /// <summary> 81 /// 删除文件 82 /// </summary> 83 /// <param name="fileName"></param> 84 public void RemoveFile(string fileName) 85 { 86 try 87 { 88 transport.Open(); 89 90 client.Remove(fileName); 91 } 92 catch (Exception ex) 93 { 94 LogHelper.WriteLog(ex); 95 } 96 finally 97 { 98 transport.Close(); 99 } 100 } 101 }