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++와의 통신
- 클래스 : Socket
- 개체 직렬화 : Marshal
- 전송 패킷 : 구조체 ↔ 바이트 배열
2. 소스
2.1 Server.cs
using UnityEngine;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using System;
using System.Runtime.InteropServices;
public class Server : MonoBehaviour
{
private Socket m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public int m_Port = 50001;
public ToServerPacket m_ReceivePacket = new ToServerPacket();
public ToClientPacket m_SendPacket = new ToClientPacket();
private List<Socket>m_Clients = new List<Socket>();
void Awake()
{
InitServer();
}
void InitServer()
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, m_Port);
m_Socket.Bind(ipEndPoint);
m_Socket.Listen(100);
// SendPacket에 배열이 있으면 선언 해 주어야 함.
m_SendPacket.m_IntArray = new int[2];
}
void Start()
{
Debug.Log("클라이언트들을 기다립니다...");
}
void Update()
{
Accept();
CheckClientList();
if (m_Clients.Count > 0)
{
Receive();
Send();
}
}
void OnApplicationQuit()
{
CloseServer();
}
void Accept()
{
List<Socket> clinets = new List<Socket>();
clinets.Add(m_Socket);
Socket.Select(clinets, null, null, 1000);
for (int i = 0; i < clinets.Count; i++)
{
Socket newSocket = ((Socket)clinets[i]).Accept();
m_Clients.Add(newSocket);
Debug.Log("Did connect");
}
}
void CheckClientList()
{
for (int i = 0; i < m_Clients.Count; i++)
{
if (!IsConnected(m_Clients[i]))
{
m_Clients.RemoveAt(i);
}
}
}
bool IsConnected(Socket socket)
{
try
{
if (socket != null && socket != null && socket.Connected)
{
if (socket.Poll(0, SelectMode.SelectRead))
{
return !(socket.Receive(new byte[1], SocketFlags.Peek) == 0);
}
return true;
}
return false;
}
catch
{
return false;
}
}
void Receive()
{
for (int i = 0; i < m_Clients.Count; i++)
{
byte[] packet = new byte[1024];
int receive = m_Clients[i].Receive(packet);
m_ReceivePacket = ByteArrayToStruct<ToServerPacket>(packet);
if (receive > 0)
{
DoReceivePacket(); // 받은 값 처리
}
}
}
void DoReceivePacket()
{
Debug.LogFormat($"m_IntArray[0] = {m_ReceivePacket.m_IntArray[0]} " +
$"m_IntArray[1] = {m_ReceivePacket.m_IntArray[1] } " +
$"FloatlVariable = {m_ReceivePacket.m_FloatlVariable} " +
$"StringlVariable = {m_ReceivePacket.m_StringlVariable}" +
$"BoolVariable = {m_ReceivePacket.m_BoolVariable} " +
$"IntlVariable = {m_ReceivePacket.m_IntVariable} ");
//출력: m_IntArray[0] = 7 m_IntArray[1] = 47 FloatlVariable = 2020 StringlVariable = Coder ZeroBoolVariable = True IntlVariable = 13
}
void Send()
{
for (int i = 0; i < m_Clients.Count; i++)
{
try
{
SetSendPacket();
byte[] sendPacket = StructToByteArray(m_SendPacket);
m_Clients[i].Send(sendPacket, 0, sendPacket.Length, SocketFlags.None);
}
catch (Exception ex)
{
Debug.Log(ex);
return;
}
}
}
void SetSendPacket()
{
m_SendPacket.m_BoolVariable = true;
m_SendPacket.m_IntVariable = 13;
m_SendPacket.m_IntArray[0] = 7;
m_SendPacket.m_IntArray[1] = 47;
m_SendPacket.m_FloatlVariable = 2020;
m_SendPacket.m_StringlVariable = "Coder Zero";
}
void CloseServer()
{
if (m_Socket != null)
m_Socket.Close();
m_Socket = null;
for (int i = 0; i < m_Clients.Count; i++)
{
m_Clients[i].Close();
}
m_Clients.Clear();
}
byte[] StructToByteArray(object obj)
{
int size = Marshal.SizeOf(obj);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
T ByteArrayToStruct<T>(byte[] buffer) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
if (size > buffer.Length)
{
throw new Exception();
}
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(buffer, 0, ptr, size);
T obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
Marshal.FreeHGlobal(ptr);
return obj;
}
}
2.2 Client.cs
using System;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
public class Client : MonoBehaviour
{
public string m_Ip = "127.0.0.1";
public int m_Port = 50001;
private IPEndPoint m_IpEndPoint;
public ToServerPacket m_SendPacket = new ToServerPacket();
public ToClientPacket m_ReceivePacket = new ToClientPacket();
private bool m_IsConnected;
private Socket m_Socket;
void Awake()
{
InitSocket();
if (!m_IsConnected)
ConnectServer();
}
void OnApplicationQuit()
{
CloseSocket();
}
void Update()
{
if (!m_IsConnected)
ConnectServer();
else
{
Send();
Receive();
}
}
void InitSocket()
{
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse(m_Ip);
m_IpEndPoint = new IPEndPoint(ipAddress, m_Port);
// SendPacket에 배열이 있으면 선언 해 주어야 함.
m_SendPacket.m_IntArray = new int[2];
}
void ConnectServer()
{
try
{
m_Socket.Connect(m_IpEndPoint);
m_IsConnected = true;
}
catch (SocketException ex)
{
//Debug.Log(ex.Message);
}
}
void CloseSocket()
{
m_Socket.Close();
m_Socket = null;
}
void SetSendPacket()
{
m_SendPacket.m_BoolVariable = true;
m_SendPacket.m_IntVariable = 13;
m_SendPacket.m_IntArray[0] = 7;
m_SendPacket.m_IntArray[1] = 47;
m_SendPacket.m_FloatlVariable = 2020;
m_SendPacket.m_StringlVariable = "Coder Zero";
}
void Receive()
{
int receive = 0;
try
{
byte[] receivedbytes = new byte[512];
receive = m_Socket.Receive(receivedbytes);
m_ReceivePacket = ByteArrayToStruct<ToClientPacket>(receivedbytes);
}
catch (Exception ex)
{
Debug.Log(ex);
return;
}
if (receive > 0)
{
DoReceivePacket(); // 받은 값 처리
}
}
void DoReceivePacket()
{
Debug.LogFormat($"BoolVariable = {m_ReceivePacket.m_BoolVariable} " +
$"IntlVariable = {m_ReceivePacket.m_IntVariable} " +
$"m_IntArray[0] = {m_ReceivePacket.m_IntArray[0]} " +
$"m_IntArray[1] = {m_ReceivePacket.m_IntArray[1] } " +
$"FloatlVariable = {m_ReceivePacket.m_FloatlVariable} " +
$"StringlVariable = {m_ReceivePacket.m_StringlVariable}");
//출력: BoolVariable = True IntlVariable = 13 m_IntArray[0] = 7 m_IntArray[1] = 47 FloatlVariable = 2020 StringlVariable = Coder Zero
}
void Send()
{
try
{
SetSendPacket();
byte[] sendPacket = StructToByteArray(m_SendPacket);
m_Socket.Send(sendPacket);
}
catch (SocketException ex)
{
Debug.Log(ex.Message);
}
}
byte[] StructToByteArray(object obj)
{
int size = Marshal.SizeOf(obj);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
T ByteArrayToStruct<T>(byte[] buffer) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
if (size > buffer.Length)
{
throw new Exception();
}
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(buffer, 0, ptr, size);
T obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
Marshal.FreeHGlobal(ptr);
return obj;
}
}
2.3 Packets.cs
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
[Serializable]
public struct ToClientPacket
{
[MarshalAs(UnmanagedType.Bool)]
public bool m_BoolVariable;
public int m_IntVariable;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] m_IntArray;
public float m_FloatlVariable;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string m_StringlVariable;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
[Serializable]
public struct ToServerPacket
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] m_IntArray;
public float m_FloatlVariable;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string m_StringlVariable;
[MarshalAs(UnmanagedType.Bool)]
public bool m_BoolVariable;
public int m_IntVariable;
}
728x90
반응형
'프로그램 > 유니티 네트워크' 카테고리의 다른 글
[유니티 네트워크] 파일 전송(File Transfer) (0) | 2021.02.02 |
---|---|
[유니티 네트워크] 멀티 스레드 1:N TcpServer, TcpClient 문자열 전송 (TcpListener, TcpClient) (0) | 2021.02.02 |
[유니티 네트워크] FTP(File Transfer Protocol) (2) | 2021.02.02 |
[유니티 네트워크] TcpServer, TcpClient 구조체 전송 (Socket) (0) | 2020.08.05 |
[유니티 네트워크] Multicast Sender, Multicast Receiver 구조체 전송 (UdpClient) (1) | 2020.08.05 |