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 908204694@qq.com
 *
 */
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 908204694@qq.com
 *
 */
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 908204694@qq.com
 *
 */
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();        
    }
    
}
原文地址:https://www.cnblogs.com/ribavnu/p/3437608.html