The core element of my project is the connection through local network between two applications ( client and server ) using sockets. I've followed many tutorials and the most stable version is the one I am about to post below.
So I was ready to implement it on my Xamarin application and for one time ( the first time ) it worked. I've even tested it on my android smartphone ( as client ) and UWP on windows ( as server ). After that first time it never worked again. Neither on my Desktop nor my Laptop. I've literally changed nothing and it stopped working.
At my first touch with sockets and Xamarin I though that it just don't work. But after that one-working time. It must not be that.
TROUBLESHOOTING
I am getting on the client classes ( ClientSocket ) on ClientSocket.Connect -> _socket.BeginConnect = false
I will try and upload a dropbox link ( for my files )
Server code :
namespace Control
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
}
private void ServerConnectBtn_Clicked(object sender, EventArgs e)
{
ServerSocket.Bind(9000);
ServerSocket.Listen(500);
ServerSocket.Accept();
msg_lbl.Text = PacketHandler.status;
}
}
}
My server classes:
namespace Control.Server
{
class ServerSocket
{
private static Socket _socket;
private static byte[] _buffer = new byte[1024];
public ServerSocket()
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public static void Bind(int port)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
}
public static void Listen(int backlog)
{
_socket.Listen(500);
}
public static void Accept()
{
_socket.BeginAccept(AcceptedCallback, null);
}
private static void AcceptedCallback(IAsyncResult result)
{
Socket clientSocket = _socket.EndAccept(result);
_buffer = new byte[1024];
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
Accept();
}
private static void ReceivedCallback(IAsyncResult result)
{
Socket clientSocket = result.AsyncState as Socket;
int bufferSize = clientSocket.EndReceive(result);
byte[] packet = new byte[bufferSize];
Array.Copy(_buffer, packet, packet.Length);
//Handle the packet
PacketHandler.Handle(packet, clientSocket);
_buffer = new byte[1024];
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
}
}
}
namespace Control.Server
{
public abstract class PacketStructure
{
private byte[] _buffer;
public PacketStructure(ushort length, ushort type)
{
_buffer = new byte[length];
WriteUshort(length, 0);
WriteUshort(type, 2);
}
public PacketStructure(byte[] packet)
{
_buffer = packet;
}
public void WriteUshort(ushort value, int offset)
{
byte[] tempbuffer = new byte[2];
tempbuffer = BitConverter.GetBytes(value);
Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, 2);
}
public short ReadUshort(int offset)
{
return BitConverter.ToInt16(_buffer, offset);
}
public void WriteUint(uint value, int offset)
{
byte[] tempbuffer = new byte[4];
tempbuffer = BitConverter.GetBytes(value);
Buffer.BlockCopy(tempbuffer, 0, _buffer, offset,4);
}
public void WriteString(string value, int offset)
{
byte[] tempbuffer = new byte[value.Length];
tempbuffer = Encoding.UTF8.GetBytes(value);
Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, value.Length);
}
public string ReadString(int offset, int count)
{
return Encoding.UTF8.GetString(_buffer, offset, count);
}
public byte[] Data { get { return _buffer; } }
}
}
namespace Control.Server
{
public static class PacketHandler
{
public static string status;
public static void Handle(byte[] packet, Socket clientSocket)
{
ushort packetLength = BitConverter.ToUInt16(packet, 0);
ushort packetType = BitConverter.ToUInt16(packet, 2);
status = "Received packet! Length: "+ packetLength + " | Type: "+ packetType;
switch (packetType)
{
case 2000:
Message msg = new Message(packet);
Console.WriteLine(msg.Text);
break;
}
}
}
}
namespace Control.Server
{
public class Message : PacketStructure
{
private string _message;
public Message(string message)
: base((ushort)(4 + message.Length), 2000)
{
Text = message;
}
public Message(byte[] packet)
: base(packet)
{
}
public string Text
{
get { return ReadString(4, Data.Length - 4); }
set
{
_message = value;
WriteString(value, 4);
}
}
}
}
Client code:
namespace Remote
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SettingsPage : ContentPage
{
public SettingsPage()
{
InitializeComponent();
}
private void ClientConnectBtn_Clicked(object sender, EventArgs e)
{
ClientSocket.Connect("192.168.1.17",9000);
Status_lbl.Text = "Status : " +ClientSocket.status;
}
private void Send_Clicked(object sender, EventArgs e)
{
string msg = msgEntry.Text;
Message packet = new Message(msg);
ClientSocket.Send(packet.Data);
Status_lbl.Text = "Status : " + ClientSocket.status;
}
}
}
Client Classes
namespace Remote.Client
{
public abstract class PacketStructure
{
private byte[] _buffer;
public PacketStructure(ushort length, ushort type)
{
_buffer = new byte[length];
WriteUshort(length, 0);
WriteUshort(type, 2);
}
public PacketStructure(byte[] packet)
{
_buffer = packet;
}
public void WriteUshort(ushort value, int offset)
{
byte[] tempbuffer = new byte[2];
tempbuffer = BitConverter.GetBytes(value);
Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, 2);
}
public short ReadUshort(int offset)
{
return BitConverter.ToInt16(_buffer, offset);
}
public void WriteUint(uint value, int offset)
{
byte[] tempbuffer = new byte[4];
tempbuffer = BitConverter.GetBytes(value);
Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, 4);
}
public void WriteString(string value, int offset)
{
byte[] tempbuffer = new byte[value.Length];
tempbuffer = Encoding.UTF8.GetBytes(value);
Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, value.Length);
}
public string ReadString(int offset, int count)
{
return Encoding.UTF8.GetString(_buffer, offset, count);
}
public byte[] Data { get { return _buffer; } }
}
}
namespace Remote.Client
{
public class Message : PacketStructure
{
private string _message;
public Message(string message)
:base((ushort)(4 + message.Length), 2000)
{
Text = message;
}
public Message(byte[] packet)
:base(packet)
{
}
public string Text
{
get { return ReadString(4, Data.Length - 4); }
set
{
_message = value;
WriteString(value, 4);
}
}
}
}
namespace Remote.Client
{
class ClientSocket
{
private static Socket _socket;
private static byte[] _buffer;
public static string status;
public ClientSocket()
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public static void Connect(string ipAddress, int port)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), ConnectCallback, null);
}
private static void ConnectCallback(IAsyncResult result)
{
if (_socket.Connected)
{
status = "Connected to the server!";
_buffer = new byte[1024];
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
// throw new Exception("Conencted");
}
else
{
status = "Could not connect";
// throw new Exception("Could not connect");
}
}
private static void ReceiveCallback(IAsyncResult result)
{
int bufLength = _socket.EndReceive(result);
byte[] packet = new byte[bufLength];
Array.Copy(_buffer, packet, packet.Length);
//Handle packet
_buffer = new byte[1024];
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
public static void Send(byte[] data)
{
_socket.Send(data);
}
}
}
I managed to achieve the proper connections by enabling loopback
as @NicoZhi-MSFT said.
Have you enabled uwp app's loopback and private network capability?
Please check this document to enable this app loop back
I've only ran the commands for the server's side from this link and it seems to be working just fine. But by have Private Network
always enabled.
So if you can make the UWP application run cmd commands
every time the server needs to start or by settings an automatic task (following the instructions for the link above) it should be ok.
TIP:
UWP is not very handy on running CMD commands
so if needed for anyone can look for UWP fulltrust
or/and by setting an external application that runs when needed in the background
Many thanks
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.