unity使用protobuf

在unity中使用protobuf和服务器进行通信

proto文件

syntax = "proto2"; 
enum Cmd {
	INVALID_CMD = 0;
	eLoginReq = 1;
	eLoginRes = 2;
}

message LoginReq {  
  required string name = 1;  
  required int32 age = 2;  
  required string email = 3;  
  required int32 int_set = 4;
}

message LoginRes {
  required int32 status = 1;	
}

C#脚本

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using ProtoBuf;
using System.IO;
using System.Text;
//1
public class network : MonoBehaviour {
    private string server_ip = "106.13.232.15";
    private int port = 9998;

    private Socket client_socket = null;
    private bool is_connect = false;
    private Thread recv_thread = null;
    private byte[] recv_buffer = new byte[8192];

    void Awake() {
        DontDestroyOnLoad(this.gameObject);
    }

	// Use this for initialization
	void Start () {
        this.connect_to_server();
        //test();
        // test
        //this.Invoke("close", 5.0f);
        // end 
	}
    //2字节长度(大端) + protobuf数据体
    void send_protobuf()
    {
        gprotocol.LoginReq req = new gprotocol.LoginReq();
        req.name = "blake";
        req.email = "blake@bycw.edu";
        req.age = 34;
        req.int_set = 8;

        byte[] send_buffer = null;
        int pro_length;
        using (MemoryStream m = new MemoryStream())
        {
            Serializer.Serialize(m, req);
            m.Position = 0;
            pro_length = (int)m.Length;
            send_buffer = new byte[2 + pro_length];
            Debug.Log("protobuf_len = " + pro_length);

            write_ushort_le(send_buffer, 0, (ushort)pro_length);
            m.Read(send_buffer, 2, pro_length);
        }
        this.client_socket.Send(send_buffer);

    }
    public static void write_ushort_le(byte[] buf, int offset, ushort value) { 
        // value ---> byte[];

        //主机序是小端,网络序是大端
        byte[] byte_value = BitConverter.GetBytes(value);
        // 小尾,还是大尾?BitConvert 系统是小尾还是大尾;
        //if (!BitConverter.IsLittleEndian) {
            Array.Reverse(byte_value);
        //}

        Array.Copy(byte_value, 0, buf, offset, byte_value.Length);
    }
    public static void write_bytes(byte[] dst, int offset, byte[] value)
    {
        Array.Copy(value, 0, dst, offset, value.Length);
    }

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

    void on_conntect_timeout() {
        Debug.Log("连接超时");
    }

    void on_connect_error(string err) { 
    }

    void connect_to_server() {
        try {
            this.client_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddress = IPAddress.Parse(this.server_ip);
            IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, this.port);

            IAsyncResult result = this.client_socket.BeginConnect(ipEndpoint, new AsyncCallback(this.on_connected), this.client_socket);
            bool success = result.AsyncWaitHandle.WaitOne(5000, true);
            if (!success) { // timeout;
                this.on_conntect_timeout();
            }
            Debug.Log("connect ok");
        }
        catch (System.Exception e) {
            Debug.Log(e.ToString());
            this.on_connect_error(e.ToString());
        }
    }

    void on_recv_data() {
        if (this.is_connect == false) {
            return;
        }

        while (true) {
            if (!this.client_socket.Connected) {
                break;
            }

            try
            {
                int recv_len = this.client_socket.Receive(this.recv_buffer);
                if (recv_len > 0) { // recv data from server

                    string str = System.Text.Encoding.Default.GetString(this.recv_buffer);
                    Debug.Log("recv:" + str);

                }
            }
            catch (System.Exception e) {
                Debug.Log(e.ToString());
                this.client_socket.Disconnect(true);
                this.client_socket.Shutdown(SocketShutdown.Both);
                this.client_socket.Close();
                this.is_connect = false;
                break;
            }
        }
    }

    void on_connected(IAsyncResult iar) {
        try {
            Socket client = (Socket)iar.AsyncState;
            client.EndConnect(iar);

            this.is_connect = true;

            //创建一个线程接收消息
            this.recv_thread = new Thread(new ThreadStart(this.on_recv_data));
            this.recv_thread.Start();

            Debug.Log("connect to server success" + this.server_ip + ":" + this.port + "!");
            send_protobuf();
        }
        catch (System.Exception e) {
            Debug.Log(e.ToString());
            this.on_connect_error(e.ToString());
            this.is_connect = false;
        }
    }

    void close() {
        if (!this.is_connect) {
            return;
        }

        // abort recv thread
        if (this.recv_thread != null) {
            this.recv_thread.Abort();
        }
        // end

        if (this.client_socket != null && this.client_socket.Connected) {
            this.client_socket.Close();
        }
    }
}

服务端使用Linux C++实现

/*
g++ -o server echo.cpp game.pb.cc -I -I/usr/local/include/google/protobuf \
    -L/usr/local/lib \
    -lprotobuf
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/epoll.h>

#include "game.pb.h"

int tcp_socket(int port);
void handle_recv(int cfd);

int main(int argc,char *argv[]){
    if(argc != 2)
	{
		printf("Usage : %s port\n",argv[0]);
		return 1;
	}
    int lfd = tcp_socket(atoi(argv[1]));
    assert(lfd > 0);
    struct sockaddr_in client;
	memset(&client,0,sizeof client);
    socklen_t len = sizeof(client);
    int cfd = accept(lfd,(struct sockaddr*)&client,&len);
    if(cfd < 0)
    {
        return -1;
    }
    char buf[1024] = {0};
    
    handle_recv(cfd);

    return 0;
}

void handle_recv(int cfd){
    char *buf = (char*)malloc(1024);
    while(1){
        int r = recv(cfd,buf,1024,0);
        if(r > 0){
            buf[r] = '\0';
            printf("recv len = %d\n",r);
            unsigned short head = *(unsigned short*)buf;
            head = ntohs(head);
            LoginReq login;
            login.ParseFromArray(buf + 2, head); 
            printf("name:%s age:%d email:%s int_set:%d\n",login.name().c_str(),
                login.age(),login.email().c_str(),login.int_set());
        }
        else{
            break;
        }
    }
}

int tcp_socket(int port){
	int sock;
	struct sockaddr_in addr;
	memset(&addr,0,sizeof addr);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("172.16.0.4");
	addr.sin_port = htons(port);

	sock = socket(AF_INET,SOCK_STREAM,0);
    const int on = 1;
    if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on)){
        printf("setsockopt\n");
        return -1;
    }
	if(bind(sock,(struct sockaddr*)&addr,sizeof(addr)) == -1){
        return -1;
    }
	if(listen(sock,10) == -1){
        return -1;
    }
	return sock;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值