Open yellowb opened 6 years ago
conv写死,serverchannel里根据clientsocket进行管理在大部分场景下是没有问题的。 client端用一个socket去handle多个kcp会话这种做法估计不存在。
Hi @szhnet
conv是会话id。conv需要外部进行指定。例子中是hard code。实际使用中,可以客户端与服务器端进行协商
请问关于“协商”,是在什么时候/什么地方进行?因为我看demo里都是在channelActive
函数中set的,那么在channelActive
之前Server/Client应该怎么协商?
Hi @caoli5288
你的意思是指Server和所有Cilent都写死一个conv是没问题的吗?
@yellowb 在kcp连接建立之前进行协商,用tcp,或者raw udp,或者其他协议如http。
仅限于kcp-netty的实现,conv写死是没问题的,因为kcp-netty根据channel.remoteAddress()保存会话。
是的,可以在外部用tcp或者udp进行协商。 另外,kcp-netty也确实根据channel.remoteAddress()保存了会话。
=
是的,可以在外部用tcp或者udp进行协商。
@szhnet 作者你好,请问能给出udp协商的 例子吗
Hi @szhnet
conv是会话id。conv需要外部进行指定。例子中是hard code。实际使用中,可以客户端与服务器端进行协商
请问关于“协商”,是在什么时候/什么地方进行?因为我看demo里都是在
channelActive
函数中set的,那么在channelActive
之前Server/Client应该怎么协商?Hi @caoli5288
你的意思是指Server和所有Cilent都写死一个conv是没问题的吗?
我也有同样的疑问,看例子中是channelActive的时候设置了conv,但在实际应用中,此时服务端并不知道这个链接对应的客户端的conv的值,想问下楼主解决了这个问题了吗?
@medusar
服务端并不知道这个链接对应的客户端的conv的值
你可以把这个值存在channel的metadata里。虽然我并不知道这么做有什么用。前文我已经解释过了,kcp-netty根据channel.remoteAddress()保存会话
,事实上你在使用tcp时也是根据remoteAddress,存在conv只是因为udp本身并没有会话这种逻辑上的概念,你可以事实上复用端口开多个会话,但是为什么要这么做呢?
@caoli5288 恩,可能暂时我们也不会使用conv这个字段
发现有个UkcpChannelOption.UKCP_AUTO_SET_CONV
参数,服务端设置该参数,可以不需要提前设置conv,直接读取客户端传递过来的conv
服务端用childOption(UkcpChannelOption.UKCP_AUTO_SET_CONV, true),客户端随机一个数值conv。只要客户端前后两次端口值和conv值不是一样即没问题。两个随机值都相同的可能性太小,理论上没问题。
我这边使用时是通过tcp来进行协商的,conv是服务器端分配的,通过tcp告诉客户端,所以不会重复。把UkcpChannelOption.UKCP_AUTO_SET_CONV设置为true,就是为了先暂时接受客户端传过来的conv,然后消息传到上层,由服务器端上层逻辑判断conv是否合法(也就是判断conv是否与之前分配的一致)。
@szhnet 恩,感觉你这种方式才是正确的。也是KCP文档里推荐的方式。但是目前我们客户端觉得这样需要一个KCP一个TCP两套逻辑,比较复杂,所以就没有搞,只用了一套方案。
@caoli5288 大佬,有一个小问题。只根据remoteAddress标识会话是不是无法区分同一端口的前后两次连接。或者是旧报文的影响。就像是tcp即使有socket四元组后,也还是需要通过三次握手协商seq
仅限于kcp-netty的实现,conv写死是没问题的,因为kcp-netty根据channel.remoteAddress()保存会话。
我简单了解过一点kcp-go的实现。 看起来也是通过remoteaddr来保存一条会话。在此基础再比较conv的值是否变化来判断连接状态。 conv则单纯由客户端随机生成,没有协商过程。这是一种最佳实践吗?请问目前比较流行怎么用呢
RE: @TXYH1
只根据remoteAddress标识会话是不是无法区分同一端口的前后两次连接
所以为什么要复用同一个udp端口前后发起两次连接?
conv则单纯由客户端随机生成,没有协商过程。这是一种最佳实践吗?
这跟写死conv一样,都是讨巧的做法。最规范的做法是在kcp连接发起前,通过别的协议(如tcp)协商出一个conv出来,但规范不代表最佳,最佳实践这东西就看场景见仁见智了。
@caoli5288 感谢大佬的回复
所以为什么要复用同一个udp端口前后发起两次连接 我只是感觉会不会存在一些特殊情况,比如在一条链接结束后,又用同一个端口重新建立了一条,或者断开重连了,同一时间只有一条链接,但是前后是不同两条链接了,避免旧包的影响啥的。
刚接触KCP,从它的首页找到kcp-netty这个项目,使用上有几个疑惑:
1. conv值的具体用法
读了KCP的文档,个人理解conv是供服务器端识别客户端的一个标识符,毕竟UDP是非面向连接的,不知道我理解对不对?我看example里的代码EchoClientHandler和EchoServerHandler里都在channelActive函数中写死了conv的值:
kcpCh.conv(EchoClient.CONV); // set conv
而且Client和Server的conv值需要一样,否则传输数据时Server会报conv不一致的异常。这里我有个疑惑,假设有多个Client,conv值都不同,那么Server端如何在channelActive函数中知道每个Client的conv值?因为example中是hard code的
2.关于stream模式的问题,如何发送大数据
读代码时看到接收缓冲区是设定成512B
public static final int FIXED_RECV_BYTEBUF_ALLOCATOR_SIZE = 512;
测试结果是如果往channel中flush超过(512 - kcp header)字节的数据时,就会被切成多个fragment发送到对端,我看官方网页和腾讯的一篇文章,只要打开stream模式:
option(UkcpChannelOption.UKCP_STREAM, true)
对端接收到fragments后会拼装成一个完整的数据提供给应用层(不知道理解对不对)。不过我本地测试结果显示对端收到的还是一个个fragment。不过如果连续flush多个很小的数据(比如2字节),对端有时候能在一次channelRead中读到多个发送过来的数据,也就是发送方的多个小包在接收方变成一个大包了(关闭stream模式时不会有这种现象,接收方每次channelRead只能读到一次发送的数据)
请问这个行为是跟KCP的stream模式行为一致的吗?那么传输大块数据(比如64KB)时,最佳实践应该怎样?