본문 바로가기

프로그램/유니티 네트워크

[유니티 네트워크] 멀티 스레드 1:N TcpServer, TcpClient 문자열 전송 (TcpListener, TcpClient)

728x90
반응형

1. 내용

 (1) 권장 포트 번호 : 49152 ~ 65535

 

포트 번호

내용

0

사용하지 않음.

1 ~1023

잘 알려진 포트(Well-known port)

1024 ~ 49151

등록된 포트(Registered port)

49152 ~ 65535

동적 포트(Dynamic port)

 

 (2) 전송 패키지 사이즈

  Tcp 전송 패키지 크기는 Ethernet(V2)에서 MTU(Maximum Transmission Unit)는 1500 Byte, MSS(Maximum Segment Size)는 Tcp헤더와 IP헤더를 제외하면 1460 Byte 입니다.

  하지만, 편의상 1024 byte이내가 사용하기 적당합니다.

 

 (3) 소스 내용

  - 유니티와 유니티, 또는 C#과의 통신, 또는 C++와의 통신

  - 클래스 : SocketTcpListener, TcpClient

 

 

2. 소스

2.1 Server.cs

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class Server : MonoBehaviour
{
    public int m_Port = 50001;
    private TcpListener m_TcpListener;
    private List<TcpClient> m_Clients = new List<TcpClient>(new TcpClient[0]);
    private Thread m_ThrdtcpListener;
    private TcpClient m_Client;

    void Start()
    {
        m_ThrdtcpListener = new Thread(new ThreadStart(ListenForIncommingRequests));
        m_ThrdtcpListener.IsBackground = true;
        m_ThrdtcpListener.Start();
    }

    void Update()
    {
        for (int i = 0; i < m_Clients.Count; i++)
        {
            if (!m_Clients[i].Connected)
                m_Clients.RemoveAt(i);

            else
                SendMessage(m_Clients[i], "서버에서 보내는 값"); // 보내는 값
        }
    }

    void OnApplicationQuit()
    {
        m_ThrdtcpListener.Abort();

        if (m_TcpListener != null)
        {
            m_TcpListener.Stop();
            m_TcpListener = null;
        }
    }

    void ListenForIncommingRequests()
    {
        m_TcpListener = new TcpListener(IPAddress.Any, m_Port);
        m_TcpListener.Start();
        ThreadPool.QueueUserWorkItem(ListenerWorker, null);
    }

    void ListenerWorker(object token)
    {
        while (m_TcpListener != null)
        {
            m_Client = m_TcpListener.AcceptTcpClient();
            m_Clients.Add(m_Client);
            ThreadPool.QueueUserWorkItem(HandleClientWorker, m_Client);
        }
    }

    void HandleClientWorker(object token)
    {
        Byte[] bytes = new Byte[1024];
        using (var client = token as TcpClient)
        using (var stream = client.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 clientMessage = Encoding.Default.GetString(incommingData);
                Debug.Log(clientMessage); // 받은 자료
            }

            if (m_Client == null)
            {
                return;
            }
        }
    }

    void SendMessage(object token, string message)
    {
        if (m_Client == null)            
            return;

        else
            Debug.Log(m_Clients.Count);

        var client = token as TcpClient;
        {
            try
            {
                NetworkStream stream = client.GetStream();
                if (stream.CanWrite)
                {
                    byte[] serverMessageAsByteArray = Encoding.Default.GetBytes(message);
                    stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
                }
            }

            catch (SocketException ex)
            {
                Debug.Log(ex);
                return;
            }
        }
    }        
}

 

2.2 Client.cs

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class Client : MonoBehaviour
{
	public string m_Ip = "127.0.0.1";
	public int m_Port = 50001;
	private TcpClient m_Client;
	private Thread m_ThrdClientReceive;

	void Start()
	{
		ConnectToTcpServer();
	}

	void Update()
	{
		SendMessage("클라이언트에서 보내는 값");
	}

	void OnApplicationQuit()
	{
		m_ThrdClientReceive.Abort();

		if (m_Client != null)
		{
			m_Client.Close();
			m_Client = null;
		}
	}

	void ConnectToTcpServer()
	{
		try
		{
			m_ThrdClientReceive = new Thread(new ThreadStart(ListenForData));
			m_ThrdClientReceive.IsBackground = true;
			m_ThrdClientReceive.Start();
		}
		catch (Exception ex)
		{
			Debug.Log(ex);
		}
	}
	
	void ListenForData()
	{
		try
		{
			m_Client = new TcpClient(m_Ip, m_Port);
			Byte[] bytes = new Byte[1024];
			while (true)
			{	
				using (NetworkStream stream = m_Client.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.Default.GetString(incommingData);
						Debug.Log(serverMessage); // 받은 값

					}
				}
			}
		}

		catch (SocketException ex)
		{
			Debug.Log(ex);
		}
	}

	void SendMessage(string message)
	{
		if (m_Client == null)
		{
			return;
		}

		try
		{			
			NetworkStream stream = m_Client.GetStream();

			if (stream.CanWrite)
			{
				byte[] clientMessageAsByteArray = Encoding.Default.GetBytes(message);
				stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
			}
		}

		catch (SocketException ex)
		{
			Debug.Log(ex);
		}
	}
}

 

728x90
반응형