Java - 理解Servlets

3
我正在完成一个作业项目,该项目应该通过HttpServlet在2个客户端之间实现一款棋盘游戏。我有几个问题:
1)我读到HttpServlet必须是无状态的,但是出于游戏的需要,我必须保持很多状态(谁的回合,棋盘的状态等)。我必须将其保存在客户机中吗? HttpServlet是否确实必须是无状态的,即没有跟踪状态的字段?
2)我知道客户端将通过doGet/doPost方法与servlet通信,但是servlet如何与客户端通信(例如,如果玩家1刚刚移动并将其发送到servlet,则servlet必须告诉客户端2这个移动是什么)。
谢谢
此外,如果您可以为我指出一个类似代码的有用且简单的示例在线资源,我会非常感激。

  1. 在此处查看轮询的示例:[http://stackoverflow.com/questions/6849236/update-a-web-page-as-a-process-runs/6849768#6849768]
- Joe Coder
4个回答

3

你的 1) 为什么与 Dave Newton 的相矛盾?此外,1) 中的链接无法使用。 - Trup
@Trup 1) 我们都在谈论同一件事。正如我所提到的,HTTP是无状态的,但Servlet提供了API来管理状态。链接对我来说是有效的,但我已经为您更换了另一个链接。 - Aravind Yarram
谢谢,现在它可以工作了。那么,您是说Servlet类不能像任何其他类一样简单地将状态保存在字段中吗?那么下一个最简单的事情是什么? - Trup
@Trup Servlet可以在字段中保存状态,但对该字段的访问必须同步--典型的多线程问题。如果服务器必须为多个玩家维护世界状态,则必须有某些东西具有共享状态,必须是线程安全的。它不一定要在servlet中,它可以在应用程序范围内,静态(呃,但是无论如何,它都必须去某个地方),等等。 - Dave Newton
@Trup - Servlet只创建一个对象来为所有客户端请求提供服务。这意味着在Servlet中存储状态不是线程安全的,也不建议这样做。此外,Servlet具有内置API,可以在无状态协议上启用状态管理,因此最好利用它而不是构建自己的状态管理机制。 - Aravind Yarram
显示剩余5条评论

2
Servlets需要能够处理多个请求——它们不需要是无状态的,但必须管理该状态以避免典型的多线程问题。显然,如果有两个用户需要访问同一个世界,则需要一种机制来实现。假设服务器将帮助跟踪游戏状态,这样可以避免作弊或恶意客户端。
有各种各样的选项;客户端可以轮询移动更新,也可以使用长轮询等。

你说的轮询是什么意思?这和我的第二个问题有关吗?你能给出一些示例来说明如何实现吗? - Trup
@Trup,有短轮询(页面刷新、定时器/ajax等)和长轮询(comet等),找到示例应该很容易。我自己对长轮询不太熟悉,所以不太敢指出具体的东西。 - Dave Newton

1

其他人已经涵盖了#1。

我只是为#2提出一个建议。另一个选择是快速查看AJAX(异步JavaScript和XML)。您可以在不需要用户刷新页面的情况下触发“幕后”HTTP请求并调整页面。客户端可以加载具有JavaScript的HTML页面,该JavaScript每隔几秒钟检查更新并刷新其面板。

这里有一个小例子。此外,如果您不想担心特定于浏览器的JavaScript,可以尝试使用jQuery。它具有相当用户友好的API,用于触发ajax请求并处理特定于浏览器的问题。

编辑

好的,对于#1-您的servlet将用于服务所有请求,可能是并行的。您不能直接将游戏板放在servlet中,因为那样您可能会有20个人尝试编辑同一场比赛。

public class GameServlet extends HttpServlet {
   private GameBoard board; // everyone would share the same board!

您有几个选项,可以将板存储在某些集合中,通过用户访问。您还可以查看HttpSession。 HttpSession是服务器端内存的一部分,servlet会为您跟踪它,您可以跨请求访问它。

public void doGet(HttpServletRequest req, HttpServletResponse resp) {

  HttpSession session = req.getSession();
  session.setAttribute("board", new GameBoard());  // this way each user will have their own game board

  // and you can retrieve it in another HTTP request
  GameBoard board = session.getAttribute("board");
}

使用HttpSession对您来说可能有点棘手,因为版面更新实际上必须更新两个用户的版面。您可能更喜欢一个由用户索引的servlet上的集合成员。希望这足以让您开始。


我能得到一个关于#1的例子吗?我仍然不太明白我应该做什么/我能做什么。 - Trup

0

HTTP协议是无状态的(正如人们所提到的)。然而,HTTP的一个小部分是在服务器和客户端之间传递“Cookies”。这些Cookie是另一个RFC(http://www.ietf.org/rfc/rfc2109.txt),由HTTP客户端(即浏览器)解释。在HTTP方面,Cookie只是另一个头字段,但对于浏览器来说具有特殊意义。

这些Cookie的一个用途是为基于Servlet的程序向客户端浏览器传递会话ID。当客户端发送后续请求时,同一Cookie会自动发送回发出它的服务器。服务器识别并标识用户会话。这对程序员来说大多是透明的。

通常,Tomcat(或其他容器)会为您处理此操作,您只需要求Servlet请求会话即可:

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {

    // the parameter determines if session can be created if one does not exist for the client
    HttpSession session = req.getSession(true); 

    session.setAttribute("attName", attValue);
}

您可以使用会话来存储/检索属性。至于常见的游戏状态,那应该存储在其他地方(某种游戏管理器对象),但您可以将用户的当前游戏ID存储在其会话中,这将允许servlet为用户查找适当的游戏。当用户进行移动时,通过指示此操作的http请求更新游戏状态。两个用户都必须定期发出http请求以请求游戏的当前状态、最近的移动等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接