由於項目需要, 我需要通過 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