[經驗] Java 服務端 和 C# 客戶端 實現 Socket 通信


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM