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();
}
}