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();
} }
erlang的简单模拟半包的产生的更多相关文章
- java web学习总结(二十二) -------------------简单模拟SpringMVC
在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: ...
- JavaWeb学习总结(四十九)——简单模拟Sping MVC
在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: ...
- c# socket 解决粘包,半包
处理原理: 半包:即一条消息底层分几次发送,先有个头包读取整条消息的长度,当不满足长度时,将消息临时缓存起来,直到满足长度再解码 粘包:两条完整/不完整消息粘在一起,一般是解码完上一条消息,然后再判断 ...
- Linux 内核 链表 的简单模拟(2)
接上一篇Linux 内核 链表 的简单模拟(1) 第五章:Linux内核链表的遍历 /** * list_for_each - iterate over a list * @pos: the & ...
- 关于TCP封包、粘包、半包
关于Tcp封包 很多朋友已经对此作了不少研究,也花费不少心血编写了实现代码和blog文档.当然也充斥着一些各式的评论,自己看了一下,总结一些心得. 首先我们学习一下这些朋友的心得,他们是: http: ...
- java模拟浏览器包selenium整合了htmlunit,火狐浏览器,IE浏览器,opare浏览器驱
//如果网页源码中有些内容是js渲染过来的,那你通过HttpClient直接取肯定取不到,但是这些数据一般都是通过异步请求传过来的(一般都是通过ajax的get或者post方式).那么你可以通过火狐浏 ...
- 记一次解决netty半包问题的经历
最近学习了netty,想写一个简单的rpc,结果发现发送消息时遇到难题了,网上搜了一下,这种情况是半包问题和粘包问题,主要是出现在并发高一些的时候. talk is cheap 客户端编码: prot ...
- Http 调用netty 服务,服务调用客户端,伪同步响应.ProtoBuf 解决粘包,半包问题.
实际情况是: 公司需要开发一个接口给新产品使用,需求如下 1.有一款硬件设备,客户用usb接上电脑就可以,但是此设备功能比较单一,所以开发一个服务器程序,辅助此设备业务功能 2.解决方案,使用Sock ...
- spring之mvc原理分析及简单模拟实现
在之前的一篇博客中已经简单的实现了spring的IOC和DI功能,本文将在之前的基础上实现mvc功能. 一 什么是MVC MVC简单的说就是一种软件实现的设计模式,将整个系统进行分层,M(model ...
随机推荐
- linux下man手册简介
Linux提供了丰富的帮助手册,当你需要查看某个命令的参数时不必到处上网查找,只要man一下即可.Linux 的man手册共有以下几个章节: 1.Standard commands (标准命令)2.S ...
- jQuery 隐藏与显示 input 默认值
分享下jQuery如何隐藏和显示 input 默认值的例子. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN ...
- mybatis 一二事(2) - 动态代理
db.properties 单独提取出来的数据库配置,方便以后维护管理 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhos ...
- Servlet与WebService关系
转自:http://www.cnblogs.com/cy163/archive/2008/04/16/1155767.html 其实从实现的效果上,它们是很相似的 相同点: 客 ...
- SQL游标操作每隔5分钟时间段数据统计信息
Tb_People 表信息: id uname era amount plushtime 1000031 张亮 中年 100000 ...
- Cocos2dx Label
cocos2dx3.0添加了一种新的文本标签,这种标签不同的地方有:使用freetype来使它在不同的平台上有相同的视觉效果:由于使用更快的缓存代理,它的渲染也将更加快速:同时它还提供了绘边.阴影等特 ...
- vue轮播图插件vue-awesome-swiper的使用与组件化
不管是APP还是移动端网页开发,轮播图在大部分项目当中都是存在的,这时候如果用vue开发项目,选择一款好的插件并且封装好是很重要的 1. 推荐使用vue-awesome-swiper 安装:cnpm ...
- Zookeeper已经分布式环境中的假死脑裂
Zookeeper简介 在上班之前都不知道有这样一个东西,在开始说假死脑裂之前先说说Zookeeper吧. Zookeeper zookeeper是一个分布式应用程序的协调服务.它是一个为分布式应用提 ...
- Mybatis Spring multiple databases Java configuration
https://stackoverflow.com/questions/18201075/mybatis-spring-multiple-databases-java-configuration ** ...
- maven打包可以行文件,包含依赖包等
<build> <!-- 设定打包的名称 --> <finalName>ismp2xy</finalName> <plugins> < ...