2010年8月11日 星期三

Unity 3D Client/Server Socket Connection Sample Code


版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!
Welcome to link to this blog when referencing the article!

I'v been looking everywhere to find a socket connection sample code for Unity 3D. Although there are many sites/blogs pointed out some feature, but not a sample in whole can be found. Finally, I put some resources that I found and came out this sample. Hope those people who are looking for the answer can get one step further via this article.

You can use .net sockets to connect between Unity and socket-based applications. Furthermore, you can use most of the .net 2.0 API. If you happen to have a Unity Pro, you can write your own C++ Dlls, be noted, for the security reason, C++ Dlls can't be used with Web Player.

.NET Sockets is kind of TCP/IP Sockets. Existing network class of .NET, ex: TcpClient(client side) and TcpListener(server side), they include socket other feature support, and are easier then using Socket directly.

Below is a simple implementation. There are 2 parts: server side and client side. Server side is the Server side TcpListener code listed below. Just compile it and run it to wait for the connection. The Server was a sample code from MSDN, it can handle one Client connection at a time. As an example to make the socket connection work is enough. I'll keep on working on a simple server code that can handle multiple clients. Wish I can get it in the near future.

To do the client in the Unity, you can create a new Project, then create a JavaScript and rename to GUI_Script, copy and past the code in 'GUI_Scripts.js' listed below. When you finish this step, press left key to grab "CUI_Script" inside Unity/Project sub-window and drop on the "Main Camera" object inside Hierarchy sub-window, the script can then be attached to the Camera, you can then see the GUI when running the game. We then create a folder in the Unity/Project sub-window and rename to "Standard Assets", create a C# Script, rename it to "s_TCP", copy and past the code in the 's_TCP.cs' below. Now, run the unity game, you can try the result now.

Client side C# TCP script is attach to a GUI JavaScript. The GUI JavaScript contains a "Connect" button, a "Level 1" button, and a "Level 2" button; a text field and a "Disconnect" button. In the beginning of the game running, there is only one "Connect" button display on the screen; after the player press the button, the Unity game client will connect to the Server and establish a socket connection. The "Connect" button disappear, and the "Level 1", "Level 2" button, text filed, and "Disconnect" button show up. Whenever press the "Level 1" or "Level 2" button, the text field will use WriteSocket() function in the GUI JavaScript to send the preset string to the server, the server will then convert the lower case text to upper case text and send the result string to the client. The GUI JavaScript will then use the ReadSocket() function to read the return string and display in the text field. If you press the "Disconnect" button, the connection will be closed and the screen will change back to display "Connect" button only.



====================================================

Code listed below is for Server side TcpListener:

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

class MyTcpListener
{
  public static void Main()
  { 
    TcpListener server=null;   
    try
    {
      // Set the TcpListener on port 13000.
      Int32 port = 13000;
      IPAddress localAddr = IPAddress.Parse("127.0.0.1");
      
      // TcpListener server = new TcpListener(port);
      server = new TcpListener(localAddr, port);

      // Start listening for client requests.
      server.Start();
         
      // Buffer for reading data
      Byte[] bytes = new Byte[256];
      String data = null;
      int counter = 0;


      // Enter the listening loop.
      while(true) 
      {
        Console.Write("Waiting for a connection... ");
        
        // Perform a blocking call to accept requests.
        // You could also user server.AcceptSocket() here.
        TcpClient client = server.AcceptTcpClient();
        counter++;
        Console.WriteLine("#"+counter+" Connected!");

        data = null;

        // Get a stream object for reading and writing
        NetworkStream stream = client.GetStream();

        int i;

        // Loop to receive all the data sent by the client.
        while((i = stream.Read(bytes, 0, bytes.Length))!=0) 
        {   
          // Translate data bytes to a ASCII string.
          data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
          Console.WriteLine("Received: {0}", data + counter);
       
          // Process the data sent by the client.
          data = data.ToUpper();

          byte[] msg = System.Text.Encoding.ASCII.GetBytes(data+"Client counter:"+counter);

          // Send back a response.
          stream.Write(msg, 0, msg.Length);
          Console.WriteLine("Sent: {0}", data + "Client counter:"+counter);            
        }
         
        // Shutdown and end connection
        client.Close();
      }
    }
    catch(SocketException e)
    {
      Console.WriteLine("SocketException: {0}", e);
    }
    finally
    {
       // Stop listening for new clients.
       server.Stop();
    }

      
    Console.WriteLine("\nHit enter to continue...");
    Console.Read();
  }   
}


====================================================

Code listed below is a C# TCP program 's_TCP.cs', which was graped from Unity Forum and made some modification:

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

public class s_TCP : 
MonoBehaviour {
    bool socketReady = false;

    TcpClient mySocket;
    NetworkStream theStream;
    StreamWriter theWriter;
    StreamReader theReader;
    String Host = "localhost";
    Int32 Port = 13000; 

    // Use this for initialization
    void Start() {

    }

    // Update is called once per frame
    void Update() {

    }

    public void setupSocket() {
        try {
            mySocket = new TcpClient(Host, Port);
            theStream = mySocket.GetStream();
            theWriter = new StreamWriter(theStream);
            theReader = new StreamReader(theStream);
            socketReady = true;
        }
        catch (Exception e) {
            Debug.Log("Socket error:" + e);
        }
    }

    public void writeSocket(string theLine) {
        if (!socketReady)
            return;
  String tmpString = theLine + "\r\n";
        theWriter.Write(tmpString);
        theWriter.Flush();
    }

    public String readSocket() {
        if (!socketReady)
            return "";
        if (theStream.DataAvailable)
            return theReader.ReadLine();
        return "";
    }

    public void closeSocket() {
        if (!socketReady)
            return;
        theWriter.Close();
        theReader.Close();
        mySocket.Close();
        socketReady = false;
    }
 
    public void maintainConnection(){
 if(!theStream.CanRead) {
  setupSocket();
 }
    }
} // end class s_TCP

====================================================

This is a JavaScript 'GUI_Scripts.js':

private var textFieldString = "Socket Testing String";
private var myTCP; 

function Awake() {
 myTCP = gameObject.AddComponent(s_TCP);
}

function OnGUI () {
 if(myTCP.socketReady==false) {
  if (GUI.Button (Rect (20,10,80,20),"Connect")) {
   myTCP.setupSocket();
  }
 }
 else {
  myTCP.maintainConnection();

  if (GUI.Button (Rect (20,40,80,20), "Level 1")) {
   myTCP.writeSocket(" The is from Level 1 Button");
   textFieldString=myTCP.readSocket();
  }
  if (GUI.Button (Rect (20,70,80,20), "Level 2")) {
   myTCP.writeSocket(" The is from Level 2 Button");
   textFieldString=myTCP.readSocket();
  }
  
  textFieldString = GUI.TextField (Rect (25, 100, 300, 30), textFieldString);
  
  if (GUI.Button (Rect (20,140,80,20),"Disconnect")) {
   myTCP.closeSocket();
   textFieldString = "Socket Disconnected...";
  }
 }
}

版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!
Welcome to link to this blog when reference the article!

7 則留言:

  1. i tried second script.connected. But not getting value

    回覆刪除
  2. Hi,感謝版主的分享,但我有些關於Unity 2d課程上的問題,希望版主不吝賜教:
    主要是TexturePackerGUI只是8天的試用版,可有一些如GIMP等的開源軟件可用,或是直接用GIMP,其方法版主可知道呢?
    因為我是新手,希望您能在這方面指教一下。

    回覆刪除
  3. Hi,
    I am new to the development.
    I am trying to build a client/server application in C#.
    I am using the same sample which you posted in this post.
    But I want to send and receive floating point data instead of string.
    Please suggest me how could i achieve this?

    回覆刪除
    回覆
    1. Use:
      float f;
      if( float.TryPars(string serverMessage, out f) )
      .....

      BR

      刪除
    2. Sorry, i don't see where i have to write that to achieve sending and receiving float data type, can you be more specific please?

      刪除
  4. I wanted to send flight data from server application(i.e, from TcpListener) to my unity application. I have used the same code for TcpListener,s_TCP.cs and GUI_Scripts.js
    It is working fine. to send and receive my flight data what changes do i need to do in this code? please suggest me.

    回覆刪除
  5. Hello there, thanks for awesome post, it made my day for those who get unknown identifier 's_TCP' change
    myTCP = gameObject.AddComponent(s_TCP);
    to
    myTCP = gameObject.AddComponent("s_TCP");

    and if you get visual studio error about putting ';' remove private fileds from first to var in js file
    those were error I got on Unity 5.3.6...

    回覆刪除