【问题标题】:Client Connects to ServerSocket without Accept - Why? [duplicate]客户端在不接受的情况下连接到 ServerSocket - 为什么? [复制]
【发布时间】:2015-02-18 20:07:43
【问题描述】:

我希望我的问题的答案是指向文档的指针。但是,如果合适的话,我可以发布代码来寻找错误。

为了简化在家工作,我试图在单个 Wintel 操作系统/计算机中模拟将在微控制器中运行的服务器与将在 Wintel PC 中运行的 Java 客户端之间的交互。如果仿真足够好,我就不必将微控制器设备带回家只是为关系的 PC 端开发软件。

因此,在单个 Wintel 计算机(在家)中的单个 JVM 中,我这样做了:

  1. 创建了一个绑定到 192.168.1.63:3456 的新 ServerSocket 对象(本地 地址和本地(知名)端口),backlog 参数设置为 0。此对象 表示通常在微控制器中的代码。
  2. 创建了一个绑定到 192.168.1.63:3456 和 192.168.1.63:0(远程地址,远程端口,本地地址,本地 端口(临时端口的占位符))。这个对象代表 通常会在 Wintel 计算机中的代码/对象。

我预计上面第 2 项中新 Socket 的创建会阻塞(不连接),直到我调用 ServerSocket 的 accept() 方法。相反,Socket 创建尝试(以及 Socket 的隐式连接尝试)立即产生了一个新的(客户端)Socket 对象;我的(客户端)代码继续执行(接下来的几条指令是 .setReuseAddress(true)、.getInputStream()、.getOutputStream() 等)。

我在 Java API 文档中读到的所有内容都明确或隐含地表明,ServerSocket 的 accept() 调用允许 Sockets 完成连接到 ServerSocket 的过程(实际上是到 ServerSocket 创建的新 Socket ......);但是我的 Socket 在调用 ServerSocket accept() 之前就已经开始比赛了。

谁能指出我所看到的解释(客户端的连接尝试在服务器的 accept() 之前完成)?

希望解释能让我知道如何创建适当的模拟(不需要特殊代码,因为客户端和服务器都在一台计算机上)。

PS:以防万一……当我看到这种行为(上图)时运行的代码是单线程的。在有人指出它必须成为多线程才能完全成功之前;我知道。无论如何,我没想到我上面描述的。

【问题讨论】:

  • 为什么会有问题?
  • @immibis, A) 任何关于我编写的代码如何执行的不理解都是一个问题(有时很小,有时很大)。 2)如果是bug,应该报告。 C)当 Socket 创建没有阻塞时,包含它的线程在服务器准备好之前开始尝试与服务器通信(这会破坏它们)。 D) 模拟服务器的行为方式与真实微控制器服务器的行为方式不同。 E) 我需要继续吗?
  • 我在 Linux 上的 C 中得到了与您相同的结果。看起来您的答案在这个问题中:stackoverflow.com/q/2409277/3004881
  • 丹·盖茨 - 谢谢。在 Stevens 的 Unix Network Programming Vol I 中,我还看到了这个有用的句子,“TCP 服务器调用accept 以从已完成的连接队列的前面返回下一个已完成的连接[Blake 说:积压](图 4.7)。 "我认为如果对 Java ServerSocket.accpt() 和 Socket() JavaDocs 进行修改以阐明接受调用从已完成连接的积压队列中提取已完成的连接(或块)(摆脱不良定义短语“未决连接”)。正式建议的简单方法是什么?
  • 仅供参考 - 我使用 Oracle 的错误报告和功能请求流程来建议更新 ServerSocket API(和教程)文档。该建议在功能请求中。该请求已分配审核 ID:JI-9019201;并且标题为“ServerSocket.accept() API 描述应包括过去时”

标签: java sockets connect serversocket acceptance


【解决方案1】:

积压参数为0

平台会向上或向下调整。请参阅 Javadoc。最小积压值从未低于 5,现在在某些平台上为 50 甚至 500。

我在 Java API 文档中读到的所有内容都明确或隐含地表明,ServerSocket accept() 调用是允许 Socket 完成连接到 ServerSocket 的过程的原因

诸如什么之类的一切?请提供引用。我不知道任何地方有任何文件证明这种错误信念是正当的。 accept() 返回的套接字表示从客户端的角度来看可能已经完全形成的连接。这就是积压队列的用途。

(实际上是ServerSocket创建的新Socket...);但是我的 Socket 在调用 ServerSocket accept() 之前就已经开始比赛了。

您的连接已由 TCP 堆栈完成并置于积压队列中。 accept() 所做的只是创建本地套接字作为其端点,甚至可能没有。

这都是正常的。您的预期不正确。

如果它“弄乱了他们俩”,您的代码中就有错误。在服务器调用accept().之前,客户端完成连接并发送请求并等待回复是完全正常的

【讨论】:

  • Java SE 7 API Javadocs 在描述“ServerSocket(port, backlog, bindAddr)”构造函数参数的含义时包含这些句子。 “backlog 参数是套接字上请求的最大挂起连接数。它的确切语义是特定于实现的。”
  • * Java SE 7 API Javadocs 在描述“ServerSocket(port, backlog, bindAddr)”构造函数参数的含义时包含这些句子。 “积压参数是套接字上请求的最大挂起连接数。它的确切语义是特定于实现的。”假设“待处理的连接”与“连接”不同是非常合理的。在相关说明中,套接字不是 TCP。一个套接字使用 TCP。因此,TCP 所做的事情在这个对话中非常有趣,但并未定义套接字的作用。
  • 1.真的。除了说你错了,没有其他方法可以回答这个问题。 2. 您没有引用任何实际说明您所声称的内容的内容。 “挂起的连接”只是一个尚未被接受的连接,您观察到的行为证明了这一点。你会发现在很多书中都用序列图正确地记录了这一点,包括我自己的。 3. ServerSocket 一个 TCP 套接字,我要补充一点,它没有任何未完全由 Berkeley 套接字 API 定义的语义。 Java 不以任何形式或形式实现 TCP。
  • 各位,对不起上面的部分评论,我还在学习StackOverflow的评论界面。 EJP - 关于设置在 5 到 500 之间的积压工作。这无关紧要。关于文档 - 请引用一个 Oracle(或其他?)教程,说明 Socket() 应该/可能在 ServerSocket.accept() 之前调用。我发现的许多人并没有说它是允许的,并且都强烈暗示相反是必需的。关于您上面的“代码中的错误”破解;在你“帮助”其他人之前,你应该弄清楚(或问别人)为什么这种破解完全没有必要,而且非常粗鲁。
  • 当您的代码尝试将积压设置为零时,设置为 5 到 500 之间的积压并不是无关紧要的。我建议不要继续与试图帮助你的人进行这种毫无意义的争吵,以及射击信使等,而是专注于真正的问题,即出错的代码。在一个新问题中发布。这其中没有生命。并删去个人言论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 2021-11-01
  • 2017-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多