Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

咨询关于conv值和stream模式的问题 #6

Open
yellowb opened this issue Jul 13, 2018 · 17 comments
Open

咨询关于conv值和stream模式的问题 #6

yellowb opened this issue Jul 13, 2018 · 17 comments

Comments

@yellowb
Copy link

yellowb commented Jul 13, 2018

刚接触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)时,最佳实践应该怎样?

@yellowb yellowb changed the title 咨询关于使用上的问题 咨询关于conv值和stream模式的问题 Jul 13, 2018
@szhnet
Copy link
Owner

szhnet commented Jul 16, 2018

  1. conv是会话id。conv需要外部进行指定。例子中是hard code。实际使用中,可以客户端与服务器端进行协商。
  2. 包模式是会保留数据包的边界。会收到所有分片后才返回给外部。流模式没有这些。现在kcp-netty在包模式下,并没有将所有分片合成到一个ByteBuf里,而是将每个分片的ButeBuf都调用了一次channelRead,并在最后调用了一次channelReadComplete,以此来表示一个数据包的边界。我考虑之后可以增加一个开关,用来控制是否将数据合并到一个ByteBuf中。

@caoli5288
Copy link

conv写死,serverchannel里根据clientsocket进行管理在大部分场景下是没有问题的。
client端用一个socket去handle多个kcp会话这种做法估计不存在。

@yellowb
Copy link
Author

yellowb commented Jul 19, 2018

Hi @szhnet

conv是会话id。conv需要外部进行指定。例子中是hard code。实际使用中,可以客户端与服务器端进行协商

请问关于“协商”,是在什么时候/什么地方进行?因为我看demo里都是在channelActive函数中set的,那么在channelActive之前Server/Client应该怎么协商?

Hi @caoli5288

你的意思是指Server和所有Cilent都写死一个conv是没问题的吗?

@caoli5288
Copy link

@yellowb 在kcp连接建立之前进行协商,用tcp,或者raw udp,或者其他协议如http。

仅限于kcp-netty的实现,conv写死是没问题的,因为kcp-netty根据channel.remoteAddress()保存会话。

@szhnet
Copy link
Owner

szhnet commented Jul 19, 2018

是的,可以在外部用tcp或者udp进行协商。
另外,kcp-netty也确实根据channel.remoteAddress()保存了会话。

@dingzhichao
Copy link

=

是的,可以在外部用tcp或者udp进行协商。

@szhnet 作者你好,请问能给出udp协商的 例子吗

@medusar
Copy link

medusar commented May 15, 2019

Hi @szhnet

conv是会话id。conv需要外部进行指定。例子中是hard code。实际使用中,可以客户端与服务器端进行协商

请问关于“协商”,是在什么时候/什么地方进行?因为我看demo里都是在channelActive函数中set的,那么在channelActive之前Server/Client应该怎么协商?

Hi @caoli5288

你的意思是指Server和所有Cilent都写死一个conv是没问题的吗?

我也有同样的疑问,看例子中是channelActive的时候设置了conv,但在实际应用中,此时服务端并不知道这个链接对应的客户端的conv的值,想问下楼主解决了这个问题了吗?

@caoli5288
Copy link

caoli5288 commented May 15, 2019

@medusar

服务端并不知道这个链接对应的客户端的conv的值

你可以把这个值存在channel的metadata里。虽然我并不知道这么做有什么用。前文我已经解释过了,kcp-netty根据channel.remoteAddress()保存会话,事实上你在使用tcp时也是根据remoteAddress,存在conv只是因为udp本身并没有会话这种逻辑上的概念,你可以事实上复用端口开多个会话,但是为什么要这么做呢?

@medusar
Copy link

medusar commented May 20, 2019

@caoli5288 恩,可能暂时我们也不会使用conv这个字段

@medusar
Copy link

medusar commented May 31, 2019

发现有个UkcpChannelOption.UKCP_AUTO_SET_CONV参数,服务端设置该参数,可以不需要提前设置conv,直接读取客户端传递过来的conv

@gdpencil
Copy link

服务端用childOption(UkcpChannelOption.UKCP_AUTO_SET_CONV, true),客户端随机一个数值conv。只要客户端前后两次端口值和conv值不是一样即没问题。两个随机值都相同的可能性太小,理论上没问题。

@szhnet
Copy link
Owner

szhnet commented Sep 30, 2019

我这边使用时是通过tcp来进行协商的,conv是服务器端分配的,通过tcp告诉客户端,所以不会重复。把UkcpChannelOption.UKCP_AUTO_SET_CONV设置为true,就是为了先暂时接受客户端传过来的conv,然后消息传到上层,由服务器端上层逻辑判断conv是否合法(也就是判断conv是否与之前分配的一致)。

@medusar
Copy link

medusar commented Sep 30, 2019

@szhnet 恩,感觉你这种方式才是正确的。也是KCP文档里推荐的方式。但是目前我们客户端觉得这样需要一个KCP一个TCP两套逻辑,比较复杂,所以就没有搞,只用了一套方案。

@TXYH1
Copy link

TXYH1 commented Sep 29, 2021

@caoli5288 大佬,有一个小问题。只根据remoteAddress标识会话是不是无法区分同一端口的前后两次连接。或者是旧报文的影响。就像是tcp即使有socket四元组后,也还是需要通过三次握手协商seq
仅限于kcp-netty的实现,conv写死是没问题的,因为kcp-netty根据channel.remoteAddress()保存会话。

@TXYH1
Copy link

TXYH1 commented Sep 29, 2021

我简单了解过一点kcp-go的实现。 看起来也是通过remoteaddr来保存一条会话。在此基础再比较conv的值是否变化来判断连接状态。 conv则单纯由客户端随机生成,没有协商过程。这是一种最佳实践吗?请问目前比较流行怎么用呢

@caoli5288
Copy link

RE: @TXYH1

只根据remoteAddress标识会话是不是无法区分同一端口的前后两次连接

所以为什么要复用同一个udp端口前后发起两次连接?

conv则单纯由客户端随机生成,没有协商过程。这是一种最佳实践吗?

这跟写死conv一样,都是讨巧的做法。最规范的做法是在kcp连接发起前,通过别的协议(如tcp)协商出一个conv出来,但规范不代表最佳,最佳实践这东西就看场景见仁见智了。

@TXYH1
Copy link

TXYH1 commented Oct 6, 2021

@caoli5288 感谢大佬的回复

所以为什么要复用同一个udp端口前后发起两次连接
我只是感觉会不会存在一些特殊情况,比如在一条链接结束后,又用同一个端口重新建立了一条,或者断开重连了,同一时间只有一条链接,但是前后是不同两条链接了,避免旧包的影响啥的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants