我设法创建了一个TCP客户端应用程序,在此答案的Programmer的帮助下,使用Unity和套接字将视频流式传输到服务器应用程序:https://stackoverflow.com/a/42727918/8713780
现在,我需要在流式传输视频时,将简单的文本消息从服务器发送到客户端,这会触发客户端立即将响应消息发送回服务器。
第一次尝试几乎总是成功,但在第二次尝试时,响应消息到服务器导致视频卡住,消息本身已损坏,我得到此异常:" System.OverflowException:Number溢出。 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上运行,服务器应用程序应该在PC上运行。我已对两者进行了测试并获得了相同的结果。
任何建议都将受到赞赏
谢谢!