考虑实现用C++做服务器,unity做客户端实现TCP网络通信。
以下采用TCP单线程连接。
Qt C++服务端
建立一个Qt的GUI项目,在界面上放一个label显示连接状态,两个button作为指令发送控制。
记得在pro文件中加入network模块
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> class QTcpServer;//前向声明 class QTcpSocket; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; private: QString statusText; //状态信息 QTcpServer *tcpServer; //服务器 QTcpSocket *clientTcpSocket; //客户端socket void SocketSend(QString sendStr); private slots: void SocketConnet(); void SocketReceive(); void on_leftBtn_clicked(); void on_rightBtn_clicked(); }; #endif // WIDGET_H
widget.cpp
#include <QTcpServer> #include <QTcpSocket> #include <QAbstractSocket> #include <QDebug> #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); //初始化server并监听 tcpServer=new QTcpServer(this); //qt自己内存管理 if(!tcpServer->listen(QHostAddress::Any,6666)) //监听所有网络地址,端口6666 qDebug()<<tcpServer->errorString(); statusText=statusText+"wait for connecting..."+"\n"; ui->statusLabel->setText(statusText); //绑定信号槽,当有连接时作出反应 connect(tcpServer,SIGNAL(newConnection()),this,SLOT(SocketConnet())); } void Widget::SocketConnet() { //获得client socket clientTcpSocket=tcpServer->nextPendingConnection(); //绑定信号槽,接收数据,并且当连接关闭是删除连接 connect(clientTcpSocket,SIGNAL(readyRead()),this,SLOT(SocketReceive())); connect(clientTcpSocket,SIGNAL(disconnected()),clientTcpSocket,SLOT(deleteLater())); //显示客户端连接信息 QString clientIp=clientTcpSocket->peerAddress().toString(); QString clientPort=QString::number(clientTcpSocket->peerPort()); statusText=statusText+"conneted with "+clientIp+":"+clientPort+"\n"; ui->statusLabel->setText(statusText); } void Widget::SocketSend(QString sendStr) { clientTcpSocket->write(sendStr.toStdString().c_str()); } void Widget::SocketReceive() { //接收数据并显示,字节转换成了字符串 QString recvStr=clientTcpSocket->readAll(); statusText=statusText+recvStr+"\n"; ui->statusLabel->setText(statusText); //经处理后发送回去 SocketSend("From server: "+recvStr); } Widget::~Widget() { delete ui; } //发送unity物体左旋消息 void Widget::on_leftBtn_clicked() { SocketSend("leftrotate"); } //发送unity物体右旋消息 void Widget::on_rightBtn_clicked() { SocketSend("rightrotate"); }
main.cpp未更改就不贴了。
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; public class TcpTest:MonoBehaviour { string editString="hello wolrd"; //编辑框文字 GameObject cube; TcpClientHandler tcpClient; // Use this for initialization void Start() { //初始化网络连接 //tcpClient=new TcpClientHandler(); //因为tcp的类继承了monobehaviour所以不能用new,或者去掉对monobehaviour继承就可以用new tcpClient=gameObject.AddComponent<TcpClientHandler>(); tcpClient.InitSocket(); //找到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 Update() { if(tcpClient.GetRecvStr()!=null) { switch(tcpClient.GetRecvStr()) { case "leftrotate": cube.transform.Rotate(Vector3.up,50*Time.deltaTime); break; case "rightrotate": cube.transform.Rotate(Vector3.down,50*Time.deltaTime); break; } } } void OnApplicationQuit() { //退出时关闭连接 tcpClient.SocketQuit(); } }
测试
程序实现服务端和客户端互相收发消息,服务端按钮可以控制客户端里面的cube旋转。
时间: 2024-11-03 05:28:11