C# 中的异步套接字没有环回
Sockets asynchronous in C# without loopback
我应该如何在两台不同的电脑之间异步使用套接字?出现我的问题是因为到目前为止,应用程序 运行 在环回中初始化同一台 PC 上的客户端和服务器。
但我不知道如何使用我所拥有的相同异步方案在两台远程 PC 之间建立连接。
这是我的听众:
public class Escuchar {
ManualResetEvent todoListo = new ManualResetEvent(false);
public delegate void Recibido(Serializador r);
public event Recibido objetoRecibido;
Socket escuchador;
public void Comenzar(int puerto) {
escuchador = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
escuchador.Bind(new IPEndPoint(IPAddress.Loopback, puerto));
Console.WriteLine("\n\nServidor iniciado.");
EsperarRespuesta();
}
public void EsperarRespuesta() {
todoListo.Reset();
escuchador.Listen(100);
escuchador.BeginAccept(Aceptar, escuchador);
}
public void Aceptar(IAsyncResult resultado) {
Serializador respuesta = new Serializador();
respuesta.Socket = ((Socket) resultado.AsyncState).EndAccept(resultado);
respuesta.Socket.BeginReceive(respuesta.buffer, 0, respuesta.buffer.Length, SocketFlags.None, Receive, respuesta);
}
public void Receive(IAsyncResult resultado) {
Serializador respuesta = (Serializador) resultado.AsyncState;
int read = respuesta.Socket.EndReceive(resultado);
if (read > 0) {
for (int i = 0; i < read; i++) {
respuesta.TransmisionBuffer.Add(respuesta.buffer[i]);
}
if (read == respuesta.buffer.Length) {
respuesta.Socket.BeginReceive(respuesta.buffer, 0, respuesta.buffer.Length, SocketFlags.None, Receive, respuesta);
Console.WriteLine("\n\nNo encaja!");
} else {
Listo(respuesta);
}
} else {
Listo(respuesta);
}
}
public void Listo(Serializador respuesta) {
Console.WriteLine("\n\nDeserializando respuesta...");
Serializador deserializado = respuesta.Deserializar();
objetoRecibido(deserializado);
todoListo.Set();
}
}
这是我的序列化程序:
[Serializable]
public class Serializador {
[NonSerialized]
public Socket Socket;
[NonSerialized]
public List < byte > TransmisionBuffer = new List < byte > ();
[NonSerialized]
public byte[] buffer = new byte[1024];
public ClaseGuardarJuego claseGuardarJuego = new ClaseGuardarJuego();
public byte[] Serializar() {
SoapFormatter formatter = new SoapFormatter();
MemoryStream mem = new MemoryStream();
formatter.Serialize(mem, this);
return mem.GetBuffer();
}
public Serializador Deserializar() {
try {
byte[] datosBuffer = TransmisionBuffer.ToArray();
SoapFormatter formatter = new SoapFormatter();
MemoryStream mem = new MemoryStream();
mem.Write(datosBuffer, 0, datosBuffer.Length);
mem.Seek(0, 0);
return (Serializador) formatter.Deserialize(mem);
} catch (SerializationException e) {
Console.WriteLine("\n\nFallo la deserializacion. Razón: " + e.Message);
return null;
}
}
}
这是我的发件人:
public class Enviar {
ManualResetEvent todoListo = new ManualResetEvent(false);
Serializador respuesta = new Serializador();
private int puerto;
public void ConfigurarClase(Juego game, Jugador player) {
respuesta.claseGuardarJuego.SetDatos(game, player);
}
public void Comenzar(int puerto) {
this.puerto = puerto;
Console.WriteLine("\n\nCliente esperando por una conexion...");
todoListo.Reset();
Socket emisor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
emisor.BeginConnect(new IPEndPoint(IPAddress.Loopback, puerto), Conectar, emisor);
todoListo.WaitOne();
}
public void Conectar(IAsyncResult resultado) {
try {
respuesta.Socket = (Socket) resultado.AsyncState;
respuesta.Socket.EndConnect(resultado);
byte[] buffer = respuesta.Serializar();
respuesta.Socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, Send, respuesta);
} catch (SocketException) {
Console.WriteLine("\n\nServidor caído, reintentando...");
Thread.Sleep(1000);
Comenzar(puerto);
}
}
public void Send(IAsyncResult result) {
Serializador respuesta = (Serializador) result.AsyncState;
int size = respuesta.Socket.EndSend(result);
Console.WriteLine("Enviando dato: " + respuesta.claseGuardarJuego.Jugador.NombreJugador);
todoListo.Set();
}
}
我知道我必须获取PC的IP地址然后发送,但我不知道如何应用。
唯一需要更改的是在连接时使用对方的 IP 地址而不是 IPAddress.Loopback
,因此
public void Comenzar(IPAdress ipAddress, int puerto) {
this.puerto = puerto;
Console.WriteLine("\n\nCliente esperando por una conexion...");
todoListo.Reset();
Socket emisor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
emisor.BeginConnect(new IPEndPoint(ipAddress, puerto), Conectar, emisor);
todoListo.WaitOne();
}
我应该如何在两台不同的电脑之间异步使用套接字?出现我的问题是因为到目前为止,应用程序 运行 在环回中初始化同一台 PC 上的客户端和服务器。
但我不知道如何使用我所拥有的相同异步方案在两台远程 PC 之间建立连接。
这是我的听众:
public class Escuchar {
ManualResetEvent todoListo = new ManualResetEvent(false);
public delegate void Recibido(Serializador r);
public event Recibido objetoRecibido;
Socket escuchador;
public void Comenzar(int puerto) {
escuchador = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
escuchador.Bind(new IPEndPoint(IPAddress.Loopback, puerto));
Console.WriteLine("\n\nServidor iniciado.");
EsperarRespuesta();
}
public void EsperarRespuesta() {
todoListo.Reset();
escuchador.Listen(100);
escuchador.BeginAccept(Aceptar, escuchador);
}
public void Aceptar(IAsyncResult resultado) {
Serializador respuesta = new Serializador();
respuesta.Socket = ((Socket) resultado.AsyncState).EndAccept(resultado);
respuesta.Socket.BeginReceive(respuesta.buffer, 0, respuesta.buffer.Length, SocketFlags.None, Receive, respuesta);
}
public void Receive(IAsyncResult resultado) {
Serializador respuesta = (Serializador) resultado.AsyncState;
int read = respuesta.Socket.EndReceive(resultado);
if (read > 0) {
for (int i = 0; i < read; i++) {
respuesta.TransmisionBuffer.Add(respuesta.buffer[i]);
}
if (read == respuesta.buffer.Length) {
respuesta.Socket.BeginReceive(respuesta.buffer, 0, respuesta.buffer.Length, SocketFlags.None, Receive, respuesta);
Console.WriteLine("\n\nNo encaja!");
} else {
Listo(respuesta);
}
} else {
Listo(respuesta);
}
}
public void Listo(Serializador respuesta) {
Console.WriteLine("\n\nDeserializando respuesta...");
Serializador deserializado = respuesta.Deserializar();
objetoRecibido(deserializado);
todoListo.Set();
}
}
这是我的序列化程序:
[Serializable]
public class Serializador {
[NonSerialized]
public Socket Socket;
[NonSerialized]
public List < byte > TransmisionBuffer = new List < byte > ();
[NonSerialized]
public byte[] buffer = new byte[1024];
public ClaseGuardarJuego claseGuardarJuego = new ClaseGuardarJuego();
public byte[] Serializar() {
SoapFormatter formatter = new SoapFormatter();
MemoryStream mem = new MemoryStream();
formatter.Serialize(mem, this);
return mem.GetBuffer();
}
public Serializador Deserializar() {
try {
byte[] datosBuffer = TransmisionBuffer.ToArray();
SoapFormatter formatter = new SoapFormatter();
MemoryStream mem = new MemoryStream();
mem.Write(datosBuffer, 0, datosBuffer.Length);
mem.Seek(0, 0);
return (Serializador) formatter.Deserialize(mem);
} catch (SerializationException e) {
Console.WriteLine("\n\nFallo la deserializacion. Razón: " + e.Message);
return null;
}
}
}
这是我的发件人:
public class Enviar {
ManualResetEvent todoListo = new ManualResetEvent(false);
Serializador respuesta = new Serializador();
private int puerto;
public void ConfigurarClase(Juego game, Jugador player) {
respuesta.claseGuardarJuego.SetDatos(game, player);
}
public void Comenzar(int puerto) {
this.puerto = puerto;
Console.WriteLine("\n\nCliente esperando por una conexion...");
todoListo.Reset();
Socket emisor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
emisor.BeginConnect(new IPEndPoint(IPAddress.Loopback, puerto), Conectar, emisor);
todoListo.WaitOne();
}
public void Conectar(IAsyncResult resultado) {
try {
respuesta.Socket = (Socket) resultado.AsyncState;
respuesta.Socket.EndConnect(resultado);
byte[] buffer = respuesta.Serializar();
respuesta.Socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, Send, respuesta);
} catch (SocketException) {
Console.WriteLine("\n\nServidor caído, reintentando...");
Thread.Sleep(1000);
Comenzar(puerto);
}
}
public void Send(IAsyncResult result) {
Serializador respuesta = (Serializador) result.AsyncState;
int size = respuesta.Socket.EndSend(result);
Console.WriteLine("Enviando dato: " + respuesta.claseGuardarJuego.Jugador.NombreJugador);
todoListo.Set();
}
}
我知道我必须获取PC的IP地址然后发送,但我不知道如何应用。
唯一需要更改的是在连接时使用对方的 IP 地址而不是 IPAddress.Loopback
,因此
public void Comenzar(IPAdress ipAddress, int puerto) {
this.puerto = puerto;
Console.WriteLine("\n\nCliente esperando por una conexion...");
todoListo.Reset();
Socket emisor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
emisor.BeginConnect(new IPEndPoint(ipAddress, puerto), Conectar, emisor);
todoListo.WaitOne();
}