상세 컨텐츠

본문 제목

[Unity] TCP/IP, 소켓통신 와 멀티쓰레드 관련

게임엔진관련/유니티 엔진

by AlrepondTech 2019. 1. 17. 14:38

본문

반응형

 

 



=======================

=======================

=======================

 

 

 

 

 

 

출처: http://www.devkorea.co.kr/bbs/board.php?bo_table=m03_qna&wr_id=67633

 

 

안녕하세요? 유니티로 게임 개발을 하고있는 초보 개발자 입니다.

 

다름이 아니라, 이번에 외주 요청이 들어왔는데

 

그 쪽에서 Tcp/ip통신으로 속도값 데이터를 지속적으로 보내면 그 값을 이용해서

 

1인칭 컨트롤러가 네비로 구성된 길을 따라 속도가 변하면서 이동해야 한다고 하더라구요.

 

제가 초보라 클라이언트/서버 통신 방식으로 1번 네트워크를 구현해 본 것 밖에 없어서,

 

이게 가능한지 궁금합니다^^

 

만약 가능하다면 참고할 만한 정보도 알려주시면 더욱 감사드리겠습니다^^

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

당연히 가능하죠. 
구글에서 유니티 TCP 소켓 통신 치면 수많은 자료가 나오니 참고하세요 ㅎ 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
선언하시면 소켓 쓸수 있어요~ 
쓰레드 하나 생성하시고, IP , Port 세팅하시고 연결 후 쓰레드에서 데이터 통신을 계속 하면 됩니다. 들어오는 속도(float이 되겠죠)값을 받아 유니티에서 처리해주면 됩니다. 
구조체값을 받아야한다면 마샬링을 하셔야 합니다(이것도 검색하면 나옵니다) 
예제로는 
UDP 이긴 하지만 비슷합니다. 
http://wonjuni.co.kr/home/udp-networks/ 
참고하세요

 

 



=======================

=======================

=======================

 

 

 

출처: http://www.devkorea.co.kr/bbs/board.php?bo_table=m03_qna&wr_id=90093

 

 

안녕하세요 Unity 초보입니다.
 
유니티를 클라이언트로 만들어 2개의 소켓을 이용하여 TCP/IP소켓통신으로 서버에  접속하고 데이터를 주고받으려합니다.
 
2개의 소켓중 한개의 소켓은 서버의 상태를 주기적으로 주고 받을 것이고 한개의 소켓은 서버에게 명령을 보내어 반환값을 받으려합니다.
 
상태를 받는 소켓에서 데이터를 주고 받는 것을 쓰레드로 만들어 사용하고 있는데 여기서 문제가 발생합니다.
 
상태를 받는 소켓의 쓰레드는 잘 동작하나.. 명령을 보내는 소켓에서 SendMessage는 되는데 Recevie를 하지 못합니다.
 
상태 소켓과 명령소켓을 둘 다 쓰레드로 만들어서 사용도 해보았고, 둘 다 코루틴으로 만들어서도 사용해보았으나 
 
연결과 동시에 상태 소켓은 쓰레드로 동작하고 있고 명령 소켓에 SendMessage를 하고 순 Recevie를 함수, 쓰레드, 코루틴으로 동작을 시키는순간 먹통이 되어 다운이 걸립니다.
 
이러한 상황을 해결할 방안을 아시거나 도움을 부탁드립니다.
 
아래의 코드는 일부를 발췌한 것이므로, 변수가 선언이 안되어있다거나 한것은 실제는 그렇지 않음을 참고 해주세요...
 
SendStatusMsg와 Lintenfordata가 상태를 받아오는 쓰레드 이고 
 
RobotSendMessage와 RobotListenForData가 명령을 보내는 소켓입니다.
 
아..또한 추가질문으로 unity상에서 Run을 하고 Run을 중지 시켰을 때 쓰레드가 멈추지않고 계속 프로세스로 동작하는 상황이있습니다.
 
그래서 쓰레드를 돌지못하게 Disconnect(아래의 코드에서 Btn이라는 펑션) 버튼을 따로 만들어 사용중인데 Run하고 Run 중지 시켰을 때 따로 Disconnect하지 않고 쓰레드를 종료 할방법이있나요.?
 
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
using System.Reflection;
namespace TeamPrjt
{
    public class TCPTestClient : MonoBehaviour
    {
        BTn tcpbtn;
        public GameObject Target;
        private TcpClient socketConnection;
        private TcpClient statusConnection;
        public Thread clientReceiveThread;
        public Thread SendStatusThread;
        public Thread RobotRecvThread;
        public Thread RobotSendThread;
        NetworkStream stream;
        NetworkStream streamst;
        
        string[] AngleJoint = new string[8];
        string beforeSendData = null;
        string saveRecvData = null;
        public string[] switchCase = null;
        public Text text;
        public Text text1;
        public string joint = null;
        public string Robotreturn = null;
        public string[] Robotsplit = null;
        int cnt;
        bool connect_flag;
        bool angleJoint_flag;
        bool Recvflag;
        bool send;
        bool recv;
        byte[] Rseddata;
        public bool ChangeWerec = false;
        public volatile string Ssbuf = null;
        public string[] TcpPositiondata = new string[7];
 
        public bool applyflag = true;
        #endregion
        // Use this for initialization 
        public void btn()
        {
            RobotSendMessage("attach 0");
            send = false;
            recv = false;
            streamst.Close();
            stream.Close();
            socketConnection.Close();
            statusConnection.Close();
            clientReceiveThread.Join();
            clientReceiveThread.Abort();
            SendStatusThread.Join();
            SendStatusThread.Abort();
        }
        void Start()
        {
            socketConnection = new TcpClient("192.168.0.1", 10100);
            statusConnection = new TcpClient("192.168.0.1", 10000);
            //socketConnection = new TcpClient("localhost", 9999);
            send = true;
            recv = true;
            stream = socketConnection.GetStream();
            string msg = "";
            byte[] data = System.Text.Encoding.Default.GetBytes(msg);
            stream.Write(data, 0, data.Length);
            streamst = statusConnection.GetStream();
            streamst.Write(data, 0, data.Length);
            ConnectToTcpServer();
            tcpbtn = GameObject.Find("TCPJog").GetComponent<BTn>();
 
 
        }
        private void ConnectToTcpServer()
        {
            try
            {
                clientReceiveThread = new Thread(new ThreadStart(ListenForData));
                clientReceiveThread.IsBackground = false;
                clientReceiveThread.Start();
 
                connect_flag = true;
                SendStatusThread = new Thread(new ThreadStart(SendStatusMsg));
                SendStatusThread.IsBackground = false;
                SendStatusThread.Start();
            }
            catch (Exception e)
            {
                Debug.Log("On client connect exception " + e);
            }
        }
        // Update is called once per frame
        void Update()
        {
 
        }
 
        /// <summary> 
        /// Runs in background clientReceiveThread; Listens for incomming data. 
        /// </summary>     
        private void SendStatusMsg()
        {
            try
            {
                //  Debug.Log("in");
 
                while (true)
                {
                    if (send == false)
                        break;
                    angleJoint_flag = true;
                    if (angleJoint_flag)
                    //NetworkStream stream;
                    {
                        Ssbuf = "wherea\r\n";
                        byte[] data = System.Text.Encoding.Default.GetBytes(Ssbuf);
                        streamst.Write(data, 0, data.Length);
                        angleJoint_flag = false;
                    }
                    Thread.Sleep(50);
                }
 
            }
            catch (SocketException socketException)
            {
                Debug.Log("Socket exception: " + socketException);
            }
        }
 
        private void ListenForData()
        {
            try
            {
                Byte[] bytes = new Byte[1024];
                while (true)
                {
                    if (recv == false)
                        break;
                    // Get a stream object for reading 
                    using (streamst = statusConnection.GetStream())
                    {
                        int length;
                        // Read incomming stream into byte arrary. 
                        while ((length = streamst.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            var incommingData = new byte[length];
                            Array.Copy(bytes, 0, incommingData, 0, length);
                            // Convert byte array to string message. 
                            string serverMessage = Encoding.ASCII.GetString(incommingData);
                            saveRecvData = serverMessage;
 
                            Recvflag = true;
 
                            if (tcpbtn.TcpJogfalg)
                            {
                                text.text = null;
                                TcpPositiondata = saveRecvData.Split(' ');
                                ChangeWerec = true;
                            }
                            else
                            {
                                text1.text = null;
                                switchCase = saveRecvData.Split(' ');
                                ChangeWerec = false;
                            }
                        }
                    }
                    Thread.Sleep(1);
 
                }
 
            }
            catch (SocketException socketException)
            {
                Debug.Log("Socket exception: " + socketException);
            }
        }
 
        public void RobotSendMessage(string Message)
        {
            try
            {
                if (Message != null)
                {
                    string buf = null;
                    buf = Message + "\r\n";
                    Rseddata = System.Text.Encoding.Default.GetBytes(buf);
                    stream.Write(Rseddata, 0, Rseddata.Length);
                  
                }
            }
            catch (SocketException socketException)
            {
                Debug.Log("Socket exception: " + socketException);
            }
 
        }
 
        public void RobotListenForData()
        {
            try
            {
                Byte[] bytes = new Byte[1024];
                while (true)
                {
                    if (recv == false)
                        break;
                    using (stream = socketConnection.GetStream())
                    {
                        int length;
                        while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            var incommingData = new byte[length];
                            Array.Copy(bytes, 0, incommingData, 0, length);
                            string serverMessage = Encoding.ASCII.GetString(incommingData);
                            Debug.Log("ROBOT message received as: " + serverMessage);
                            Robotreturn = serverMessage;
                            Robotsplit = serverMessage.Split(' ');
                        }
                    }
                    Thread.Sleep(1);
                }
 
            }
            catch (SocketException socketException)
            {
                Debug.Log("Socket exception: " + socketException);
            }
        }
    }
 
}

 

 

 

반응형

 

 

728x90

 

 



=======================

=======================

=======================

 

 

 

출처: http://blog.naver.com/PostView.nhn?blogId=iii4625&logNo=221377862635&categoryNo=18&parentCategoryNo=0&viewDate=&currentPage=1&postListTopCurrentPage=1&from=postView

 

 

서버에 Connect후에 통신을 위해 소켓통신용 쓰레드를 하나 만들어서 서버에서 받는 메세지로 유니티UI이 변경되도록 만들었지만
유니티에서 유니티 리소스에는 메인쓰레드만 접근허용한다는 오류메세지가 뜬다.
get_isPlaying.
socket.BeginReceive로 코루틴+비동기처리로 코드를 갈아엎었지만 비동기처리 자체가 쓰레드를 생성, 콜백함수의 실행은 결국 서브스레드에서 발생해 같은오류가 발생.

결국 소켓통신쓰레드와 유니티 매인쓰레드와의 통신을 하기위해 중간매개체로 메세지큐를 두었다.

소켓통신 스레드에서 메세지를 받으면 해석하여 적절한 데이터큐에 넣고 유니티에선 그 ㅁ큐를 확인하여 dequeue.


이제야 채팅까지 완성함.

 



=======================

=======================

=======================

 

 

 

 

출처: http://www.devkorea.co.kr/bbs/board.php?bo_table=m03_qna&wr_id=67633

 

안녕하세요? 유니티로 게임 개발을 하고있는 초보 개발자 입니다.

 

다름이 아니라, 이번에 외주 요청이 들어왔는데

 

그 쪽에서 Tcp/ip통신으로 속도값 데이터를 지속적으로 보내면 그 값을 이용해서

 

1인칭 컨트롤러가 네비로 구성된 길을 따라 속도가 변하면서 이동해야 한다고 하더라구요.

 

제가 초보라 클라이언트/서버 통신 방식으로 1번 네트워크를 구현해 본 것 밖에 없어서,

 

이게 가능한지 궁금합니다^^

 

만약 가능하다면 참고할 만한 정보도 알려주시면 더욱 감사드리겠습니다^^

--------------------------------------------------------------------------------------------------------------------------------------------------------------

 

당연히 가능하죠. 
구글에서 유니티 TCP 소켓 통신 치면 수많은 자료가 나오니 참고하세요 ㅎ 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
선언하시면 소켓 쓸수 있어요~ 
쓰레드 하나 생성하시고, IP , Port 세팅하시고 연결 후 쓰레드에서 데이터 통신을 계속 하면 됩니다. 들어오는 속도(float이 되겠죠)값을 받아 유니티에서 처리해주면 됩니다. 
구조체값을 받아야한다면 마샬링을 하셔야 합니다(이것도 검색하면 나옵니다) 
예제로는 
UDP 이긴 하지만 비슷합니다. 
http://wonjuni.co.kr/home/udp-networks/ 
참고하세요

 

 



=======================

=======================

=======================

 

 

 

 

* 기타관련링크

 

C# tcp/ip 소켓통신관련

- https://202psj.tistory.com/1245

 

https://202psj.tistory.com/975

 



=======================

=======================

=======================

 

 

 

 

반응형


관련글 더보기

댓글 영역