您的位置:首页 > 理论基础 > 计算机网络

Unity: C# TCP Client Server TcpListener NetworkStream UDP

2016-03-10 14:52 615 查看
from: https://gist.github.com/anselm/c92efb677d8cbbe23d4e
/*

Some scratch code for testing a variety of patterns of client server connection.

I needed to send data from an android phone to a macbook via USB and I happened to be using C# under Unity 3D. Some of the problems I ran into included:

- co-routines under unity were not fully exhausting the tcp buffers fast enough i think; even when I aggressively polled until they were empty...

- kept running into a curious bug where when the android device overheated that there would be a huge latency in traffic from the android device to the desktop.

- ran into a problem where the fake TCP port forwarding accomplished by "sdk/platform-tools/adb forward tcp:1234 tcp:1234" was not letting the android device be anything other than a host... and wouldn't let me ship UDP packets either.

- there's a lot of bad advice out there; for example the android emulator does offer an IP for the host but a real device does not. And it's a hassle to setup a real route back to the host - even with netcat and the like...  for example usb0 doesn't even appear as a device and I don't feel like adding it...

It was easiest to ask for each packet one by one... to throttle the traffic rate... this was "good enough" for me. Once I was comfortable with that I then let the android end go ahead and just send at a fixed rate... although the overheating problem was still present in all cases. In my mind many of these issues must have something to do with the fake TCP over USB bridge.

*/

-------------------------------------------------------------------------------------------------------------------------------
myserver.cs
-------------------------------------------------------------------------------------------------------------------------------

using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System;

public class MyServer : MonoBehaviour {

static float x=0,y=0,z=0,qx=0,qy=0,qz=0,qw=1;

void Start () {
Application.targetFrameRate = 30;
Screen.sleepTimeout = 0;
TCPStart(0);
}

void OnDisable() {
stop = true;
TCPStop();
}

void Update () {

x = transform.position.x;
y = transform.position.y;
z = transform.position.z;
qx = transform.rotation.x;
qy = transform.rotation.y;
qz = transform.rotation.z;
qw = transform.rotation.w;
tick++;

if(style == -1) TCPSpeak();
}

void OnGUI () {
var style = new GUIStyle("label");
style.fontSize = 50;
GUI.color = Color.yellow;
GUI.Label (new Rect(10,400,1200,50), "t="+ms, style);
GUI.Label (new Rect (10, 500, 1200, 50), "x=" + x, style);
GUI.Label (new Rect (10, 550, 1200, 50), "y=" + y, style);
GUI.Label (new Rect (10, 600, 1200, 50), "z=" + z, style);
}

// --------------------------------------------------------------------------------------------

static IPEndPoint p = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234);
static UdpClient u = null;
static TcpClient c = null;
static NetworkStream s;
static TcpListener l = null;
static long msr=0,ms=0,ms2=0;
static byte[] buf = new byte[1024];
static bool stop = false;
static int tick=0,lasttick=0;
static int style = -1; // -1 = send on update, 0 = send update requests every 33ms, 1 or 2 = send update requests when asked
static bool pending = false;
static bool host = true;
static bool isandroiddevice = true;

static void TCPStop() {
if(s!=null) s.Close(); s = null;
if(c!=null) c.Close(); c = null;
if(u!=null) u.Close(); u = null;
if(l!=null) l.Stop(); l = null;
}

static void TCPStart(int delay = 1000) {
if(stop) return;
TCPStop();
if(delay>0) System.Threading.Thread.Sleep(delay);
Debug.Log("(re)starting");
TCPHost(); // else TCPClient();
}

static void TCPHost() {
try {
l = new TcpListener(p);
l.Start();
l.BeginAcceptTcpClient(TCPHostAccept,l);
} catch (Exception e) {
Debug.Log("Error..... " + e.StackTrace);
TCPStart();
return;
}
//u = new UdpClient(p);
//u.BeginReceive(new System.AsyncCallback(UDPCallback),u);
//Debug.Log ("UDP Started");
}

static void TCPHostAccept(IAsyncResult state) {
if(stop)return;
try {
c = l.EndAcceptTcpClient(state);
} catch(Exception e) {
Debug.Log ("Error..." + e );
TCPStart();
return;
}
TCPAccept();
}

static void TCPClient() {
if(stop)return;
try {
c = new TcpClient();
c.Connect(p);
} catch(Exception e) {
Debug.Log ("Error..." + e );
TCPStart();
return;
}
TCPAccept();
}

static void TCPAccept() {
if(stop)return;
Debug.Log("Got a connection");
c.NoDelay = true;
c.SendBufferSize = 512;
c.ReceiveBufferSize = 512;
s = c.GetStream();
//c.ReceiveTimeout = 1;
//s.ReadTimeout = 100;
tick = lasttick = 0;
pending = false;
TCPListen();
if(style==0 && isandroiddevice)TCPSpeak();
}

// -----------------------------------------------------------------------------------

static void TCPListen() {
if(stop) return;
try {
s.BeginRead(buf,0,buf.Length,new AsyncCallback(TCPListened),s);
} catch(Exception e) {
Debug.Log("Error... " + e);
TCPStart();
return;
}
}

static void TCPListened(IAsyncResult state) {
if(stop) return;
int len = 0;
try {
len = s.EndRead(state);
}  catch(Exception e) {
Debug.Log("Error... " + e);
TCPStart();
return;
}
TCPListen();
if(style==1 || style==2) TCPSpeak(); // in a call response pattern we respond only when asked
}

// -----------------------------------------------------------------------------------

static void TCPSpeak() {
if(stop) { Debug.Log ("Asked to stop"); return; }
if(s == null) { Debug.Log ("No connection"); return; }
//if(pending) { Debug.Log ("Pending"); return; } // it is possible that there could be multiple calls outstanding - ignore overlapping calls
try {
long ms = DateTime.UtcNow.Ticks;
string msg = x + " " + y + " " + z + " " + qx + " " + qy + " " + qz + " " + qw + " " + ms + " " + tick;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(msg);
s.BeginWrite(bytes,0,bytes.Length,new AsyncCallback(TCPSpoke),s);
pending = true;
} catch(Exception e) {
Debug.Log ("Error..." + e );
TCPStart();
return;
}
}

static void TCPSpoke(IAsyncResult state) {
if(stop)return;
try {
s.EndWrite(state);
pending = false;
} catch(Exception e) {
Debug.Log ("Error..." + e );
TCPStart();
return;
}
if(style==0) {
System.Threading.Thread.Sleep(33);
TCPSpeak();
}
}

// ----------------------------------------------------------------------------------------------------

static void UDPSend() {
if(stop)return;
try {
string msg = x + " " + y + " " + z + " " + qx + " " + qy + " " + qz + " " + qw + " " + ms;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(msg);
u.BeginSend(bytes,bytes.Length,p,UDPDone,s);
//u.Send(bytes,bytes.Length);
} catch (Exception e ) {
Debug.Log ("UDP Socket failed to send data " + e);
}
}

static void UDPDone(System.IAsyncResult ar) {
if(stop)return;
try {
u.EndSend(ar);
// xxx could send again here right now...
} catch(Exception e) {
Debug.Log ("failed " + e);
}
}

}

-------------------------------------------------------------------------------------------------------------------------------
myclient.cs
-------------------------------------------------------------------------------------------------------------------------------

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

public class MyClient : MonoBehaviour {

public GameObject target;
static float x=0,y=0,z=0,qx=0,qy=0,qz=0,qw=1;

public void Start() {
Application.targetFrameRate = 60;
TCPStart(0);
}

public void OnDisable() {
stop = true;
TCPStop();
}

public void Update() {
if(TCPUpdated()) {
target.transform.position = new Vector3(x,y,z);
target.transform.rotation = new Quaternion(qx,qy,qz,qw);
}
}

// --------------------------------------------------------------------------
static IPEndPoint p = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234);
static UdpClient u = null;
static TcpClient c = null;
static NetworkStream s;
static TcpListener l = null;
static long msr=0,ms=0,ms2=0;
static byte[] buf = new byte[1024];
static bool stop = false;
static int tick=0,lasttick=0;
static int style = -1; // -1 / 0 = just listen for updates, 1 = ask for updates manually, 2 = ask for updates automatically
static bool pending = false;
static bool isandroiddevice = false;

static bool TCPUpdated() {
if(style == 1) TCPAsk(); // make a manual request; can do this as often as we wish - overlapping requests blocked in tcpask()
if(tick > lasttick) {
// for all modes we want to return true if we have new data: ticks > lasttick...
lasttick = tick;
return true;
}
return false;
}

static void TCPStop() {
if(s!=null) s.Close(); s = null;
if(c!=null) c.Close(); c = null;
if(u!=null) u.Close(); u = null;
if(l!=null) l.Stop(); l = null;
}

static void TCPStart(int delay = 1000) {
if(stop) return;
TCPStop();
if(delay>0) System.Threading.Thread.Sleep(delay);
Debug.Log("(re)starting");
TCPClient();
}

static void TCPHost() {
try {
l = new TcpListener(p);
l.Start();
l.BeginAcceptTcpClient(TCPHostAccept,l);
} catch (Exception e) {
Debug.Log("Error..... " + e.StackTrace);
TCPStart();
return;
}
//u = new UdpClient(p);
//u.BeginReceive(new System.AsyncCallback(UDPCallback),u);
//Debug.Log ("UDP Started");
}

static void TCPHostAccept(IAsyncResult state) {
if(stop)return;
try {
c = l.EndAcceptTcpClient(state);
} catch(Exception e) {
Debug.Log ("Error..." + e );
TCPStart();
return;
}
TCPAccept();
}

static void TCPClient() {
if(stop)return;
try {
c = new TcpClient();
c.Connect(p);
} catch(Exception e) {
Debug.Log ("Error..." + e );
TCPStart();
return;
}
TCPAccept();
}

static void TCPAccept() {
if(stop)return;
Debug.Log("Got a connection");
c.NoDelay = true;
c.SendBufferSize = 512;
c.ReceiveBufferSize = 512;
s = c.GetStream();
//c.ReceiveTimeout = 1;
//s.ReadTimeout = 100;
tick = lasttick = 0;
pending = false;
TCPListen();
if(style==2 && !isandroiddevice)TCPAsk(); // on other devices it is our job to ask for data in some modes
}

// -----------------------------------------------------------------------------------

static void TCPListen() {
if(stop) return;
try {
s.BeginRead(buf,0,buf.Length,new AsyncCallback(TCPListened),s);
} catch(Exception e) {
Debug.Log("Error... " + e);
TCPStart();
return;
}
}

static void TCPListened(IAsyncResult state) {
if(stop) return;
int len = 0;
try {
len = s.EndRead(state);
}  catch(Exception e) {
Debug.Log("Error... " + e);
TCPStart();
return;
}

string str = Encoding.UTF8.GetString(buf,0,len);
string[] args = str.Split(' ');
if(args.Length >= 8) {
x = float.Parse(args[0]);
y = float.Parse(args[1]);
z = float.Parse(args[2]);
qx = float.Parse(args[3]);
qy = float.Parse(args[4]);
qz = float.Parse(args[5]);
qw = float.Parse(args[6]);
msr = long.Parse (args[7]); // the time on REMOTE end
ms2 = DateTime.UtcNow.Ticks;
if((tick&31)==0) {
Debug.Log ("Step="+tick+" msr="+msr+" ms="+ms+" delta="+(msr-ms)+" mydelta="+(ms2-ms)+" x="+x+" y="+y+" z="+z);
}
}
tick++;
TCPListen(); // listen again - this should be the only place that restarts listening other than bootup
}

// -----------------------------------------------------------------------------------

static void TCPAsk() {
if(stop) return;
if(pending) return; // TODO technically this should be a synchronous block but I expect 33ms between these tests
if(s==null) return;
try {
byte[] bytes = System.Text.Encoding.UTF8.GetBytes("" + DateTime.UtcNow.Ticks);
s.BeginWrite(bytes,0,bytes.Length,new AsyncCallback(TCPAsked),s);
pending = true;
} catch(Exception e) {
Debug.Log("Error... " + e);
TCPStart();
return;
}
}

static void TCPAsked(IAsyncResult state) {
if(stop) return;
try {
s.EndWrite(state);
pending = false;
} catch(Exception e) {
Debug.Log("Error... " + e);
TCPStart();
return;
}
if(style == 2) {
System.Threading.Thread.Sleep(33);
TCPAsk(); // for automatical mode get a fresh update but not too often
}
}

// ---------------------------------------------------------------------------------------

public static void UDPCallback(System.IAsyncResult ar) {
if(stop) return;
try {
byte[] receiveBytes = u.EndReceive(ar, ref p);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
u.BeginReceive(new System.AsyncCallback(UDPCallback),ar);
Debug.Log("Received: " +  receiveString);
} catch (System.Exception send_exception ) {
Debug.Log ("UDP Socket failed to receive");
}
}

}

--------------------------------------------------------------------------------------------------------
tcpclient.java - just another way to test
--------------------------------------------------------------------------------------------------------

import java.io.*;
import java.net.*;

class TCPClient {
public static void main(String argv[]) throws Exception {
Socket socket = new Socket("127.0.0.1", 1235);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true) {
String data = reader.readLine();
if(data != null) System.out.println(data);
}
}
}

--------------------------------------------------------------------------------------------------------
tcpserver.java - just another way to test
--------------------------------------------------------------------------------------------------------

import java.io.*;
import java.net.*;

class TCPServer
{
public static void main(String argv[]) throws Exception
{
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(1235);

while(true)
{
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
System.out.println("Received: " + clientSentence);
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: