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 ...
随机推荐
- win10 U盘安装ubuntu16.04双系统
所需工具U盘,软件ultralISO.ubuntu16.04,自己使用的系统是win10 一.制作U盘启动盘 打开ultraISO软件 2 2 3 4 开始写入—>直到完成大概五分的样子 二. ...
- MATLAB(2)——小波工具箱使用简介
作者:桂. 时间:2017-02-19 21:47:27 链接:http://www.cnblogs.com/xingshansi/articles/6417638.html 前言 本文主要介绍MA ...
- Windows Store Apps 开发转载
懒得写了,就直接记录转载一下文章地址吧. 如何为应用定义全局默认字体:http://blogs.msdn.com/b/gautamdh/archive/2014/03/16/how-to-change ...
- [k8s]subpath解决cm覆盖目录问题
参考 发现cm老覆盖容器原有目录里的内容,后来不得不通过in -s的方式来搞cm, 先将cm挂到/tmp下,然后ln -s文件到指定目录. 后来发现个cm的subpath特性可以解决这个问题 写了bu ...
- angular学习笔记(十四)-$watch(1)
本篇主要介绍$watch的基本概念: $watch是所有控制器的$scope中内置的方法: $scope.$watch(watchObj,watchCallback,ifDeep) watchObj: ...
- Oracle PLSQL Demo - 18.02.管道function[查询零散的字段组成list管道返回] [字段必须对上]
--PACKAGE CREATE OR REPLACE PACKAGE test_141215 is TYPE type_ref IS record( ENAME ), SAL )); TYPE t_ ...
- rm: cannot remove `dir': Device or resource busy解决办法
使用df查看系统发现: [ops@bs038 cm-5.4.0]$ df -hFilesystem Size Used Avail Use% Mounted on/dev/sda3 1.1T 200G ...
- svn 版本导致
Malformed network data svn: Unable to parse URL '/svn/PROJECT/13.深大出版社/trunk/sdcbs/' svn 版本导致 1 ...
- poj 50道dp题
1.poj 3267 题意:给你一个字符串,下面有若干单词,问字符串要变成由下面单词组成的字符串,至少要删除多少个字母...... 例如: 6 10 browndcodw cow milk whit ...
- kubernetes生态圈
1:helm(部署工具,可以用来部署常用的应用,替代kubelet原生命令) https://github.com/kubernetes/helm 应用列表:https://github.com/ku ...