- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
正如标题所说,我有一个用 Erlang 编写的服务器,一个用 Java 编写的客户端,它们通过 TCP 进行通信。我面临的问题是 gen_tcp:recv 显然不知道何时收到来自客户端的“完整”消息,因此将其“拆分”为多条消息。
这是我正在做的一个例子(不完整的代码,试图只保留相关部分):
-module(server).
-export([start/1]).
-define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr, true}].
start(Port) ->
{ok, ListenSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
accept(ListenSocket).
accept(ListenSocket) ->
{ok, Socket} = gen_tcp:accept(ListenSocket),
spawn(fun() -> loop(Socket) end),
accept(ListenSocket).
loop(Socket) ->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
io:format("Recieved: ~s~n", [Data]),
loop(Socket);
{error, closed} ->
ok
end.
public class Client {
public static void main(String[] args) {
Socket connection = new Socket("localhost", Port);
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
Scanner sc = new Scanner(System.in);
while(true) {
output.writeBytes(sc.nextLine());
}
}
}
Hello!
Received: H
Received: el
Received: lo!
我一直在搜索,如果我理解正确的话,TCP 不知道消息的大小,你需要手动设置某种分隔符。
但我没有明白的是,如果我改为用 Erlang 编写客户端,消息似乎永远不会分开,如下所示:
-module(client).
-export([start/1]).
start(Port) ->
{ok, Socket} = gen_tcp:connect({127,0,0,1}, Port, []),
loop(Socket).
loop(Socket) ->
gen_tcp:send(Socket, io:get_line("> ")),
loop(Socket).
Hello!
Received: Hello!
这让我想知道它是否可以在 Java 端修复?我在服务器端尝试了几种不同的输出流、写入方法和套接字设置的组合,但没有解决问题。
另外,网络上有大量 Erlang(聊天)服务器示例,它们不做任何分隔符的事情,尽管这些通常在两端都是用 Erlang 编写的。然而,他们似乎假设消息的接收与发送一样。这只是不好的做法,还是当客户端和服务器都用 Erlang 编写时,是否存在一些关于消息长度的隐藏信息?
如果需要进行定界符检查,我很惊讶找不到关于该主题的太多信息。如何以实用的方式完成?
提前致谢!
最佳答案
This makes me wonder if it is something that can be fixed on the Java side?
不,绝对不是。不管您为什么没有碰巧看到 Erlang 客户端的问题,如果您没有在协议(protocol)中加入任何类型的“消息边界”指示,您将无法可靠地检测到整个消息。我强烈怀疑如果您使用 Erlang 客户端发送非常大的消息,您仍然会看到拆分的消息。
你应该:
除此之外,您目前还不能清楚地区分字节和文本。例如,您的 Java 客户端当前静默忽略每个 char
的前 8 位。与其使用 DataOutputStream
,我建议只使用 OutputStream
,然后对每条消息:
使用特定编码将其编码为字节数组,例如
byte[] encodedText = text.getBytes(StandardCharsets.UTF_8);
将长度前缀写入流(可能是 7 位编码整数,或者可能只是固定宽度,例如 4 字节)。 (实际上,坚持使用 DataOutputStream
会使这更简单一些。)
在服务器端,您应该通过读取长度来“读取消息”,然后读取指定的字节数。
您无法回避 TCP 是基于流 的协议(protocol)这一事实。如果你想要一个基于消息的协议(protocol),你真的必须自己把它放在首位。 (当然,我确信有有用的库可以做到这一点——但你不应该把它留给 TCP 并寄希望于。)
关于java - Erlang 服务器,Java 客户端 - TCP 消息被拆分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23724112/
我想实现一个 Erlang 解释器,最近我在阅读 Erlang 的标准库源代码。我在 erlang.erl 中找到 erlang:display/1 的源代码是: %% display/1 -spec
我即将用 Erlang 构建一个系统(我的问题可以用多个 CPU 更好地解决),我已经浏览了: 向你学习一些 Erlang; Erlang/OTP 在行动 编程 Erlang(阿姆斯壮); Erlan
我真的很难理解 Erlang 中的尾递归。 我有以下 eunit 测试: db_write_many_test() -> Db = db:new(), Db1 = db:write(f
我不确定或者我不知道 erlang 定位不在默认目录中的模块的传统方式。我知道它会查看已编译的文件夹和 erlang 的系统文件夹或 - lists:foreach(fun (E) -> io:fwr
对 Erlang 完全陌生。我正在尝试为函数组合定义一些函数,例如 compose , juxt和 pipe但是遇到这样一个事实,即 Erlang 没有(据我所知)可变参数,因此很难只编写适用于所有输
在 Erlang 中存储和管理高性能可变对象的最佳方法是什么?假设我想编写具有实时游戏玩法的非常简单的在线游戏服务器。不知何故,我需要在 Erlang 内存中表示玩家的状态。例如,它可能只是一个简单的
警告:前面的 erlang n00b。 我正在尝试掌握 erlang,只是尝试与牛仔一起使用基本的 hello world 应用程序。我正在模拟一个错误,基本上是在我的代码中的某处返回一个无效值,并试
当你向 shell 进程发送消息时,你可以通过调用: c:flush(). 来清除所有消息。 C:\Windows\System32>erl Eshell V5.9(使用 ^G 中止) 1> 自我()
这应该是一个简单的问题,但我不太了解文档,无法找到答案。 如果 OTP 管理器在崩溃后重新启动 gen_server,新子进程是否继承了崩溃进程的消息队列,或者消息是否在崩溃之前发送但尚未由旧子进程处
我将 net_ticktime 值设置为 600 秒。 net_kernel:set_net_ticktime(600) 在 net_ticktime = TickTime 的 Erlang 文档中:
我正在监视一个 Erlang 应用程序,我目前正在尝试确定特定 PID 已经运行了多长时间。绝对时间戳或持续时间对我有用,但我在 process_info 或通过 sys 模块看不到这些数据位中的任何
我想重新定义查找特定单词的元组的顺序 例如,我有一个像这样的元组列表: [{"a",["r001"]}, {"bi",["bidder"]}, {"bo",["an"]}] 但有时元组的顺序可能会
以下几行出现在 http://aosabook.org/en/riak.html 中,在该部分的第二段: 15.1. Erlang 简介 : "Calling the function with a
我认为 Erlang 节点之间的消息不应该很大。如果我想构建一个流服务器,通常每个连接都需要很大的带宽,Erlang 能做好吗?如果是,是否有任何开源代码可供我学习?我了解到 Erlang 很适合处理
下一个代码在结果中给了我 5.999999999999998,但正确答案是 6。 Alpha = math:acos((4*4 + 5*5 - 3*3) / (2*4*5)) Area = 1/2 *
注意:这是我的 previous question 的进化延续。关于类似的话题。 一段时间以来,我一直在寻找有关部署和更新 Erlang/OTP 版本(一组应用程序)的“最佳实践”,但我找不到任何直接
我试图在头文件中指定一个函数。 像这样: -spec update(pid(), tuple(tuple(), integer(), atom()), tuple(atom(), atom())) -
所以我在过去的八个小时里一直在使用 Erlang,我花了两个时间用我的头敲击键盘试图找出我的控制台不断返回的异常错误。 我正在编写一个骰子程序来学习erlang。我希望它能够通过 erlang 解释器
当我编译以下模块时: -module(x). -export([inp/0]). f(X) -> g(X). g(X) -> error(X). inp() -> f(123)
我目前正在开发一个实时媒体服务器,它将允许普通消费者向我们发送实时视频。在我们当前的环境中,我们已经看到发送给我们的广播持续了几天,因此能够在不断开用户连接的情况下修复错误(或添加功能)的想法非常引人
我是一名优秀的程序员,十分优秀!