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