Штамповка сети UDP работает и работает. Однако, когда дело доходит до TCP, возможно, что я пишу что-то не так, но я не начинающий программист, или, может быть, я чего-то не понимаю.
Конечно, я немного укоротю , мы предполагаем, что у нас уже есть что-то столь же тривиальное, как соединение с внешним сервером а не то, что работает.
Мы будем использовать класс TcpListener для сервера.
public void InitializeServer(IPAddress address, int port)
{
try
{
// 127.0.0.1 accept only local connections, 0.0.0.0 is open for whole internet connections
listener = new TcpListener(address, port);
socket = listener.Server;
// Enable NAT Translation
listener.AllowNatTraversal(true);
// Start listening for example 10 client requests.
listener.Start(listenQueue);
Debug.Log($"[L{socket.LocalEndPoint}]Server start... ", EDebugLvl.Log);
OnServerInitialize(true);
// Enter the listening loop.
StartListener();
}
catch (SocketException e)
{
Debug.LogError($"SocketException: {e}", EDebugLvl.Error);
OnServerInitialize(false);
}
}
Мы начинаем слушать
private void StartListener()
{
Debug.Log("\nWaiting for a connection... ");
listener.BeginAcceptTcpClient(AcceptCallback, listener);
}
Когда сервер получает соединение, мы создать новый сокет
private void AcceptCallback(IAsyncResult ar)
{
TcpListener server = (TcpListener)ar.AsyncState;
TcpClient newClient = null;
try
{
newClient = server.EndAcceptTcpClient(ar);
}
catch (Exception e)
{
Debug.LogError(e.ToString());
}
if (newClient != null && newClient.Connected)
{
//...
client.StartRead();
}
//Loop
StartListener();
}
Мы создаем новый сокет на клиенте и пытаемся установить sh соединение
public void Connect(IPEndPoint remote, IPEndPoint bind = null, bool reuseAddress = false)
{
if (bind == null)
{
client = new TcpClient();
}
else
{
client = new TcpClient(bind);
}
socket = client.Client;
if (reuseAddress)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
//It throws me a error SocketOption so im comment this.
//socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, reuseAddress);
}
client.BeginConnect(remote.Address, remote.Port, ConnectCallback, null);
}
Соединение работает без проблем и передачи данных.
К сожалению, здесь, как мы знаем, мы должны запустить новый сокет, прослушивающий тот же адрес и порт, который был создан при подключении к серверу. RVer. Я делаю это для каждого клиента.
public void StartHost(Client server)
{
if (server != null && server.socket.Connected)
{
IPEndPoint localHost = (IPEndPoint)server.socket.LocalEndPoint;
InitializeHost(localHost.Address, localHost.Port);
}
}
public void InitializeHost(IPAddress address, int port, bool reuse = false)
{
try
{
listener = new TcpListener(address, port);
socket = listener.Server;
if (reuse)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
}
// Enable NAT Translation
listener.AllowNatTraversal(true);
// Start listening for example 10 client requests.
listener.Start(listenQueue);
Debug.Log($"\n[L{socket.LocalEndPoint}]Host start... ", EDebugLvl.Log);
OnServerInitialize(true);
// Enter the listening loop.
StartListener();
}
catch (SocketException e)
{
Debug.LogError($"SocketException: {e}", EDebugLvl.Error);
OnServerInitialize(false);
}
}
private void StartListener()
{
Debug.Log("\nWaiting for a connection... ");
listener.BeginAcceptTcpClient(AcceptCallback, listener);
}
private void AcceptCallback(IAsyncResult ar)
{
TcpListener server = (TcpListener)ar.AsyncState;
TcpClient newClient = null;
try
{
newClient = server.EndAcceptTcpClient(ar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (newClient != null && newClient.Connected)
{
//...
client.StartRead();
}
//Loop
StartListener();
}
Итак, когда они пишут везде ... клиент "B" отправляет пакет на сервер, который хочет установить sh При соединении сервер отправляет информацию клиенту "A" о клиенте "B" и наоборот
Тогда оба они пытаются соединиться с новым сокетом? Нет проблем ...
public void Connect(IPEndPoint remote, IPEndPoint bind = null, bool reuseAddress = false)
{
if (bind == null)
{
client = new TcpClient();
}
else
{
client = new TcpClient(bind);
}
socket = client.Client;
if (reuseAddress)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
//socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, reuseAddress);
}
client.BeginConnect(remote.Address, remote.Port, ConnectCallback, null);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
client.EndConnect(ar);
}
catch (Exception e)
{
Debug.LogError(e.ToString(), EDebugLvl.ConnectionError);
}
if (client.Connected)
{
Debug.Log($"[P{socket.RemoteEndPoint}, L{socket.LocalEndPoint}]Connected", EDebugLvl.ConnectionLog);
stream = new NetworkStream(socket, FileAccess.ReadWrite, true);
StartRead();
}
ConnectedComplete(this, socket.Connected);
}
Независимо от того, сколько раз я пытаюсь, соединение отклоняется ... адреса совпадают везде, и все же это не работает, поэтому мне не о чем писать в этом случае, тем более, что у меня работает UDP.
То, что я написал, работает только в той же сети NAT. К сожалению, я заметил, что на одном и том же NAT созданы два соединения. Один - результат попытки подключить новый сокет A к B, а другой - результат получения нового подключения от B к A, поэтому у каждого клиента есть один ненужный сокет, связанный локальным адресом. Так что все NAT TCP / IP Punch NAT не работает для меня. Я действительно могу использовать UDP, но мне действительно нужен TCP. Я сидел на нем несколько месяцев в свободное время, но нигде не могу найти пример из кода, а не теорию, которой много. Я накопил много знаний за 8 лет, и из 2 я пишу приложения, используя сокеты, и, наконец, мне нужно пробить net.
Почему я не буду использовать готовое решение? Мне нужен мой собственный, который полностью открыт с использованием только UDP и TCP, потому что некоторые целевые устройства поддерживают только эти протоколы. Я также использовал класс Socket, но этот не дал мне рабочую копию.
Может быть, кто-то сможет мне помочь, за что я был бы очень благодарен, и, конечно, пост также поможет другим понять это.
С уважением Октавиан