主要参考博客:https://blog.csdn.net/u012234115/article/details/46489537
考虑实现用Qt C++做服务器,unity做客户端实现TCP网络通信,来传递unity中模型的坐标。
建立一个Qt的GUI项目,在界面上放一个label显示连接状态,两个button作为指令发送控制。
记得在pro文件中加入network模块。
如图所示:
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场景,拖入一个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();
}
}