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

9 篇文章 1 订阅

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模块。
如图所示:
在这里插入图片描述
server1.h

#ifndef SERVER1_H
#define SERVER1_H

#include <QObject>

#include <QTcpServer>
#include <QTcpSocket>

#include <QThread>

#include <QDebug>
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 <QWidget>
#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();
    }
}

效果:

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值