erlang的简单模拟半包的产生

 gen_tcp:linsten()/2使用的是{packet,2/4/8},则gen_tcp模块在接受或者发送时自动除去包头或者自动加上包头。

本例中使用的是{packet,0}。

-module(mod_tcp_server_listener)%%监听端口,收到新的socket就启动 mod_client_reader进程

%%监听端口,收到新的socket就启动 mod_client_reader进程

-module(mod_tcp_server_listener).

-include("common.hrl").

%% ====================================================================

%% API functions

%% ====================================================================

-export([start/1,stop_listen/1]).







%% ====================================================================

%% Internal functions

%% ====================================================================



start(Port)->

	io:format("hello tcp_server~n"),

	spawn(fun()-> start_listen(Port) end).



start_listen(Port)->

	{ok,LSocket}=	gen_tcp:listen(Port, [binary,{active,true},{packet,4}]),

	socket_accept(LSocket),

	{ok,LSocket}.



socket_accept(LSocket)->

	

	{ok,Socket}=gen_tcp:accept(LSocket),



	Pid=mod_client_reader:start(Socket),

	ok = gen_tcp:controlling_process(Socket, Pid),	

	socket_accept(LSocket).



%%tcp_accept(Socket)->

%%	io:format("hello one accept~n"),

%%	receive 

%%			{tcp,Socket,Bin}

%%			  	->

			%%	<<Length:32/integer,OneFloat:32/float,OneInt:1/big-unsigned-integer-unit:32,StrLength:2/big-unsigned-integer-unit:8,Left:9/binary>> = Bin,

			%%		io:format("receive data length: ~w,float:~w,int:~w,str size:~w~n",[Length,OneFloat,OneInt,StrLength]),

				%%	io:format("receive data: ~w~n",[byte_size(Bin)]),

			%%		io:format("receive data: ~ts~n",[Left]),

%%					NewData= <<Bin/binary,Bin/binary>>,

	%%				gen_tcp:send(Socket, NewData)

		%%			end,

			%%{tcp,Socket,?FL_POLICY_REQ}

%%	tcp_accept(Socket).



stop_listen(LSocket)->

	gen_tcp:close(LSocket).

 

 

module(mod_client_reader):%收到新的socket链接即启动一个该进程

%%收到新的socket链接即启动一个该进程

%%该进程负责玩家打开socket后正式进入游戏前的操作,负责登录验证等

%%该进程代表这客户端的socket,并将客户端到发送来的转给user进程

-module(mod_client_reader).



%% ====================================================================

%% API functions

%% ====================================================================

-export([start/1,start_io/0]).



%% 记录客户端进程

-record(client, {

			  	player_pid = undefined,%玩家的player的进程

				player_id = 0, %玩家的id

			   	login  = 0,

			   	accid  = 0,

			   	accname = undefined,

			   	timeout = 0,				% 超时次数

				sn = 0,						% 服务器号

				socketN = 0

				}

	   ).



%% ====================================================================

%% Internal functions

%% ====================================================================



start(Socket)->

	io:format("client start:~n",[]), 

	spawn(fun()-> start_accept(Socket) end ).



start_accept(Socket)->

	receive

			{tcp,Socket,<<Packet_Length:32,Cmd:32,Str_Length:32,Bin:Str_Length/binary>>}->

				 

			%%	io:format(" Data:~w,Bin:~w~n",[byte_size(Data),byte_size(Bin)] ), 

				

				 io:format("receive length:~w,cmd:~w,str_length:~w~n",[Packet_Length,Cmd,Str_Length] ),

				 io:format("Bin:~ts~n",[Bin]),

				io:format("============one==========================~n",[])		;

			{tcp,Socket,<<Packet_Length:32,Cmd:32,Str_Length:32,Bin:10/binary,Bin2/binary>>}->

				 

			%%	io:format(" Data:~w,Bin:~w~n",[byte_size(Data),byte_size(Bin)] ), 

				

				 io:format("receive length:~w,cmd:~w,str_length:~w,bin2_length:~w~n",[Packet_Length,Cmd,Str_Length,byte_size(Bin2)] ),

				 io:format("Bin:~ts~n",[Bin]),

				 io:format("Bin2:~ts~n",[Bin2]),

				io:format("============two==========================~n",[])		

		end,

	

	start_accept(Socket).





%%接收来自客户端的数据 - 登陆后进入游戏逻辑

%%Socket:socket id

%%Client: client记录

do_parse_packet(Socket, Client) ->

	.





start_io()->

	io:format("client start:~n",[]).

 

 

以下是java代码:

package tcp;



/**

 * @author [email protected]

 *

 */

public class Door {



	/**

	 * @param args

	 */

	public static void main(String[] args) 

	{

		// TODO Auto-generated method stub



		Tcp_Client tcp_client=new Tcp_Client(0);

		tcp_client.start();

		

		

	}



}





----------------------------------------------------------------------





package tcp;





import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;



import java.net.Socket;

import java.net.UnknownHostException;





/**

 * @author [email protected]

 *

 */

public class Tcp_Client extends Thread

{

	private int id;

	private int port=5000;

	

	public Tcp_Client(int new_id)

	{

		this.id=new_id;

	}



	

	public  void run() 

	{

		// TODO Auto-generated method stub

		

		Socket socket=null;

		try 

		{

			socket=new Socket("192.168.1.113",port);

			System.out.println("连接成功-----");

		}

		catch (UnknownHostException e) 

		{

			System.out.println("UnknownHostException:"+e.getLocalizedMessage());

		}

		catch (IOException e) 

		{

			System.out.println("IOException:"+e.getLocalizedMessage());

		}

		

		InputStream input=null;

		

		OutputStream output=null;

	

		

		Packet packet=new Packet();

		packet.writeInt(100);

		packet.writeString("你好啊1");		

		byte[] out_bytes=packet.send();;

		

		

		Packet packet1=new Packet();

		packet1.writeInt(101);

		packet1.writeString("你好啊2");		

		byte[] out_bytes1=packet1.send(9);//此值不是固定的值,与位置①的长度一致

		

		

		Packet packet2=new Packet();

		packet2.writeInt(102);

		packet2.writeString("你好啊3");		

		byte[] out_bytes2=packet2.send();;

		

		

		

		byte[] in_bytes=new byte[100];

		

		try 

		{

			 input=socket.getInputStream();

			

			 

			 output=socket.getOutputStream();

			

		} catch (IOException e) {

			// TODO Auto-generated catch block

			e.printStackTrace();

		}



		try 

		{

		

			output.write(out_bytes);

			output.flush();

			

			output.write(out_bytes1);

			output.flush();

			output.write("你好吗".getBytes("UTF-8"));//位置①

			output.flush();

			

			output.write(out_bytes2);

			output.flush();

			

			System.out.println("发送成功--");

			

			

		} catch (IOException e1) 

		{

			// TODO Auto-generated catch block

			e1.printStackTrace();

			}

		

		

		try 

		{

			

		int read_length=	input.read(in_bytes);

			

			System.out.println(new String(in_bytes,0,read_length,"utf8"));

		} catch (IOException e) {

			// TODO Auto-generated catch block

			e.printStackTrace();

		}

	}



}









----------------------------------------------------------------------





package tcp;



import java.io.UnsupportedEncodingException;

import java.nio.ByteBuffer;





/**

 * @author [email protected]

 *

 */

public class Packet 

{



    private ByteBuffer buff;

    private int length;

    

    public Packet() 

	{

        this(1024);

    }



    public Packet(int size) 

	{

        length = size;

        buff = ByteBuffer.allocate(length);

    }



    public Packet(ByteBuffer buffer) 

	{

        buff = buffer;

        length = buffer.limit();

    }



    public static Packet wrap(ByteBuffer buffer) 

	{

        return new Packet(buffer);

    }



   //写入数据

    public void writeChar(char value) 

	{

        buff.putChar(value);

    }



    public void writeByte(byte value) 

	{

        buff.put(value);

    }



    public void writeFloat(float value) 

	{

        buff.putFloat(value);

    }



    public void writeLong(long value) 

	{

        buff.putLong(value);

    }



    public void writeDouble(double value) 

	{

        buff.putDouble(value);

    }



    public void writeInt(int value) 

	{

        buff.putInt(value);

    }



    public void writeShort(short value) 

	{

        buff.putShort(value);

    }



    public void writeBytes(byte[] bytes) 

	{

        buff.put(bytes);

    }



    /**

     * 

     * @param str

     * 采用UTF-8的编码方式和client端保持一致,utf-8汉字占3位

     */

    public void writeString(String str) 

	{

      

		try 

		{

			  byte[] str_bytes= str.getBytes("UTF-8");

			  int len = str_bytes.length;

		        writeInt(len);

		        writeBytes(str_bytes);

		}

		catch (UnsupportedEncodingException e) 

		{

			System.out.println("writeString出现异常");

            System.exit(0);

		}

        

    }



    public void writeString(String str, String charset) 

	{

        

        try

		{

            byte[] str_bytes = str.getBytes(charset);

            short len = (short) (str_bytes.length);

            writeShort(len);

            writeBytes(str_bytes);

        }

		catch (UnsupportedEncodingException e) 

		{

            System.out.println("writeString出现异常");

            System.exit(0);

        }

    }



    //取出数据

    public char readChar() 

	{

        return buff.getChar();

    }



    public byte readByte() 

	{

        return buff.get();

    }



    public float readFloat() 

	{

        return buff.getFloat();

    }



    public long readLong() 

	{

        return buff.getLong();

    }



    public double readDouble()

	{

        return buff.getFloat();

    }



    public int readInt() 

	{

        return buff.getInt();

    }



    public short readShort()

	{

        return buff.getShort();

    }



    public String readString()

	{

        short len = buff.getShort();

        byte[] _bytes = new byte[len];

        buff.get(_bytes, 0, len);

       

        try 

        {

			return new String(_bytes,"UTF-8");

		}

        catch (UnsupportedEncodingException e) 

		{

			// TODO Auto-generated catch block

        	System.out.println("readString出现异常");

		}

        return null;

    }



    public String readString(String charset)

	{

        short len = buff.getShort();

        byte[] _bytes = new byte[len];

        buff.get(_bytes, 0, len);

        try

		{

            return new String(_bytes, charset);

        }

		catch (UnsupportedEncodingException e) 

		{

            System.out.println("readString出现异常");

            e.printStackTrace();

            System.exit(0);

        }

        return new String(_bytes);

    }



    public ByteBuffer byteBuffer()

	{

        return buff;

    }



    public ByteBuffer pack() 

	{

        int l = length();

        ByteBuffer buffer = ByteBuffer.allocate(l);

        if (position() > 0) 

		{

            flip();

        }

        buffer.put(array(), 0, l);

        buffer.flip();

        return buffer;

    }



    public byte[] array()

	{

        return buff.array();

    }



    public int position()

	{

        return buff.position();

    }



    public void flip()

	{

        if (buff.position() > 0)

		{

            buff.flip();

        }

    }



    public void clear()

	{

        buff.clear();

        length = 0;

    }



    

    public int length()

	{

        return length - buff.remaining();

    }



    

    public int totalSize()

	{

        return length;

    }



    public void outInfo(byte[] bytes)

	{

        for (int i = 0; i < bytes.length; i++) 

		{

            System.out.println("---------" + bytes[i]);

        }

    }

    

    //发送

    public byte[] send() 

	{    	

	        //发送数据的实际长度

    	int dataLen = buff.limit() - buff.remaining();

    	

        if (buff.position() > 0)

		{

        	buff.flip();

        }



        //发送的bytes,4为数据包的长度信息,为int型,占用4个字节

        ByteBuffer bts = ByteBuffer.allocate(dataLen + 8);

        //写入数据包的长度

        System.out.print("发送的数据长度:"+dataLen);

     //   bts.putInt(dataLen+4);

        bts.putInt(dataLen+4);//在erlang的socket的{packet,2}中头部的数值的大小是包体的长度,因为此次多输个int型的,所以多加了个4,不要误解了

        bts.putInt(dataLen+4);

        //写入数据内容

        bts.put(buff);



        if (bts.position() > 0) 

		{

            bts.flip();

        }

        

        System.out.println("发送给服务端的长度:"+bts.limit() +",告诉服务器的长度"+ (dataLen+4));

        

       return bts.array();        

    }

    

    //发送

    public byte[] send(int length) 

	{    	

	        //发送数据的实际长度

    	int dataLen = buff.limit() - buff.remaining();

    	

        if (buff.position() > 0)

		{

        	buff.flip();

        }



        //发送的bytes,4为数据包的长度信息,为int型,占用4个字节

        ByteBuffer bts = ByteBuffer.allocate(dataLen + 8);

        //写入数据包的长度

        System.out.print("原始数据的长度:"+dataLen);

    

        bts.putInt(dataLen+4+length);//在erlang的socket的{packet,2}中头部的数值的大小是包体的长度,因为此次多输个int型的,所以多加了个4,不要误解了

        bts.putInt(dataLen+4+length);

        //写入数据内容

        bts.put(buff);



        if (bts.position() > 0) 

		{

            bts.flip();

        }

        

        System.out.println("发送给服务端的长度:"+bts.remaining()+",告诉服务端的长度:"+ (dataLen+4+length));

        

       return bts.array();        

    }

    

}

 

你可能感兴趣的:(erlang)