├── .gitignore ├── README.md └── networking-with-protobuf-example ├── NetWorking.cs ├── README.md ├── server.py └── utest.proto /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | *.swp 3 | *.pyc 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## A Collections of useful Scripts/Examples for Unity3d 2 | 3 | #### networking-with-protobuf-example 4 | 5 | An example to show how to using C# socket in Unity3d. 6 | And How to using Google Protobuf to serialize data. 7 | 8 | The Example server was written in Python. -------------------------------------------------------------------------------- /networking-with-protobuf-example/NetWorking.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | using System; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | 8 | using Google.ProtocolBuffers; 9 | 10 | /* This is a demo, to show how to using Socket in Unity3d 11 | * and how to serialize data with Google protobuf. 12 | * So, Do not care about the logic. 13 | */ 14 | 15 | 16 | public class NetWorking : MonoBehaviour { 17 | public string ip = "192.168.137.98"; 18 | public int port = 8888; 19 | 20 | private Socket socket; 21 | private bool connected = false; 22 | 23 | // for test 24 | private int id = 1; 25 | 26 | 27 | // Use this for initialization 28 | void Start () { 29 | IPAddress ipAddress = IPAddress.Parse(ip); 30 | socket = new Socket( 31 | AddressFamily.InterNetwork, 32 | SocketType.Stream, 33 | ProtocolType.Tcp 34 | ); 35 | 36 | try { 37 | socket.Connect(new IPEndPoint(ipAddress, port)); 38 | // In my test, Connect method NEVER thrown an exception even 39 | // there were wrong ip, port. 40 | // So, for determine whether we have connected to the server 41 | // we must do some IO opprate. means send and recv. 42 | // Actually, There is necessary send data here, 43 | // For verification or something else 44 | 45 | byte[] data = PackData(id++); 46 | SockSend(data); 47 | 48 | byte[] recv = SockRecv(); 49 | 50 | CodeBattle.Marine marine = CodeBattle.Marine.ParseFrom(recv); 51 | print (marine); 52 | connected = true; 53 | } 54 | catch { 55 | print("NewWorking NOT work!"); 56 | } 57 | } 58 | 59 | // Update is called once per frame 60 | void Update () { 61 | if(!connected) return; 62 | 63 | // Wating for Param#1 Microseconds to check is there any data send from server. 64 | // 1 second == 1000 Millisecond == 1000 * 1000 Microseconds 65 | if( socket.Poll(10000, SelectMode.SelectRead) ) { 66 | try { 67 | byte[] data = SockRecv(); 68 | CodedInputStream stream = CodedInputStream.CreateInstance(data); 69 | CodeBattle.Marine marine = CodeBattle.Marine.ParseFrom(stream); 70 | print ("Receive: " + marine); 71 | } 72 | catch (Exception e) { 73 | print(e); 74 | connected = false; 75 | return; 76 | } 77 | } 78 | 79 | if(Input.GetKeyDown(KeyCode.A)) { 80 | byte[] data = PackData(id++); 81 | try { 82 | SockSend(data); 83 | } 84 | catch { 85 | print ("Socket Send Error"); 86 | } 87 | } 88 | } 89 | 90 | 91 | 92 | void SockSend (byte[] data) { 93 | socket.Send(data, data.Length, SocketFlags.None); 94 | } 95 | 96 | byte[] SockRecv () { 97 | byte[] lenBytes = new byte[4]; 98 | int rec = socket.Receive(lenBytes, 4, SocketFlags.None); 99 | if (rec == 0) { 100 | throw new Exception("Remote Closed the connection"); 101 | } 102 | 103 | int len = IPAddress.NetworkToHostOrder( BitConverter.ToInt32(lenBytes, 0) ); 104 | byte[] data = new byte[len]; 105 | rec = socket.Receive(data, len, SocketFlags.None); 106 | if (rec == 0) { 107 | throw new Exception("Remote Closed the connection"); 108 | } 109 | return data; 110 | } 111 | 112 | 113 | 114 | byte[] PackData (int id) { 115 | CodeBattle.Marine.Builder marineBuilder = new CodeBattle.Marine.Builder(); 116 | CodeBattle.Position.Builder positionBuilder = new CodeBattle.Position.Builder(); 117 | 118 | marineBuilder.Id = id; 119 | marineBuilder.Hp = 99; 120 | 121 | positionBuilder.X = 1; 122 | positionBuilder.Y = 2; 123 | positionBuilder.Z = 3; 124 | 125 | marineBuilder.Position = positionBuilder.BuildPartial(); 126 | 127 | CodeBattle.Marine marine = marineBuilder.BuildPartial(); 128 | 129 | byte[] buffer = new byte[marine.SerializedSize]; 130 | CodedOutputStream stream = CodedOutputStream.CreateInstance(buffer); 131 | marine.WriteTo(stream); 132 | 133 | byte[] binary = new byte[buffer.Length + 4]; 134 | 135 | int len = IPAddress.HostToNetworkOrder( buffer.Length ); 136 | byte[] lenBytes = BitConverter.GetBytes(len); 137 | lenBytes.CopyTo(binary, 0); 138 | buffer.CopyTo(binary, 4); 139 | 140 | return binary; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /networking-with-protobuf-example/README.md: -------------------------------------------------------------------------------- 1 | ## How to Compile proto 2 | 3 | We need the same proto file for server side and client side (unity3d). 4 | 5 | At server side, you can choose any language. C++, Java, Python, Ruby, Nodejs, Erlang, Or whatever you like. 6 | 7 | There are two implemention of Proto For .NET. As methoned above, You'd better keep the proto file in same at server/client both side. 8 | 9 | So, using http://code.google.com/p/protobuf-csharp-port/ . 10 | It using the origin format to define proto message. This can be compatible with any languages. 11 | 12 | 1. Define your proto. 13 | 2. Compile it for server/client both side 14 | * Server side. It's depends what language you are using. 15 | 16 | For example, Python: 17 | 18 | protoc --python_out=. 19 | * Client side. 20 | 21 | protoc --descriptor_set_out=msg.protobin --include_imports msg.proto 22 | protogen msg.protobin 23 | 24 | then you will get a `msg.cs` file, copy it in you unity3d protject's assert folder. 25 | 26 | **NOTE** copy `Google.ProtocolBuffers.dll` too. 27 | 28 | 3. Done and test. 29 | 30 | #### Checkout the example, and have fun. 31 | -------------------------------------------------------------------------------- /networking-with-protobuf-example/server.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | import gevent 4 | from gevent.server import StreamServer 5 | 6 | from utest_pb2 import Marine 7 | 8 | 9 | def pack_data(i): 10 | m = Marine() 11 | m.id = i 12 | m.hp = 299 13 | m.position.x = 5 14 | m.position.y = 6 15 | m.position.z = 7 16 | return m.SerializeToString() 17 | 18 | 19 | def send(sock): 20 | def _send(): 21 | data = pack_data(i) 22 | data_len = len(data) 23 | fmt = '!i%ds' % data_len 24 | s = struct.Struct(fmt) 25 | data = s.pack(data_len, data) 26 | sock.sendall(data) 27 | 28 | for i in range(10): 29 | _send() 30 | gevent.sleep(1) 31 | 32 | print "Send Complete!" 33 | 34 | 35 | 36 | def recv(sock): 37 | len_type = struct.Struct('!i') 38 | while True: 39 | try: 40 | data = sock.recv(4) 41 | except: 42 | print "sock recv error" 43 | break 44 | 45 | if not data: 46 | print "lost connection" 47 | break 48 | 49 | 50 | data_len = len_type.unpack(data) 51 | data = sock.recv(data_len[0]) 52 | if not data: 53 | print "lost connection" 54 | break 55 | 56 | m = Marine() 57 | m.ParseFromString(data) 58 | 59 | print "recv: ", m 60 | 61 | 62 | def handler(client, address): 63 | print "new connections", address 64 | 65 | _r = gevent.spawn(recv, client) 66 | _s = gevent.spawn(send, client) 67 | 68 | def _clear(glet): 69 | client.close() 70 | glet.unlink(_clear) 71 | gevent.killall([_r, _s]) 72 | print "Shutdown" 73 | 74 | _r.link(_clear) 75 | _s.link(_clear) 76 | gevent.joinall([_r, _s]) 77 | 78 | 79 | s = StreamServer(('0.0.0.0', 8888), handler) 80 | s.serve_forever() 81 | 82 | -------------------------------------------------------------------------------- /networking-with-protobuf-example/utest.proto: -------------------------------------------------------------------------------- 1 | package CodeBattle; 2 | 3 | message Position { 4 | required int32 x = 1; 5 | required int32 y = 2; 6 | required int32 z = 3; 7 | } 8 | 9 | 10 | message Marine { 11 | required int32 id = 1; 12 | required int32 hp = 2; 13 | required Position position = 3; 14 | } --------------------------------------------------------------------------------