`
bachmozart
  • 浏览: 111369 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

erlang轻松实现memcached binary协议

阅读更多
简单实现了下memcached binary protocol的 get和 set command,体验了下erlang binary语法的强大和方便
代码:

-module(binary_server).
-export([start/0]).

start() ->
	{ok,Listen}=gen_tcp:listen(7777,[binary,{packet,0},{reuseaddr,true},{active,true}]),
	register(kvs,spawn(fun() -> dict() end)),
	accept(Listen).

accept(Listen) ->
	{ok,Socket}=gen_tcp:accept(Listen),
	spawn(fun() -> accept(Listen) end),
	inet:setopts(Socket,[binary,{packet,0},{active,true}]),
	process(Socket,<<>>).

process(Socket,Left) ->
	receive
		{tcp,Socket,Bin} ->
			Buffer=list_to_binary(binary_to_list(Left) ++ binary_to_list(Bin)),
			case regonized(Buffer) of
				{save_ok,RealRemaning} ->
					Resp=[16#81,16#1] ++ fill_all(0,22,[]),
					gen_tcp:send(Socket,list_to_binary(Resp)),
					process(Socket,RealRemaning);

				{get_ok,undefined,Remaining} ->
					Value= <<"not_found">>,
					BodyLen=length(binary_to_list(Value))+4,
					Resp=[16#81] ++ fill_all(0,3,[]) ++[16#4] 
                                        ++ fill_all(0,3,[]) ++ 
					binary_to_list(<<BodyLen:32>>) ++ 
                                        binary_to_list(<<0:128>>) ++ 
                                        binary_to_list(Value),
					gen_tcp:send(Socket,list_to_binary(Resp)),
					process(Socket,Remaining);

				{get_ok,{ok,Value},Remaining} ->
					BodyLen=length(binary_to_list(Value))+4,
					Resp=[16#81] ++ fill_all(0,3,[]) ++[16#4]
                                         ++ fill_all(0,3,[]) ++ 
					binary_to_list(<<BodyLen:32>>) ++ 
                                        binary_to_list(<<0:128>>) ++ 
                                        binary_to_list(Value),
					gen_tcp:send(Socket,list_to_binary(Resp)),
					process(Socket,Remaining);

				{get_timeout,Remaining} ->
					process(Socket,Remaining);

				{not_engouh_streams} ->
					process(Socket,Buffer)
			end;
		{tcp_closed,Socket} ->
			io:format("peer closed~n")
 	end.

regonized(Buffer) ->
	case Buffer of
		%%set command
		<<16#80:8,16#1:8,KeyLen:16/big,
                ExtraLen:8/big,DataType:8,Reserved:16/big,
		BodyLen:32/big,Opaque:32/big,Cas:64/big,
                Extras:64/big,Key:KeyLen/big-binary-unit:8,
                Remaning/binary>> ->
			ValueLen=BodyLen-KeyLen-ExtraLen,
			case Remaning of
				<<Value:ValueLen/binary-unit:8,
                                 RealRemaning/binary>> ->
					%% got completed packet,deal with set command
				 	kvs ! {self(),{store,Key,Value}},	
					{save_ok,RealRemaning};
				<<_/binary>> ->
					%% not enough streams
					{not_enough_streams}
			end;
		%%get command
		<<16#80:8,16#0:8,KeyLen:16/big,16#0:8,
                DataType:8,Reserved:16/big,BodyLen:32/big,
                Opaque:32/big,Cas:64/big,Key:KeyLen/big-binary-unit:8,
                Remaining/binary>> ->
			kvs ! {self(),{lookup,Key}},
			receive 
				{lookup,Value} ->
					{get_ok,Value,Remaining}
		    after 1000 ->
			    {get_timeout,Remaining}		
		    end;
		%% no match
		<<_/binary>> ->
			{not_engouh_streams}
	end.

dict() ->
	receive
		{From,{store,Key,Value}} ->
			put(Key,{ok,Value}),
			dict();
		{From,{lookup,Key}} ->
			From ! {lookup,get(Key)},
			dict()
	end.
debug_print([H|T]) ->
        io:format("~w,",[H]),
        debug_print(T);
debug_print([])->
        ok.

fill_all(C,0,L)->
        L;
fill_all(C,N,L)->
        N1=N-1,
        L1=[C|L],
        fill_all(C,N1,L1).



说明:
1. 16#80:8  
   16#代表16进制,80是memcached协议头的第一个字节 80代表request
   具体协议内容memcached官网上有很详尽的解释
2. KeyLen:16/big 
   协议中key的长度是占2个字节 ,16是bit数 .
   因为多于一个字节的数据在存储和传输时就会涉及字节序问题,
   这里big代表的是大端/网络字节序,
   因为我的测试client在传输数据前已经将数据转成网络字节序,所以这里接收必须是big
3. Key:KeyLen/big-binary-unit:8 ,
   这里Key具体的字节数是由之前得到的KeyLen指定的,所以表示为Key:KeyLen,
   因为这里的单位应该是字节,所以需要指定为unit:8,其实这里指定了binary
   binary类型默认的unit就是8,即 实际的size = KeyLen * unit 个 bit
4. lookup没有找到指定key对应value时,这里没有按协议处理,以not_found为value返回给client,实际协议是返回一个status为非0的协议包





分享到:
评论
22 楼 javaeyebird 2009-06-17  
bachmozart 写道
{not_engouh_streams} ->

engouh
21 楼 bachmozart 2009-06-16  
fxsjy 写道
bachmozart 写道
美洲豹 写道
前段时间也要用Erlang和memcached通信,在网上找了个,写的好复杂,
就放弃了,改成和PHP socket server通信 来解决

你这段代码也没有说明如何散列访问,我们那些memcache都是散列在多台的


我就是想试试binary的语法而已,整好拿memcached protocol做个试验而已

这个程序离一个真正的memcached client可差远了,估计有很多地方都是 Don't do this的典范,呵呵



我看你的代码,怎么觉得是实现server呢?


你说的没错,是server, 笔误,sorry
20 楼 fxsjy 2009-06-15  
bachmozart 写道
美洲豹 写道
前段时间也要用Erlang和memcached通信,在网上找了个,写的好复杂,
就放弃了,改成和PHP socket server通信 来解决

你这段代码也没有说明如何散列访问,我们那些memcache都是散列在多台的


我就是想试试binary的语法而已,整好拿memcached protocol做个试验而已

这个程序离一个真正的memcached client可差远了,估计有很多地方都是 Don't do this的典范,呵呵



我看你的代码,怎么觉得是实现server呢?
19 楼 bachmozart 2009-06-15  
大众化的语言已经有很多了,java,python不就是吗

不同的东西定位不同吧

就像java做得足够好的地方是,跨平台,自动内存管理等

但是很多时候通用意味着永远达不到最佳

我的平台就是linux,我就是要用最快的epoll,并且我需要自定义的高效数据结构和最佳的内存管理策略,那么通用的java能达到么

erlang可能在很多场合都不适合,但是在某些场合,确实没有比它更方便的了
18 楼 dogstar 2009-06-15  
我也认为代码写的精妙了,确实不容易看懂.但是我认为这个不是问题.joe也没期待erlang能够成为一种大众化的语言.我想符合大众的语言,我相信是会有的,不急的话,就等吧.
17 楼 Joo 2009-06-14  
dogstar 写道
bachmozart 写道
test_destack() ->
    {<<"a">>, [], []} =
        destack([{<<"a">>, [], []}]),
    {<<"a">>, [], [{<<"b">>, [], []}]} =
        destack([{<<"b">>, [], []}, {<<"a">>, [], []}]),
    {<<"a">>, [], [{<<"b">>, [], [{<<"c">>, [], []}]}]} =
     destack([{<<"c">>, [], []}, {<<"b">>, [], []}, {<<"a">>, [], []}]),
    [{<<"a">>, [], [{<<"b">>, [], [{<<"c">>, [], []}]}]}] =
     destack(<<"b">>,
             [{<<"c">>, [], []}, {<<"b">>, [], []}, {<<"a">>, [], []}]),
    [{<<"b">>, [], [{<<"c">>, [], []}]}, {<<"a">>, [], []}] =
     destack(<<"c">>,
             [{<<"c">>, [], []}, {<<"b">>, [], []},{<<"a">>, [], []}]),
    ok.

类似这样的函数是比较头大

不过相比较相同功能和近似同等性能的一个网络服务器端程序

C要近上万行,而erlang只要几百行,你选哪个,况且象上面的写法也不多见,大部分还是挺清晰的

就算是dirty and quickly 的方式也还不错呀


看不懂说明功力还不够深.那你最精通的来说,你是一上来就能够使用的游刃有余的么?要得到好处,就得付出代价.

我觉得fp中最核心的,或者说最饶人的就是高阶函数传递来,传递去的.容易搞晕.其他还好吧.


不要混淆概念,看不看的懂跟容不容易看懂是两码事。又或者说,fp写出来是不需要被经常维护的,或者被除了开发者的其他人维护的,或者被跟开发者水平差太多的入门人员维护的?
16 楼 google_fans 2009-06-14  
pipilu 写道
andrew913 写道
我们组的项目核心是用erlang做的,可惜我不会,有空一定要去学学。


用于实现什么功能?

web 服务器监控。


15 楼 dogstar 2009-06-14  
bachmozart 写道
test_destack() ->
    {<<"a">>, [], []} =
        destack([{<<"a">>, [], []}]),
    {<<"a">>, [], [{<<"b">>, [], []}]} =
        destack([{<<"b">>, [], []}, {<<"a">>, [], []}]),
    {<<"a">>, [], [{<<"b">>, [], [{<<"c">>, [], []}]}]} =
     destack([{<<"c">>, [], []}, {<<"b">>, [], []}, {<<"a">>, [], []}]),
    [{<<"a">>, [], [{<<"b">>, [], [{<<"c">>, [], []}]}]}] =
     destack(<<"b">>,
             [{<<"c">>, [], []}, {<<"b">>, [], []}, {<<"a">>, [], []}]),
    [{<<"b">>, [], [{<<"c">>, [], []}]}, {<<"a">>, [], []}] =
     destack(<<"c">>,
             [{<<"c">>, [], []}, {<<"b">>, [], []},{<<"a">>, [], []}]),
    ok.

类似这样的函数是比较头大

不过相比较相同功能和近似同等性能的一个网络服务器端程序

C要近上万行,而erlang只要几百行,你选哪个,况且象上面的写法也不多见,大部分还是挺清晰的

就算是dirty and quickly 的方式也还不错呀


看不懂说明功力还不够深.那你最精通的来说,你是一上来就能够使用的游刃有余的么?要得到好处,就得付出代价.

我觉得fp中最核心的,或者说最饶人的就是高阶函数传递来,传递去的.容易搞晕.其他还好吧.
14 楼 rrsy23 2009-06-13  
现在的 软件世界 不是 艺术 是 服务!

服务简单化 实用化 才是 王道!

erlang语法太艺术了!

语言 是为程序员 服务的!

希望能简化!

个人觉得java这样的语言+groovy这样的结合也许是 商业软件走向

其他 语言 自有 自己的 特殊 领域!
13 楼 bachmozart 2009-06-11  
没人说erlang的执行效率会高过c, 开发效率和天生的分布应该才是优势
12 楼 Joo 2009-06-10  
楼上所说的大部分还是挺清晰的不知道指的是哪部分? 别说我还是看过erlang基本语法的人,即便是erlang熟手拿到这个也是头大吧.计算机在执行代码时,是不管代码到底是几万行还是几百行的,而是看运行时具体的执行代码以及代码的执行效率,从这个方面来说,有没有数据支持Erlang能优胜c?
11 楼 bachmozart 2009-06-09  
test_destack() ->
    {<<"a">>, [], []} =
        destack([{<<"a">>, [], []}]),
    {<<"a">>, [], [{<<"b">>, [], []}]} =
        destack([{<<"b">>, [], []}, {<<"a">>, [], []}]),
    {<<"a">>, [], [{<<"b">>, [], [{<<"c">>, [], []}]}]} =
     destack([{<<"c">>, [], []}, {<<"b">>, [], []}, {<<"a">>, [], []}]),
    [{<<"a">>, [], [{<<"b">>, [], [{<<"c">>, [], []}]}]}] =
     destack(<<"b">>,
             [{<<"c">>, [], []}, {<<"b">>, [], []}, {<<"a">>, [], []}]),
    [{<<"b">>, [], [{<<"c">>, [], []}]}, {<<"a">>, [], []}] =
     destack(<<"c">>,
             [{<<"c">>, [], []}, {<<"b">>, [], []},{<<"a">>, [], []}]),
    ok.

类似这样的函数是比较头大

不过相比较相同功能和近似同等性能的一个网络服务器端程序

C要近上万行,而erlang只要几百行,你选哪个,况且象上面的写法也不多见,大部分还是挺清晰的

就算是dirty and quickly 的方式也还不错呀
10 楼 Joo 2009-06-08  
一直有一个疑问就是,erlang难道不要求代码的可读性吗,类似的命令式语言语法都比较奇怪(可能这个是从一个过程式语言编程者的角度来看的,但是不可否认它更接近于人类语言,更接近伪码的表达方式)。那么在后期对erlang代码进行维护、重构和一系列优化时,不能说这样奇怪的写法是一个灾难
9 楼 whaosoft 2009-06-06  
willko 写道
大牛啊,,,

erlang的语法好怪,,以后一定要学学```

以后我也学学 ~!~
8 楼 pipilu 2009-06-06  
andrew913 写道
我们组的项目核心是用erlang做的,可惜我不会,有空一定要去学学。


用于实现什么功能?
7 楼 bachmozart 2009-06-05  
美洲豹 写道
前段时间也要用Erlang和memcached通信,在网上找了个,写的好复杂,
就放弃了,改成和PHP socket server通信 来解决

你这段代码也没有说明如何散列访问,我们那些memcache都是散列在多台的


我就是想试试binary的语法而已,整好拿memcached protocol做个试验而已

这个程序离一个真正的memcached client可差远了,估计有很多地方都是 Don't do this的典范,呵呵
6 楼 bachmozart 2009-06-05  
mryufeng 写道
binary确实很强大 还有bianry list comprehension 不要忘记了哦


好的,回头好好研究下
5 楼 美洲豹 2009-06-05  
前段时间也要用Erlang和memcached通信,在网上找了个,写的好复杂,
就放弃了,改成和PHP socket server通信 来解决

你这段代码也没有说明如何散列访问,我们那些memcache都是散列在多台的
4 楼 mryufeng 2009-06-05  
binary确实很强大 还有bianry list comprehension 不要忘记了哦
3 楼 andrew913 2009-06-04  
我们组的项目核心是用erlang做的,可惜我不会,有空一定要去学学。

相关推荐

    erlang语言实现binary_to_term完整代码

    erlang提供了binary_to_term 函数...这个函数都是c实现的,这里用erlang语言实现了,很有参考价值,其他语言可以参考这个解析erlang二进制协议数据。配套文章地址http://blog.csdn.net/mycwq/article/details/42460033

    Erlang emulator 实现分析

    Erlang emulator 实现分析Erlang emulator 实现分析

    erlang ranch实现的游戏tcp服务器

    Erlang Ranch是一个轻量级、高性能的网络协议栈,专为构建TCP服务器而设计。在游戏开发领域,由于其并发处理能力和强大的故障恢复机制,Erlang常被用来构建可扩展、高可用性的游戏服务器。Ranch库提供了一种简单的...

    介绍 Erlang binary 和 bit string 数据类型的经典文章

    ### Erlang Binary与Bit String 数据类型详解 #### 引言 Erlang 是一种功能强大且灵活的编程语言,尤其适合开发高并发、分布式及容错性应用。自 R12B 版本以来,Erlang 在处理二进制数据方面引入了两项重大更新:...

    Erlang OTP 20.1 Windows 64-bit Binary File

    Erlang OTP 20.1 Windows 64-bit Binary File 下载地址:http://www.erlang.org/downloads

    erlmc:Erlang Memcached二进制协议客户端

    Erlang二进制协议Memcached客户端 外部文件 二进制协议规范 快速开始 您必须具有1.3或更高版本的memcached $&gt; make $&gt; make test $&gt; sudo make install $&gt; memcached -d 1&gt; erlmc:start(). ok 2&gt; erlmc:stats(). ...

    for_each_file 用erlang代码实现遍历文件

    下面我们将深入探讨如何使用Erlang实现这个功能,以及涉及的相关知识点。 首先,让我们看看`for_each_file.erl`可能的实现。在这个模块中,我们可能会定义一个名为`for_each_file/2`的函数,它接受两个参数:一个是...

    megaco_session-0.5.rar_erlang_erlang Megaco_megaco

    这个项目是关于Megaco协议的实现,而“Erlang”是用于开发这个实现的编程语言。Erlang是一种功能强大的并行、分布式和容错的编程语言,特别适合于构建高可用性和实时性系统,如电信领域中的应用。 “erlang_erlang_...

    <27>erlang record

    标题中的“&lt;27&gt;erlang record”可能指的是Erlang编程语言中的Record特性,它是一种数据结构,类似于结构体或者哈希表,用于组织和操作数据。在Erlang中,Record提供了一种方便的方式来定义和访问具有固定字段的数据...

    KMP(Erlang)代码实现

    在给定的文件内容中,通过Erlang语言实现了KMP算法,以下是从文件内容中提取的关键知识点: 1. kmp_search/2函数:这是KMP算法的主函数,用于检查子串(SubString)是否存在于主串(String)中。该函数调用了kmp_...

    erlang的timer和实现机制

    此外,提供的"erlang的timer和实现机制.pdf"和"更多erlang资料下载.txt"也是进一步学习和研究的好资源。 总之,Erlang的timer模块是其强大并发能力的一个体现,通过熟练掌握这一部分,开发者可以构建出更加高效和...

    erlang编程 Introducing Erlang

    Erlang的并发模型和 otp 设计模式使得系统能够轻松实现负载均衡和故障切换。当一个节点或进程失败时,系统可以重新分配工作,确保服务的连续性。 ### 9. BEAM虚拟机 BEAM是Erlang运行时系统的名称,全称为伯尔尼...

    erlang_win64.rar

    掌握这些基础知识后,你可以进一步学习如何在Erlang中编写RabbitMQ客户端,实现消息的发布和订阅,以及如何利用RabbitMQ实现可靠的数据传输和系统解耦。同时,了解Erlang的错误处理机制和调试工具,如observer和...

    一种傻纸牌游戏的Erlang实现

    标题 "一种傻纸牌游戏的Erlang实现" 暗示了我们将探讨一个使用Erlang编程语言构建的简单纸牌游戏。Erlang是一种并发性极强、功能丰富的函数式编程语言,常用于构建分布式系统和高可用性的应用程序。 在描述中提到的...

    Erlang实现遗传算法.docx

    ### Erlang 实现遗传算法详解 #### 一、引言 遗传算法(Genetic Algorithm, GA)是一种模拟自然界中生物进化过程的优化搜索方法。它借鉴了自然选择、遗传、变异等生物进化的机制,通过迭代的方式寻找问题的最优解...

    erlang最新api

    本文将深入探讨Erlang中的I/O协议,特别是它在STDLIB 1.17.4版本中的实现细节。 #### 标准库STDLIB简介 STDLIB是Erlang的一个核心模块,包含了各种通用的函数库,如列表操作、字符串处理、文件系统交互等。它为...

    Erlang开发环境搭建

    Erlang OTP是Erlang的官方实现,提供了完整的开发环境。 readers可以从Erlang官方网站下载最新的Windows binary版本。安装Erlang OTP非常简单,只需要按照安装程序的提示进行操作。 二、安装Emacs W32 Emacs W32是...

    ErlangB和ErlangC计算工具(exe可执行文件+excel两个)

    Erlang B和Erlang C是电信领域中两种重要的流量模型,用于预测和分析通信系统中的呼叫处理能力和拥塞情况。这两个模型由丹麦工程师Agner Krarup Erlang在20世纪初提出,至今仍广泛应用于现代通信网络的设计与优化。 ...

Global site tag (gtag.js) - Google Analytics