在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;
}