Qt C++与unity之间TCP网络通信(多线程)

Qt C++与unity之间TCP网络通信(多线程)

主要参考博客:https://blog.csdn.net/u012234115/article/details/46489537
考虑实现用Qt C++做服务器,unity做客户端实现TCP网络通信,来传递unity中模型的坐标。

Qt C++服务端

建立一个Qt的GUI项目,在界面上放一个label显示连接状态,两个button作为指令发送控制。
记得在pro文件中加入network模块。
如图所示:
Qt C++与unity之间TCP网络通信(多线程)_第1张图片
server1.h

#ifndef SERVER1_H
#define SERVER1_H

#include 

#include 
#include 

#include 

#include 
class Server1 : public QTcpServer
{
    Q_OBJECT
public:
    explicit Server1(QObject *parent = nullptr);

signals:
    void msg(const QString &);
    void connectsuccess(QString str);
    void sended(QString str);

public slots:
    void send(const QString &);
    void NewConnection();
    void ReadyRead();

public:
    QTcpSocket *socket;
};

#endif // SERVER1_H

server1.cpp

#include "server1.h"
#pragma execution_character_set("utf-8")
Server1::Server1(QObject *parent) : QTcpServer(parent)
{
    listen(QHostAddress("127.0.0.1"),6666);

    connect(this,&QTcpServer::newConnection,this,&Server1::NewConnection);
}

void Server1::NewConnection()
{

    if(this->hasPendingConnections())
    {
        socket = nextPendingConnection();
        if(socket)
        {
            connect(socket,&QIODevice::readyRead,this,&Server1::ReadyRead);
        }
        emit connectsuccess("start");
    }
}

void Server1::ReadyRead()
{
    QString recvStr=socket->readAll();
    QString a=recvStr.mid(0,recvStr.indexOf("a"));
    QString b=recvStr.mid(recvStr.indexOf("a")+1,recvStr.indexOf("b")-recvStr.indexOf("a")-1);
    QString c=recvStr.mid(recvStr.indexOf("b")+1,recvStr.indexOf("c")-recvStr.indexOf("b")-1);
    QString sum=recvStr.mid(recvStr.indexOf(":")+1);
    qDebug()<<"子线程:"<<QThread::currentThread();
    emit msg(QString("x:%1,y:%2,z:%3,sum:%4").arg(a).arg(b).arg(c).arg(sum));
}

void Server1::send(const QString &str)
{
    socket->write(str.toStdString().c_str());
    emit sended(str);
    qDebug()<<"已发送"<<str<<QThread::currentThread();
}

tcp1.h

#ifndef TCP1_H
#define TCP1_H

#include 
#include "server1.h"
#include "socket1.h"

namespace Ui {
class TCP1;
}

class TCP1 : public QWidget
{
    Q_OBJECT

public:
    explicit TCP1(QWidget *parent = nullptr);
    ~TCP1();



signals:
    void socketMsg(const QString &);
    void serverMsg(const QString &);


private slots:
    void on_btn_start_clicked();

    void on_btn_stop_clicked();

    void setflag(QString);

private:
    Ui::TCP1 *ui;
    Server1 *server;
    QThread *serverThread;
    bool flag=false;
    int n=-1;
};

#endif // TCP1_H

tcp1.cpp

#include "tcp1.h"
#include "ui_tcp1.h"
#pragma execution_character_set("utf-8")
TCP1::TCP1(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TCP1)
{
    ui->setupUi(this);

    server = nullptr;
    serverThread = nullptr;
    server = new Server1;
    serverThread = new QThread;
    server->moveToThread(serverThread);
    serverThread->start();
    connect(this,&TCP1::serverMsg,server,&Server1::send);
    connect(server,&Server1::msg,this,[&](const QString &str){ui->textEdit->append(str);});
    connect(server,&Server1::connectsuccess,this,&TCP1::setflag);
    connect(server,&Server1::sended,this,&TCP1::setflag);
    qDebug()<<"主线程:"<<QThread::currentThread();

}

TCP1::~TCP1()
{
    delete ui;

    if(serverThread)
    {
        serverThread->quit();
        serverThread->wait();
        delete serverThread;
    }
    serverThread = nullptr;

    if(server)
        delete server;
    server = nullptr;
}

void TCP1::on_btn_start_clicked()
{
    if(flag&&n)
    {
       emit serverMsg("start");
       QString clientIp=server->socket->peerAddress().toString();
       QString clientPort=QString::number(server->socket->peerPort());
       ui->label->setText("conneted with "+clientIp+":"+clientPort+"\n");
       n++;
    }
     qDebug()<<flag;
}

void TCP1::on_btn_stop_clicked()
{
    if(flag)
    {
        emit serverMsg("stop");
    }

}

void TCP1::setflag(QString str)
{

    if(str=="start")
    {
        flag=true;
    }
    else if(str=="stop")
    {
        flag=false;
        n=-1;
    }
}

unity C#客户端

建立一个unity场景,拖入一个cube
把tcpsocket连接部分封装成了一个单独的类TcpClientHandler,再加一个脚本TcpTest挂到场景中,在这个脚本中实例化用于连接的TcpClientHandler。

TcpClientHandler.cs

using UnityEngine;
using System.Collections;
//引入库
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class TcpClientHandler : MonoBehaviour
{
    Socket serverSocket; //服务器端socket
    IPAddress ip; //主机ip
    IPEndPoint ipEnd;
    string recvStr; //接收的字符串
    string sendStr; //发送的字符串
    byte[] recvData = new byte[1024]; //接收的数据,必须为字节
    byte[] sendData = new byte[1024]; //发送的数据,必须为字节
    int recvLen; //接收的数据长度
    Thread connectThread; //连接线程

    //初始化
    public void InitSocket()
    {
        //定义服务器的IP和端口,端口与服务器对应
        ip = IPAddress.Parse("127.0.0.1"); //可以是局域网或互联网ip,此处是本机
        ipEnd = new IPEndPoint(ip, 6666); //服务器端口号


        //开启一个线程连接,必须的,否则主线程卡死
        connectThread = new Thread(new ThreadStart(SocketReceive));
        connectThread.Start();
    }

    void SocketConnet()
    {
        if (serverSocket != null)
            serverSocket.Close();
        //定义套接字类型,必须在子线程中定义
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        print("ready to connect");
        //连接
        serverSocket.Connect(ipEnd);

        //输出初次连接收到的字符串
        recvLen = serverSocket.Receive(recvData);
        recvStr = Encoding.ASCII.GetString(recvData, 0, recvLen);
        print(recvStr);
    }

    public void SocketSend(string sendStr)
    {
        //清空发送缓存
        sendData = new byte[1024];
        //数据类型转换
        sendData = Encoding.ASCII.GetBytes(sendStr);
        //发送
        serverSocket.Send(sendData, sendData.Length, SocketFlags.None);
    }

    void SocketReceive()
    {
        SocketConnet();
        //不断接收服务器发来的数据
        while (true)
        {
            recvData = new byte[1024];
            recvLen = serverSocket.Receive(recvData);
            if (recvLen == 0)
            {
                SocketConnet();
                continue;
            }
            recvStr = Encoding.ASCII.GetString(recvData, 0, recvLen);
            print(recvStr);
        }
    }

    //返回接收到的字符串
    public string GetRecvStr()
    {
        string returnStr;
        //加锁防止字符串被改
        lock (this)
        {
            returnStr = recvStr;
        }
        return returnStr;
    }
    public void SocketQuit()
    {
        //关闭线程
        if (connectThread != null)
        {
            connectThread.Interrupt();
            connectThread.Abort();
        }
        //最后关闭服务器
        if (serverSocket != null)
         
            serverSocket.Close();
        print("diconnect");
    }

}

TcpTest.cs

using UnityEngine;
using System.Collections;
using System.Threading;

public class TcpTest : MonoBehaviour
{
    string editString; //编辑框文字
    GameObject cube;
    public int sum = 0;

    TcpClientHandler tcpClient;
    // Use this for initialization
    private void Awake()
    {
        tcpClient = gameObject.AddComponent<TcpClientHandler>();
        tcpClient.InitSocket();
    }
    void Start()
    {
        //初始化网络连接
        //tcpClient=new TcpClientHandler(); //因为tcp的类继承了monobehaviour所以不能用new,或者去掉对monobehaviour继承就可以用new
       

        //找到cube
        cube = GameObject.Find("Cube");
    }

    void OnGUI()
    {
        editString = GUI.TextField(new Rect(10, 10, 100, 20), editString);
        GUI.Label(new Rect(10, 30, 300, 20), tcpClient.GetRecvStr());
        if (GUI.Button(new Rect(10, 50, 60, 20), "send"))
            tcpClient.SocketSend(editString);
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if (tcpClient.GetRecvStr()=="start")
        {

        string strCube_x = cube.transform.position.x.ToString();
        string strCube_y = cube.transform.position.y.ToString();
        string strCube_z = cube.transform.position.z.ToString();
        //Debug.Log("strcube的差:"+strCube_x + " ," + strCube_y + " ," + strCube_z + ", sum:" + sum);
        //Debug.Log("新的位置:"+x_st + " ," + y_st + " ," + z_st + ", sum:" + sum);
        //Debug.Log(strCube_x);
        editString = strCube_x + "a" + strCube_y + "b" + strCube_z + "sum:" + sum; 
        tcpClient.SocketSend(editString);
        sum++;
        }
        else if(tcpClient.GetRecvStr() == "stop")
        {
            tcpClient.SocketQuit();
        }
        
       
        }

    void OnApplicationQuit()
    {
        //退出时关闭连接
        tcpClient.SocketQuit();
    }
}

效果:

Qt C++与unity之间TCP网络通信(多线程)_第2张图片Qt C++与unity之间TCP网络通信(多线程)_第3张图片Qt C++与unity之间TCP网络通信(多线程)_第4张图片Qt C++与unity之间TCP网络通信(多线程)_第5张图片

你可能感兴趣的:(C++,Unity,socket,网络通信,unity3d,多线程)