2025-10-23 18:43:38 +09:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using UdpClientLib;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
public class SingleTcpClient : NetworkClientBase
|
|
|
|
|
{
|
|
|
|
|
private NetworkStream stream;
|
|
|
|
|
private System.Net.Sockets.TcpClient client;
|
|
|
|
|
private bool isConnected = false;
|
|
|
|
|
private readonly SemaphoreSlim requestSemaphore = new SemaphoreSlim(1, 1);
|
|
|
|
|
|
|
|
|
|
public async Task<bool> ConnectAsync(string name, string serverIp, int serverPort, int? localPort = null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Name = name;
|
|
|
|
|
_serverEndPoint = new IPEndPoint(IPAddress.Parse(serverIp), serverPort);
|
|
|
|
|
|
|
|
|
|
client = new System.Net.Sockets.TcpClient();
|
|
|
|
|
await client.ConnectAsync(serverIp, serverPort);
|
|
|
|
|
stream = client.GetStream();
|
|
|
|
|
isConnected = true;
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"TCP 서버에 연결되었습니다: {serverIp}:{serverPort}");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"연결 실패: {ex.Message}");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<bool> SendMessageAsync(string message)
|
|
|
|
|
{
|
|
|
|
|
if (!isConnected || stream == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("서버에 연결되지 않았습니다.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
byte[] data = Encoding.UTF8.GetBytes(message);
|
|
|
|
|
await stream.WriteAsync(data, 0, data.Length);
|
|
|
|
|
Console.WriteLine($"메시지 전송: {message}");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"메시지 전송 실패: {ex.Message}");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<string> ReceiveMessageAsync()
|
|
|
|
|
{
|
|
|
|
|
if (!isConnected || stream == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("서버에 연결되지 않았습니다.");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
byte[] buffer = new byte[4096];
|
|
|
|
|
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
|
|
|
|
|
|
|
|
|
|
if (bytesRead == 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("서버와의 연결이 끊어졌습니다.");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
|
|
|
|
|
|
|
|
|
|
return message;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"메시지 수신 실패: {ex.Message}");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Disconnect()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
isConnected = false;
|
|
|
|
|
stream?.Close();
|
|
|
|
|
client?.Close();
|
|
|
|
|
Console.WriteLine("서버와의 연결을 종료했습니다.");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"연결 종료 중 오류: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<String> SendHttpRequestAsync(HttpRequest request)
|
|
|
|
|
{
|
|
|
|
|
//await requestSemaphore.WaitAsync();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
string httpPacket = CreateHttpRequest(request);
|
|
|
|
|
|
|
|
|
|
await SendMessageAsync(httpPacket);
|
|
|
|
|
|
|
|
|
|
return await ReceiveMessageAsync();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
// requestSemaphore.Release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 편의 메서드들
|
2025-11-19 18:38:48 +09:00
|
|
|
public Task<String> SendGetRequestAsync(string path, Dictionary<string, string> headers = null, CancellationToken token = default)
|
|
|
|
|
=> SendHttpRequestAsync(new HttpRequest(UdpClientLib.HttpMethod.GET, path, headers, null, token));
|
2025-10-23 18:43:38 +09:00
|
|
|
|
2025-11-19 18:38:48 +09:00
|
|
|
public Task<String> SendPostRequestAsync(string path, object body = null, Dictionary<string, string> headers = null, CancellationToken token = default)
|
2025-10-23 18:43:38 +09:00
|
|
|
{
|
|
|
|
|
string jsonBody;
|
|
|
|
|
|
|
|
|
|
if (body == null)
|
|
|
|
|
{
|
|
|
|
|
jsonBody = null;
|
|
|
|
|
}
|
|
|
|
|
else if (body is string str)
|
|
|
|
|
{
|
|
|
|
|
jsonBody = str;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
jsonBody = JsonConvert.SerializeObject(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SendHttpRequestAsync(new HttpRequest(UdpClientLib.HttpMethod.POST, path, headers, jsonBody));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsConnected => isConnected && client?.Connected == true;
|
|
|
|
|
}
|
|
|
|
|
|