由于项目需要, 我需要通过 Java 开发的服务端对 C# 作为脚本语言开发的 unity 项目实现控制
话不多说, 直接上代码
首先, 我们先来构建服务端的代码, 服务端我们使用 Java 语言
import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* *@Description //TODO Socket 服务端$ *@Author 吾王剑锋所指 吾等心之所向 *@Date 2019/8/20 14:42 */ public class SocketServer { private static Logger LOGGER = LoggerFactory.getLogger(SocketServer.class); private static SocketServer instance = null; private boolean flag = true;public void start(){ new Thread(new SocketThread(), "socket server").start(); while (!flag) { try { Thread.sleep(1000); } catch (InterruptedException e) { LOGGER.error(e.getMessage(), e); } } } }
上面这段代码作为一个开关, 负责启动 socket 服务
接着, 我们来写一个线程, 负责在服务启动后监听 port 端口发来的连接请求
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.ServerSocket; import java.net.Socket; /* *@Description //TODO socket 通信线程$ *@Author 吾王剑锋所指 吾等心之所向 *@Date 2019/8/19 14:49 */ public class SocketThread implements Runnable { private static Logger LOGGER = LoggerFactory.getLogger(SocketThread.class); private static final Integer port = 5656; @Override public void run() { ServerSocket serverSocket = null; try{ serverSocket = new ServerSocket(port); LOGGER.info("socket server start, monitor 5656 port ! "); Socket socket = serverSocket.accept(); new SocketClientRequest(socket).start(); LOGGER.info("send success ! "); }catch (Exception ex){ LOGGER.error("send fail ! "); } try { Thread.sleep(5000); } catch (InterruptedException e) { LOGGER.error("Server delayed restart failed ! "); } } }
接着, 再写一个线程, 负责在监听到连接后, 接收客户端发来的信息和向客户端发送信息
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; /* *@Description //TODO socket 客户端请求线程$ *@Author 吾王剑锋所指 吾等心之所向 *@Date 2019/8/20 14:54 */ public class SocketClientRequest extends Thread{ private static Logger LOGGER = LoggerFactory.getLogger(SocketClientRequest.class); private int messageLengthBytes = 1024; public Socket socket; private BufferedInputStream bufferedInputStream = null; public SocketClientRequest(Socket socket) { this.socket = socket; } @Override public void run() { try { //获取socket中的数据 bufferedInputStream = new BufferedInputStream(socket.getInputStream()); byte[] clientCharStream = new byte[messageLengthBytes]; bufferedInputStream.read(clientCharStream); System.out.println(new String(clientCharStream, "utf-8")); OutputStream(socket); //发送信息到客户端 } catch (IOException e) { LOGGER.error("read massage error [{}]", e); } } /** * 向客户端发送指定信息 * */ private static void OutputStream(Socket socket) throws IOException { OutputStream out = socket.getOutputStream(); out.write(new String("welcome_send_server!").getBytes()); } }
到这里, socket 的服务端代码就搞定了, 接着, 我们来写客户端的代码
客户端我使用 unity 作为客户端程序, 所以用C#作为客户端的编程语言
因为知识做一个实验, 所以随随便便新建一个项目就行了
在文件夹处新建一个 script 文件夹, 用于保存程序文件, 然后在建两个C#文件, 双击打开
using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEngine; public class SocketUtils{ private static SocketUtils socketUtils = new SocketUtils(); private Socket socket; //单例模式 public static SocketUtils GetInstance() { return socketUtils; } private SocketUtils() { //采用TCP方式连接 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //服务器IP地址 IPAddress address = IPAddress.Parse("127.0.0.1"); //服务器端口 IPEndPoint endpoint = new IPEndPoint(address, 5566); //异步连接,连接成功调用connectCallback方法 IAsyncResult result = socket.BeginConnect(endpoint, new AsyncCallback(ConnectCallback), socket); //这里做一个超时的监测,当连接超过5秒还没成功表示超时 bool success = result.AsyncWaitHandle.WaitOne(5000, true); if (!success) { //超时 Closed(); Debug.Log("connect Time Out"); } else { //与socket建立连接成功,开启线程接受服务端数据。 Thread thread = new Thread(new ThreadStart(ReceiveSorket)); thread.IsBackground = true; thread.Start(); } } private void ConnectCallback(IAsyncResult asyncConnect) { Debug.Log("connect success"); } private void ReceiveSorket() { //在这个线程中接受服务器返回的数据 while (true) { if (!socket.Connected) { //与服务器断开连接跳出循环 Debug.Log("Failed to clientSocket server."); socket.Close(); break; } try { //接受数据保存至bytes当中 byte[] bytes = new byte[4096]; int i = socket.Receive(bytes); if (i <= 0) { socket.Close(); break; } Debug.Log(System.Text.Encoding.Default.GetString(bytes)); } catch (Exception e) { Debug.Log("Failed to clientSocket error." + e); socket.Close(); break; } } } //关闭Socket public void Closed() { if (socket != null && socket.Connected) { socket.Shutdown(SocketShutdown.Both); socket.Close(); } socket = null; } //向服务端发送一条字符 public void SendMessage(string str) { byte[] msg = Encoding.UTF8.GetBytes(str); if (!socket.Connected) { socket.Close(); return; } try { IAsyncResult asyncSend = socket.BeginSend(msg, 0, msg.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); bool success = asyncSend.AsyncWaitHandle.WaitOne(5000, true); if (!success) { socket.Close(); Debug.Log("Failed to SendMessage server."); } } catch { Debug.Log("send message error"); } } private void SendCallback(IAsyncResult asyncConnect) { Debug.Log("send success"); } }
然后是
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SocketMain : MonoBehaviour { void Start () { //创建socket连接 SocketUtils s = SocketUtils.GetInstance(); //发送信息向服务器端 s.SendMessage("啦啦啦"); } }
再将 SocketMain.cs 挂载到相机上
这样子, 服务端和客户端就简单的实现了 socket 连接
先启动服务端
socket 服务端启动成功, 接着启动客户端
客户端已经成功收到服务端发来的信息
服务端也接受到了客户端的信息
这样子, 一个简单的双工通讯就新建成功了
但是这样的系统还有很多问题没有解决,
例如: service 层要怎么调用 socket 实现主动控制服务端向客户端发送信息呢?
于是我决定使用netty来做一次升级, 因为netty的框架还提供了很多别的功能, 使得整个通讯系统变得更加的健壮,
详情跳转我的另一篇博文 https://www.cnblogs.com/unityworld/p/11425180.html