一.准备工作
1.序言
做这个项目的目的是帮助大家理解http服务器是怎样运行的,所以我使用的方法只是为了实现核心http传输信息功能,并没有考虑数据的存储,以及安全性之类的东西。所以这个项目仅供学习参考,不喜勿喷。
这个项目的实现方法有很多很多,比如:
(1)jsp+application:直接使用jsp内置application对象来实现数据的暂存。
(2)servlet+redis:使用servlet来处理请求,使用redis来缓存数据。
以及还有很多其他方法,这里就不累赘了,为了方便大家理解,我就直接使用jsp的内置对象application来实现
2.环境:
- tomcat 9.0
- jdk 1.8
- unity2017.4
3.相关知识:
服务器部分:
-
jsp:(java server page)即运行在服务器端的一个程序。
<%@page import="java.lang.*"%> //需要导入的包 <%@ page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%> //定义页面的字符编码,一般是支持中文的国际编码utf-8 <% java代码 %> //和普通的java一样、只是内置对象可以直接使用,不用定义 <html> html网页代码 //具体不详写 </html> -
request: jsp中存储有http请求的相关信息的一个内置对象。
request.getParameter("表单属性名"); //获取http请求中的表单数据 -
response: jsp中存储有服务器响应给浏览器客户端的相关信息的一个内置对象。
response.getWriter().write("输出信息"); //获取响应的书写器,向客户端输出信息,和内置out对象一样
- application: jsp的一个内置对象,即可以直接使用,一个服务器项目只有一个application对象,服务器重启这个对象就会重置,当jsp转为servlet的java代码后,application会转为ServletContext对象,可以在servlet代码中使用request.getServletContext()来获取这个对象
application.setAttribute("属性名",属性值); //存储数据 application.getAttribute("属性名"); //获取数据
- out: jsp中内置的向客户端输出信息的对象,在servlet中是JspWriter对象。
out.write("输出信息"); //向客户端输出信息(先写入缓冲区) out.flush(); //刷新缓冲区、执行后会将缓冲区的内容发送给客户端
unity客户端部分:
unity内置有一个WWW类,可以用来发送HTTP请求(当然也可以通过C#中有关HTTP协议的部分来实现),返回的WWW实例中存储有从服务器端返回的数据
注意:要想用unity的WWW类发送HTTP请求必须通过协程来实现
发送HTTP请求:
WWWForm form = new WWWForm(); //新建一个表单 form.AddField("属性名", 属性值); //向表单中添加字段 WWW www = new WWW("http://127.0.0.1:8080/Server/index.jsp", form); //post方式发送HTTP请求
WWW www = new WWW("http://127.0.0.1:8080/Server/index.jsp?username=user&password=123"); //get方式发送HTTP请求
获取返回的信息:
String result = www.text //获取www中的文本信息 byte[] res = www.bytes; //获取www中的二进制数据 AudioClip audioclip = www.GetAudioClip(); //获取www中的音频文件 MovieTexture movie = www.GetMovieTexture(); //获取www中的视频文件
4. 具体开发
服务器端(在项目文件夹Server下的index.jsp):
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String x = request.getParameter("x"); //棋子的x坐标 String y = request.getParameter("y"); //棋子的y坐标 String id = request.getParameter("id"); //棋子的颜色(0代表黑色,1代表白色)
//如果发来的是黑棋信息,则在服务器端更新存储的黑棋信息,并将白棋信息发送给客户端 if(id.equals("0")) { application.setAttribute("black", x +","+ y); out.write((String)application.getAttribute("white")); out.flush(); } //如果发来的是黑棋信息,则在服务器端更新存储的黑棋信息,并将白棋信息发送给客户端 else if(id.equals("1")) { application.setAttribute("white", x +","+ y); out.write((String)application.getAttribute("black")); out.flush(); } %>
unity客户端(客户端TakeChess脚本获取用户落棋的坐标,然后通过SenChessPos脚本发送给服务器端,随后将服务器端返回的对方的落棋坐标在本地显示出来):
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /* Bcoordinate:Vector2类型的变量,用来存储游戏中每回合的黑棋的下棋坐标 Wcoordinate:Vector2类型的变量,用来存储游戏中每回合的白棋的下棋坐标 */ [RequireComponent(typeof(TakeChess))] //挂上此脚本的物体必须要有TakeChess脚本,即游戏主逻辑脚本 public class SendChessPos : MonoBehaviour { public float timer = 0.1f; //客户端发送HTTP请求的间隔时间 public GameObject infotext; //通知连接信息的UI组件 TakeChess takechess; //游戏的主逻辑组件(脚本),期中存有每回合的黑白棋坐标 // Use this for initialization void Start () { takechess = this.GetComponent<TakeChess>(); //获取主逻辑脚本组件 } // Update is called once per frame void Update () { timer -= Time.deltaTime; if (timer <= 0) { timer = 0.1f; StartCoroutine(SendChesspos()); } } public void onClickBtn() { StartCoroutine(sendChesspos()); } //发送HTTP请求的协程 IEnumerator SendChesspos() { WWWForm form = new WWWForm(); if(takechess.Bcoordinate != null) { form.AddField("x", (int)takechess.Wcoordinate.x); form.AddField("y", (int)takechess.Wcoordinate.y); form.AddField("id", 1); //编号和服务器端统一 } WWW www = new WWW("http://127.0.0.1:8080/Server/index.jsp", form); yield return www; //等服务器响应后才执行后面的代码 if (www.error != null) //如果连接服务器出错,则显示出错的log信息 { Debug.Log(www.error); yield return null; } else if(www.error == null) { string s = www.text; string[] pos = s.Split(','); //按格式取出服务器发来的坐标 int x = int.Parse(pos[0]); if(x != -1) { int y = int.Parse(pos[1]); takechess.Bcoordinate = new Vector2(x, y); takechess.infotext.text = "在线..."; } else { takechess.infotext.text = "等待连接..."; } } } }
游戏的主逻辑TakeChess有很多实现方式,这个大家随便写一个就好了,到此,一个网络五子棋的基本网络功能部分就实现了。大家可以自己写一写试一下,如果过程中有问题可以QQ找我(1263415838)。