2010-11-17 16 views
5

मैं this ट्यूटोरियल से socket_server उपयोग कर रहा हूँ और एक क्लाइंट और सर्वर के लिए निम्न कोड:gen_tcp smushed संदेशों

सर्वर:

-module(echo_server). 
-export([start/0, loop/1]). 

% echo_server specific code 
start() -> 
    spawn(socket_server, start, [?MODULE, 7000, {?MODULE, loop}]). 

loop(Socket) -> 
    case gen_tcp:recv(Socket, 0) of 
     {ok, Message} -> 
      Msg = binary_to_term(Message), 
      case Msg of 
       start -> 
        io:format("Got start message on socket ~p.~n", [Socket]), 
        send_count(Socket, 10), 
        gen_tcp:close(Socket); 
       Other -> 
        io:format("Got message on socket ~p: ~p~n", 
           [Socket, Other]) 
      end; 
     {error, closed} -> 
      io:format("Got closed message on socket ~p.~n", [Socket]), 
      ok; 
     Error -> 
      io:format("Got bad message: ~p on socket ~p.~n", [Error, Socket]) 
    end. 

send_count(_Socket, 0) -> 
    ok; 
send_count(Socket, Num) -> 
    io:format("Sending ~p to ~p.~n", [Num, Socket]), 
    gen_tcp:send(Socket, term_to_binary(Num)), 
    send_count(Socket, Num - 1). 

ग्राहक:

-module(echo_client). 
-export([start/0, do_stuff/0]). 


send(Socket, Msg) -> 
    gen_tcp:send(Socket, term_to_binary(Msg)). 

start() -> 
    dbg:tracer(), 
    Pid = spawn(?MODULE, do_stuff, []), 
    dbg:p(Pid, r). 

do_stuff() -> 
    case gen_tcp:connect("localhost", 7000, [binary, {packet, 0}]) of 
     {ok, Socket} -> 
      send(Socket, start), 
      rx_loop(Socket); 
     Error -> 
      io:format("Error connecting to server: ~p~n", [Error]) 
    end. 

rx_loop(Socket) -> 
    receive 
     {tcp, Socket, Message} -> 
      Msg = binary_to_term(Message), 
      io:format("Received message: ~p~n", [Msg]), 
      rx_loop(Socket) 
    after 5000 -> 
      finish_loop(Socket) 
    end. 

finish_loop(Socket) -> 
    receive 
     {tcp, Socket, Message} -> 
      Msg = binary_to_term(Message), 
      io:format("Received message: ~p~n", [Msg]), 
      rx_loop(Socket); 
     {tcp_closed, Socket} -> 
      io:format("Server terminated connection.~n"), 
      exit(normal); 
     Error -> 
      io:format("Received bad message: ~p~n", [Error]), 
      rx_loop(Socket) 
    end. 

मैं echo_server:start() और echo_client:start() से डायल कर रहा हूं उसी क्रम में, उसी क्रम पर तरंग गोले। यहां मैं देखता हूं:

सर्वर ठीक काम करता प्रतीत होता है।

1>echo_server:start(). 
<0.39.0> 
Got start message on socket #Port<0.2041>. 
Sending 10 to #Port<0.2041>. 
Sending 9 to #Port<0.2041>. 
Sending 8 to #Port<0.2041>. 
Sending 7 to #Port<0.2041>. 
Sending 6 to #Port<0.2041>. 
Sending 5 to #Port<0.2041>. 
Sending 4 to #Port<0.2041>. 
Sending 3 to #Port<0.2041>. 
Sending 2 to #Port<0.2041>. 
Sending 1 to #Port<0.2041>. 

ग्राहक काफी सभी संदेशों को सही नहीं मिलता है:

2> echo_client:start(). 
{ok,[{matched,[email protected],1}]} 
3> (<0.41.0>) << {code_server,{module,gen_tcp}} 
(<0.41.0>) << {code_server,{module,inet_tcp}} 
(<0.41.0>) << {#Ref<0.0.0.74>,{ok,<0.43.0>}} 
(<0.41.0>) << {#Ref<0.0.0.76>, 
       {ok,<<4,0,0,0,2,127,0,0,1,127,0,0,1,0,0,0,3,108,111,99,97,108, 
        104,111,115,116,0,105,112,54,45,108,111,99,97,108,104, 
        111,115,116,0,105,112,54,45,108,111,111,112,98,97,99, 
        107,0>>}} 
(<0.41.0>) << {inet_async,#Port<0.2058>,0,ok} 
(<0.41.0>) << {inet_reply,#Port<0.2058>,ok} 
Received message: 10 
3> (<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,10>>} 
Received message: 9 
3> (<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << timeout 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,9>>} 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
Received message: 8 
Received message: 5 
Received message: 4 
Received message: 3 
Received message: 2 
Received message: 1 
3> (<0.41.0>) << timeout 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,8,131,97,7,131,97,6>>} %% <---This guy here 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,5>>} 
(<0.41.0>) << timeout 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << timeout 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,4>>} 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << timeout 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,3>>} 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << timeout 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,2>>} 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << timeout 
(<0.41.0>) << {tcp,#Port<0.2058>,<<131,97,1>>} 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << {tcp_closed,#Port<0.2058>} 
(<0.41.0>) << timeout 
Server terminated connection. 
3> (<0.41.0>) << timeout 
(<0.41.0>) << {io_reply,<0.25.0>,ok} 
(<0.41.0>) << timeout 

अगर मैं lo पर नेटवर्क यातायात को देखो, मैं प्रत्येक संख्या नीचे गिनती के लिए अच्छा स्वच्छ PSH/एसीके जोड़े देखते हैं। जिस पंक्ति पर मैंने ऊपर बताया है, वह एक संदेश में दिखाए गए दो पैकेट दिखाता है: 7 और 6. वे नेटवर्क में दो अलग-अलग टीसीपी पैकेट के रूप में आए। किसी को भी कोई विचार है कि उन्हें एक साथ क्यों धुआं जा रहा है या उन्हें कैसे मिटाया जा सकता है?

+0

@closers: यह प्रश्न 2010 से है। यह कल से एक प्रश्न का डुप्लिकेट कैसे है? – nmichaels

+0

अन्य प्रश्न को कैननिकल डुप्लिकेट के रूप में चुना गया था। – bjb568

उत्तर

7

क्यों वे प्राप्त अंत में "smushed" किया जा रहा हो: क्योंकि टीसीपी एक स्ट्रीमिंग प्रोटोकॉल, है और वहाँ भेजने के लिए कोई आवश्यकता नहीं है/recv नेटवर्क पैकेट (भले ही वे आने के साथ 1-1 पत्राचार के लिए कॉल तार पर उस तरह से)।

कैसे करें "गैर-Smush" उन्हें: या तो अपने TCP प्रोटोकॉल को बदलने संदेश सीमांकक शामिल करने के लिए, तो आप को पता है जहां पैकेट सीमाओं थे की जरूरत के बिना धारा से संदेशों निकाल सकते हैं; या टीसीपी के बजाय यूडीपी का उपयोग करें।

+0

वाह, यह नया है। मैं यूडीपी का उपयोग नहीं करना चाहूंगा, तब से मुझे टीसीपी की सभी अच्छी चीजें करना होगा (जैसे ऑर्डर डिलीवरी की गारंटी।) क्या आप टीसीपी में संदेश डिलीमीटर कैसे प्राप्त कर सकते हैं इसके बारे में अधिक विशिष्ट हो सकते हैं? क्या gen_tcp में कुछ बनाया गया है जिसका मैं उपयोग कर सकता हूं, या मुझे अपना खुद का रोल करना है? – nmichaels

+0

@ नाथन: मुझे एरलांग नहीं पता, इसलिए मैं gen_tcp की क्षमताओं से बात नहीं कर सकता। आप निश्चित रूप से टीसीपी परत से पढ़ रहे संदेशों के लिए कुछ प्रकार के बफर का प्रबंधन करना होगा, फिर एक पूरा संदेश उपलब्ध होने पर पता लगाने का एक तरीका होगा। यदि आपके संदेश सभी एक ही लंबाई हैं, तो आप लगभग पूरा कर चुके हैं! संदेश के दसवें क्षेत्र के रूप में संदेश के पहले कुछ बाइट आरक्षित करना भी आम बात है। या यदि यह भेजने के पक्ष में सुविधाजनक नहीं है, तो आप बाइट्स के अनुक्रम को परिभाषित कर सकते हैं जो आपकी डेटा स्ट्रीम में दिखाई नहीं देगी, फिर पूरा अनुक्रम तैयार होने पर यह अनुक्रम देखने के लिए देखें। –

+4

अहह! {पैकेट, एन} विकल्प पैकेट के पहले एन बाइट्स को लंबाई क्षेत्र के रूप में उपयोग करता है। उस क्षेत्र के लिए विकल्पों की एक लंबी सूची http://www.erlang.org/doc/man/inet.html#setopts-2 – nmichaels

संबंधित मुद्दे