Как отправлять и получать TCP-сообщения при потоковой передаче видео? (Unity и Socket Networking)

Мне удалось создать клиентское приложение TCP, которое передает потоковое видео на серверное приложение, используя Unity и сокеты, с помощью Programmer из этого ответа: /questions/2683877/unity-potokovoe-video/2683882#2683882

Теперь мне нужно при потоковой передаче видео отправить простое текстовое сообщение с сервера клиенту, которое заставляет клиента сразу же отправить ответное сообщение обратно на сервер.

Первая попытка почти всегда успешна, но во второй попытке ответное сообщение на сервер вызывает зависание видео, само сообщение повреждено, и я получаю следующее исключение: "System.OverflowException: Number overflow. At <0x00000> "

Это серверный скрипт:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System;
using UnityEngine.UI;
using System.IO;

public class MySocketsServer : MonoBehaviour {

    TcpListener listner;
    TcpClient client;
    NetworkStream stream;
    StreamWriter streamWriter;
    StreamReader streamReader;

    int port = 8010;
    int SEND_RECEIVE_COUNT = 15;

    bool getVideo = false;
    bool waitingForClient = false;
    bool serverConnected = false;
    bool clientConnected = false;

    private List<TcpClient> clients = new List<TcpClient>();

    WaitForEndOfFrame waitEndOfFrame = new WaitForEndOfFrame();
    WaitForFixedUpdate waitFixedUpdate = new WaitForFixedUpdate ();

    Texture2D tex;

    public RawImage serverRawImage; 

    public GameObject startServerUiBtn;
    public GameObject stopServerUiBtn;
    public GameObject startStopTrackingUiBtn;

    public Text startStopTrackingTxt;





    void Start(){
        Application.runInBackground = true;

        tex = new Texture2D(2, 2, TextureFormat.RGB24, false);
    }




    public void StartServer () {
        listner = new TcpListener(IPAddress.Any, port);
        client = new TcpClient ();

        listner.Start();

        serverConnected = true;

        Debug.Log ("Server conected! - IP = " + Network.player.ipAddress);
        UIDebugLog.VisableLog ("Server conected! - IP = " + Network.player.ipAddress);

        StartCoroutine (WaitForClient());

        startServerUiBtn.SetActive (false);

    }



    public void StopServer(){
        stopServerUiBtn.SetActive (false);
        startStopTrackingUiBtn.SetActive (false);
        serverConnected = false;
        getVideo = false;

        streamWriter.Close ();
        stream.Close ();
        client.Close ();

        foreach (TcpClient c in clients) {
            c.Close ();
        }

        if (listner != null)
        {
            listner.Stop();
        }

        startServerUiBtn.SetActive (true);

        serverRawImage.gameObject.SetActive (false);
    }



    private void OnApplicationQuit()
    {
        StopServer ();
    }





    IEnumerator WaitForClient()
    {

        clientConnected = false;
        waitingForClient = true;
        stopServerUiBtn.SetActive (true);

        // Wait for client to connect in another Thread 
        Loom.RunAsync(() =>
            {
                while (waitingForClient)
                {
                    // Wait for client connection
                    client = listner.AcceptTcpClient();
                    // We are connected
                    clients.Add(client);
                    clientConnected = true;
                }
            });

        //Wait until client has connected
        while (!clientConnected)
        {
            yield return null;
        }

        stream = client.GetStream ();

        streamWriter = new StreamWriter(stream);
        streamReader = new StreamReader(stream);

        streamWriter.AutoFlush = true;

        startStopTrackingUiBtn.SetActive (true);

        serverRawImage.gameObject.SetActive (true);

        Debug.Log("Client is Connected!");
        UIDebugLog.VisableLog("Client is Connected!");

        waitingForClient = false;

        getVideo = true;
        imageReceiver ();

    }


    int imageSize;
    void imageReceiver()
    {
        Loom.RunAsync(() =>
            {
                while (getVideo)
                {
                    //Read Image Count
                    imageSize = readImageByteSize(SEND_RECEIVE_COUNT);

                    //Read Image Bytes and Display it
                    readFrameByteArray(imageSize);
                }
            });
    }



    byte[] imageBytesCount;

    private int readImageByteSize(int size)
    {
        bool disconnected = false;

        try{

            imageBytesCount = new byte[size];
            var total = 0;
            do
            {
                var read = stream.Read(imageBytesCount, total, size - total);

                if (read == 0)
                {
                    disconnected = true;
                    break;
                }
                total += read;
            } while (total != size);

        }catch(Exception e){
            Debug.Log ("readImageByteSize() error: " + e);
            disconnected = true;
        }

        if (disconnected)
        {
            return -1;
        }
        else
        {
            return frameByteArrayToByteLength(imageBytesCount);
        }

    }


    //Converts the byte array to the data size and returns the result
    int frameByteArrayToByteLength(byte[] frameBytesLength)
    {
        return BitConverter.ToInt32(frameBytesLength, 0);
    }


    byte[] imageBytes;

    private void readFrameByteArray(int size)
    {
        try{

            bool disconnected = false;

            imageBytes = new byte[size];
            var total = 0;
            do
            {
                var read = stream.Read(imageBytes, total, size - total);

                if (read == 0)
                {
                    disconnected = true;
                    break;
                }
                total += read;
            } while (total != size);

        bool readyToReadAgain = false;

        if (!disconnected)
        {
            //Display Image on the main Thread
            Loom.QueueOnMainThread(() =>
                {
                    displayReceivedImage(imageBytes);
                    readyToReadAgain = true;
                });
        }

        //Wait until old Image is displayed
        while (!readyToReadAgain)
        {
            System.Threading.Thread.Sleep(1);
        }

        }catch(Exception e){
            Debug.Log ("readFrameByteArray() error: " + e);
        }
    }


    void displayReceivedImage(byte[] receivedImageBytes)
    {
        tex.LoadImage(receivedImageBytes);
        serverRawImage.texture = tex;
    }





    bool waitingForMsgCallback = false;

    public void SendMsgToTheClient(){
        try{
            // Stop recieving video for a moment:
            getVideo = false;

            // Start listenung to the callback:
            waitingForMsgCallback = true;
            StartCoroutine (RecieveMsgCallback());

            // send the msg:
            streamWriter.WriteLine ("msg_from_the_server");

            Debug.Log("msg_from_the_server sended");
            UIDebugLog.VisableLog("msg_from_the_server sended");

        }catch(Exception e){
            Debug.Log("SendMsgToTheClient() error: " + e);
        }
    }


    IEnumerator RecieveMsgCallback(){
        while (waitingForMsgCallback) {
            try{
                if (stream.DataAvailable) {
                    // get the callback msg:
                    string callbackMsg = streamReader.ReadLine ();

                    Debug.Log ("Recieved msg Callback: " + callbackMsg);
                    UIDebugLog.VisableLog ("Recieved msg Callback: " + callbackMsg);

                    waitingForMsgCallback = false;

                    // Continue receiving video:
                    getVideo = true;
                    imageReceiver ();
                }
            }catch(Exception e){
                Debug.Log("RecieveStartTrackingCallback() error: " + e);
            }

            yield return waitFixedUpdate;
        }
    }


}

И клиентский скрипт:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Text;
using System.Net;
using UnityEngine.UI;
using System;
using System.IO;


public class MySocketsClient : MonoBehaviour {

    TcpClient client;
    NetworkStream stream;
    StreamWriter streamWriter;
    StreamReader streamReader;

    int port = 8010;
    int SEND_RECEIVE_COUNT = 15;

    string IP = "127.0.0.1";

    bool connected = false;
    bool sendingVideo = false;
    bool waitingForMsgFromServer = false;

    WebCamTexture webCam;

    public RawImage clientRawImage;

    Texture2D currentTexture;

    WaitForEndOfFrame waitEndOfFrame = new WaitForEndOfFrame();
    WaitForFixedUpdate waitFixedUpdate = new WaitForFixedUpdate();

    public GameObject StartClientUiBtn;
    public GameObject StopClientUIBtn;

    public InputField ipField;

    Rect captureRect;




    void Start () {
        Application.runInBackground = true;

        if (PlayerPrefs.GetString ("server_address") != "") {
            IP = PlayerPrefs.GetString ("server_address");
            ipField.text = IP;
        }
        captureRect = new Rect (0, 0, Screen.width, Screen.height);

        InitWebCam();

        currentTexture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
        frameBytesLength = new byte[SEND_RECEIVE_COUNT];
    }


    public void StartClientBtn(){
        if (IP == "") {
            Debug.Log ("Please enter an ip address");
            return;
        }
        StartCoroutine (StartClient());
        StartClientUiBtn.SetActive (false);
    }


    IEnumerator StartClient(){

        client = new TcpClient();
        StopClientUIBtn.SetActive (true);

        //Connect to server from another Thread
        Loom.RunAsync(() =>
            {
                Debug.Log("Connecting to server...");

                IPAddress ipaddress = IPAddress.Parse(IP);
                client.Connect(ipaddress, port);

                Debug.Log("Connected!");

                connected = true;
            });

        while (!connected) {
            yield return null;
        }

        stream = client.GetStream();

        streamWriter = new StreamWriter(stream);
        streamReader = new StreamReader(stream);

        streamWriter.AutoFlush = true;

        //Start sending video:
        sendingVideo = true;
        StartCoroutine(senderCOR());

        //Start listening to msg from the server:
        waitingForMsgFromServer = true;
        StartCoroutine(RecieveServerMsg());
    }


    public void StopClient(){
        StopClientUIBtn.SetActive (false);
        connected = false;
        sendingVideo = false;

        streamReader.Close ();
        streamWriter.Close ();
        stream.Close ();


        if (client != null)
        {
            client.Close();
        }

        if (webCam != null && webCam.isPlaying)
        {
            webCam.Stop();
        }

        StartClientUiBtn.SetActive (true);
    }


    void OnApplicationQuit()
    {
        StopClient ();
    }



    public void OnChangeAddress(){
        IP = ipField.text;
        PlayerPrefs.SetString ("server_address", IP);
    }




    void InitWebCam(){

        webCam = new WebCamTexture();

        webCam.requestedHeight = 10;
        webCam.requestedWidth = 10;

        clientRawImage.texture = webCam;

        webCam.Play();
    }





    bool readyToGetFrame = false;
    byte[] frameBytesLength;
    byte[] jpgBytes;

    IEnumerator senderCOR()
    {
        readyToGetFrame = true;

        while (sendingVideo)
        {
            //Wait for End of frame
            yield return waitEndOfFrame;

            currentTexture.ReadPixels (captureRect , 0, 0);

            currentTexture.Apply();

            jpgBytes = currentTexture.EncodeToJPG(12);

            //Fill total byte length to send. Result is stored in frameBytesLength
            byteLengthToFrameByteArray(jpgBytes.Length, frameBytesLength);

            readyToGetFrame = false;

            try{
            Loom.RunAsync(() =>
                {
                    //NetworkStream videoStream = client.GetStream();

                    //Send total byte count first
                    stream.Write(frameBytesLength, 0, frameBytesLength.Length);

                    //Send the image bytes
                    stream.Write(jpgBytes, 0, jpgBytes.Length);

                    //Sent. Set readyToGetFrame true
                    readyToGetFrame = true;
                });
            }catch(Exception e){
                Debug.Log ("senderCOR() error: " + e.Message);
                readyToGetFrame = true;
            }
            //Wait until we are ready to get new frame(Until we are done sending data)
            while (!readyToGetFrame)
            {
                yield return null;
            }
        }
    }


    //Converts the data size to byte array and put result to the fullBytes array
    void byteLengthToFrameByteArray(int byteLength, byte[] fullBytes)
    {
        //Clear old data
        Array.Clear(fullBytes, 0, fullBytes.Length);
        //Convert int to bytes
        byte[] bytesToSendCount = BitConverter.GetBytes(byteLength);
        //Copy result to fullBytes
        bytesToSendCount.CopyTo(fullBytes, 0);
    }




    IEnumerator RecieveServerMsg(){
        while (waitingForMsgFromServer) {
            try{
                if (stream.DataAvailable) {
                    // read the msg from the server:
                    string msg = streamReader.ReadLine ();
                    UIDebugLog.VisableLog ("ReadStartTrackingMsg: " + msg);

                    // send a msg callback to the server:
                    streamWriter.WriteLine ("Callback Message from the client");
                    UIDebugLog.VisableLog ("callback sended...");
                    }
            }catch(Exception e){
                Debug.Log ("ReadStartTrackingMsg() error: " + e.Message);
            }
            yield return waitFixedUpdate;
            yield return waitEndOfFrame;
        }
    }

}

Конечное клиентское приложение должно работать на Android, а серверное приложение - на ПК. Я тестировал оба и получил одинаковые результаты.

Любой совет будет наиболее ценным

Спасибо!

0 ответов

Другие вопросы по тегам