I try to send data from my PC (server) to my HoloLens (client) in UWP apps.
My primary goal is to use "Windows.Networking.Sockets.DatagramSocket" for the HoloLens receiver because else the code does not work in unity.
I already accomplished the system with wrong roles. The HoloLens sends data to the PC but with "System.Net.Sockets.UdpClient" instead of DatagramSocket...
Here you can see the important code parts:
// Current client application on PC (using System.Net.Sockets...)
HostName serverIp = new HostName("192.168.0.109");
string port = "1337";
async void Client()
{
DatagramSocket socket = new DatagramSocket(); //creating socket
socket.MessageReceived += Socket_MessageReceived; //attach receive event
await socket.BindEndpointAsync(serverIp, port); //bind socket
}
async void Socket_MessageReceived(DatagramSocket sender,
DatagramSocketMessageReceivedEventArgs args) //receive event
{
Stream streamIn = args.GetDataStream().AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
string msg = await reader.ReadLineAsync();
Print("Message received: " + msg);
}
// Current Server application on HoloLens (using Windows.Networking.Sockets...)
IPAddress serverIp = IPAddress.Parse("192.168.0.109");
const int port = 1337;
async void Server()
{
var udpClient = new UdpClient();
var serverEP = new IPEndPoint(serverIp, port);
byte[] bytes = Encoding.ASCII.GetBytes("Hello from Client!"); //parse
await udpClient.SendAsync(bytes, bytes.Length, serverEP); //send
}
The PC succesfully receives the message from the HoloLens.
My problem: When I swap server and client application on the devices that the PC sends (with UdpClient) and the HoloLens receives (with DatagramSocket), the message is not received anymore.
Both devices have connection to the network, I disabled firewall at the PC and in both appxmanifests "PrivateNetworks" is enabled.
Does anybody can figure the reasons?
Kind Regards
I somehow made it work but I unfortunately can't tell the difference.
My problem now is that the communication only works in one direction. I can write to the socket and the message arrives but I can't send messages from the socket back.
When I want to write from a socket I must not use "socket.BindEndpointAsync()" but "socket.ConnectAsync()" right? But no matter if I use a DataWriter or the OutputStream attribute no message can be received by my actually working receiver.
writer = new DataWriter(socket.OutputStream);
writer.WriteString("test");
IBuffer buffer = Encoding.ASCII.GetBytes("test").AsBuffer();
await socket.OutputStream.WriteAsync(buffer);
Maybe somebody can help me.
Kind regards
Related
I am a C#/WPF developer and have not many experience in network-communication (socket/tcp) and just trying to get a simple working example for a TCP-Listener-project for exchanging messages between server and client.
I think Im nearly there where I want to come to, but have an open issue left: When I start the server and after that the client, the messages get exchanged like wanted. After that I close the client and restart it, the second connection gets refused (at "await client.ConnectAsync(ipEndPoint)") with following message (sorry, its translated from german to english):
"A connection could not be established because the target computer refused the connection"
Do you maybe have any hint for me, what I am doing wrong? I also tried closing clients connection in the client app, but same behaviour.
Server-code:
public async Task<bool> StartServer()
{
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, 8888);
using Socket listener = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(100);
Socket client = await listener.AcceptAsync();
while (true)
{
var buffer = new byte[1_024];
var received = client.Receive(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
var eom = "<|EOM|>";
if (response.IndexOf(eom) > -1 /* is end of message */)
{
AddLogText($"Socket server received message: \"{response.Replace(eom, "")}\"");
var ackMessage = "Hallo Client!<|ACK|>";
var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
await client.SendAsync(echoBytes, 0);
AddLogText($"Socket server sent acknowledgment: \"{ackMessage}\"");
break;
}
}
client.Shutdown(SocketShutdown.Both);
client.Close();
return true;
}
Client Code:
private async Task<bool> StartClient()
{
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, 8888);
using Socket client = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
await client.ConnectAsync(ipEndPoint);
while (true)
{
var message = "Hallo Server?<|EOM|>";
var messageBytes = Encoding.UTF8.GetBytes(message);
_ = await client.SendAsync(messageBytes, SocketFlags.None);
Console.WriteLine($"Socket client sent message: \"{message}\"");
var buffer = new byte[1_024];
var received = await client.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
if (response.Contains("<|ACK|>"))
{
Console.WriteLine($"Socket client received acknowledgment: \"{response}\"");
break;
}
}
return true;
}
Your StartServer method returns after the first client socket finishes, disposing the listening socket.
Usually, you want to keep the listening socket open and listening, and call AcceptAsync in an infinite loop.
But I have to caution you: socket programming is extremely difficult. For example, your socket reading code is far too simplistic to properly handle message framing. I recommend self-hosting ASP.NET or something else that handles the protocol-level details for you.
You might have misunderstood how the server works. It should be like this:
Create a socket and call Bind and Listen. This part is okay.
Call Accept, which waits for a client to connect, and then returns a socket connected to that specific client.
Send and receive data from the client.
If you want to wait for another client, after you are done with the first one, then of course you need to call Accept again.
It is also common for servers to handle several clients at the same time, for example by using threads (or async). One thread just calls Accept over and over, and whenever a new client connects, it starts a new thread to handle that client. You don't need this for a toy program, that only handles one connection at a time. But you do need it for a real server, otherwise one client can connect, and be really slow, and your server won't handle any other clients while that is happening.
If you are not doing a "graceful close" there is no need to call Shutdown - you can just Close the client's socket to disconnect the client. When you Close the main server socket you stop accepting new connections. Shutdown doesn't apply to the main server socket.
I am listening for connections through a Windows Universal App and would like to connect to that App through a Windows Console Application. I have done some basic code which I think should connect but I get a timeout error from the console application.
{"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 192.168.0.5:1771"}
The windows universal app never even goes into the connection received function.
The Server (UWP):
public async void SetupServer()
{
try
{
//Create a StreamSocketListener to start listening for TCP connections.
Windows.Networking.Sockets.StreamSocketListener socketListener = new Windows.Networking.Sockets.StreamSocketListener();
//Hook up an event handler to call when connections are received.
socketListener.ConnectionReceived += SocketListener_ConnectionReceived;
//Get Our IP Address that we will host on.
IReadOnlyList<HostName> hosts = NetworkInformation.GetHostNames();
HostName myName = hosts[3];
//Assign our IP Address
ipTextBlock.Text = myName.DisplayName+":1771";
ipTextBlock.Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255,0,255,0));
//Start listening for incoming TCP connections on the specified port. You can specify any port that' s not currently in use.
await socketListener.BindEndpointAsync(myName, "1771");
}
catch (Exception e)
{
//Handle exception.
}
}
The Client (Console Application):
static void Main(string[] args)
{
try
{
byte[] data = new byte[1024];
int sent;
string ip = "192.168.0.5";
int port = 1771;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port);
TcpClient client = new TcpClient();
client.Connect(ipep); //**************Stalls HERE************
using (NetworkStream ns = client.GetStream())
{
using (StreamReader sr = new StreamReader(ns))
{
using (StreamWriter sw = new StreamWriter(ns))
{
sw.WriteLine("Hello!");
sw.Flush();
System.Threading.Thread.Sleep(1000);
Console.WriteLine("Response: " + sr.ReadLine());
}
}
}
}
catch (Exception e)
{
}
}
I have tested your code on my side and it can work well. So there is nothing wrong with your code. But I can reproduce your issue by running the server and client on the same device, the client will throw the same exception as you showed above. So please ensure you're connecting from another machine. We cannot connect to a uwp app StreamSocketListener from another app or process running on the same machine,this is not allowed. Not even with a loopback exemption.
Please also ensure the Internet(Client&Server) capability is enabled. And on the client you can ping the server 192.168.0.5 successfully.
I seem to be having a hard time figuring out how to get my client app to automatically connect to a server app running on a separate machine on my LAN.
Right now the only way I'm able to get the client to connect to the server is by manually specifying the server's IP address in code:
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = neIPEndPoint(IPAddress.Parse("Server IP address goes here"), 8888);
My server app uses a TCP Listener, so I figured my client could do something similar, to be able to find the server, but I can't figure out how to implement it in code.
Code from my server app for finding the client to connect to:
private TcpListener tcpListener;
private Thread listenThread;
private int connectedClients = 0;
private delegate void WriteMessageDelegate(string msg);
public Form1()
{
InitializeComponent();
Server();
}
private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
I've tried using a TextBox that the user can manually enter their server's IP address into (since they wouldn't have access to the code), but I think an automatic connection would be much more user friendly, especially since I don't know how to permanently save the user's server IP address if they use the above method of setting the IP for the client to connect to.
So, my question is: What would be the best method for me to enable my client to automatically connect to a server running on my LAN?
Thanks,
Patrick
UPDATE
I tried implementing the code for a UDP broadcast, but I can't seem to get it working.
Here is what I've added to my client (Along with the client code I had in there before):
public partial class Console : Form
{
//FIND SERVER
private void FindServer()
{
var Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("SomeRequestData");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, 8888));
var ServerResponseData = Client.Receive(ref ServerEp);
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
Console.WriteLine("Recived {0} from {1}", ServerResponse, ServerEp.Address.ToString());
Client.Close();
}
// SEND MESSAGES TO SERVER (VIA USER INTERACTION)
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("My IP Address was here (I tried changing it to "broadcast" as well"), 8888);
public Console()
{
InitializeComponent();
client.Connect(serverEndPoint);
}
private void SendMessage(string msg)
{
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
Here is what I've added to my server code:
private void BroadcastToClients()
{
var Server = new UdpClient(8888);
var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData");
while (true)
{
var ClientEp = new IPEndPoint(IPAddress.Any, 0);
var ClientRequestData = Server.Receive(ref ClientEp);
var ClientRequest = Encoding.ASCII.GetString(ClientRequestData);
Console.WriteLine("Recived {0} from {1}, sending response", ClientRequest, ClientEp.Address.ToString());
Server.Send(ResponseData, ResponseData.Length, ClientEp);
}
}
I'd imagine there must be some conflicting code in there, but since I'm so new to this, I can't seem to figure it out...
UPDATE
I've still not managed to make any progress on this. Anyone out there that might be able to chime in and help me figure out why this isn't working for me?
Your client app can send a broadcast on the local subnet, on startup, 'asking for server'.
Your server will be listening for that message, and replies to the client.
Now the client knows the server's IP address and can start the TCP connection.
You have it here: C# How to do Network discovery using UDP Broadcast
I'm having a bit of trouble in getting a very simple TCP client working on my HTC Titan w/ Windows Phone 7.5.
When the USB cable is attached to the phone, the TCP client works like a charm, but as soon as the cable is unplugged, the client is unable to connect to a TCP server running on my development machine. The devices are on the same network and I'm using the explicit IP-address of my desktop machine to connect, so there's no name resolution going on afaik.
Here's the code I use. Most of it was taken from the Sockets samples on MSDN (can't seem to find the link now though).
private Socket _sock = null;
private ManualResetEvent _done = new ManualResetEvent(false);
private const int TIMEOUT = 5000;
//connect to server
public string Connect(string ip, int port) {
string result = string.Empty;
var host = new IPEndpoint(IPAddress.Parse(ip), port);
_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_sock.SetNetworkRequirement(NetworkSelectionCharacteristics.NonCellular);
var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = host;
args.Completed += new EventHandler((s,e) => {
result = e.SocketError.ToString();
_done.Set();
});
_done.Reset();
_sock.ConnectAsync(args);
_done.WaitOne(TIMEOUT);
return result;
}
//send message
public string Send(string msg) {
string response = "Operation timeout";
if (_sock != null) {
var args= new SocketAsyncEventArgs();
args.RemoteEndPoint = _sock.RemoteEndPoint;
args.Completed += new EventHandler(s, e) => {
response = e.SocketError.ToString();
_done.Set();
});
var payload = Encoding.UTF8.GetBytes(data);
args.SetBuffer(payload, 0, payload.Length);
_done.Reset();
_sock.SendAsync(args);
_done.WaitOne(TIMEOUT);
}
return response;
}
//receive message
public string Receive() {
string response = "Operation timeout";
if (_sock != null) {
var args= new SocketAsyncEventArgs();
args.RemoteEndPoint = _sock.RemoteEndPoint;
args.SetBuffer(new Byte[MAX_BUFSIZE], 0, MAX_BUFSIZE);
args.Completed += new EventHandler((s,e) => {
if (e.SocketError == SocketError.Success) {
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else {
response = e.SocketError.ToString();
}
_done.Set();
});
_done.Reset();
_sock.ReceiveAsync(args);
_done.WaitOne(TIMEOUT);
}
return response;
}
The code is then simply used like:
Connect(...);
Send(...);
Receive(...);
//and then close the socket
As I said before, the code works like a charm when the device is attached to my development machine. When the cable is unplugged, the connection phase just times out (regardless of the timeout interval I should say).
Also, the manifest contains the ID_CAP_NETWORKING capability which as I understand it should give the app permission to access the network.
Any ideas?
EDIT:
I discovered that switching to UDP communication works like a charm. Which means that the problem is that for some reason, the phone is unable to set up a persistant TCP connection to my dev machine. This is getting stranger by the minute.
Do you have a wireless ap nearby on which your phone is connected? because when you plug it in the pc it uses the pc's network connection.
You should check the IP address that you have on both the phone (from your code) and on the PC (which it looks like you've already found using ipconfig in your command prompt).
These should be in the same IP address range, and so start with the same digits (for IPv4, probably something link 192.168.0.*).
If this all matches up check your wireless router hasn't enabled a security setting which means that it doesn't allow TCP traffic from your phone to your PC.
If this is a consumer router you manage this should be fairly simple to verify (and potentially fix). If not, you're probably stuck...
i have a GPS device that will be installed in many trucks.
i can configure the device to send data statement "gps data, device id" over gprs to IP and Port.
i'm using TcpListener class to read the data on the server side.
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.Write("Connected!");
data = null; int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
}
}
that method is listening to what is coming on server ip and port.
i want to know if i configured the devices to send to the server on the same port.am i able to listen to all the devices or the first device to connect will be the only one ?
is this method the the best way to read the coming data from the devices?
do i need to configure a different port for each device and create a new listen thread for each device port?
sometimes i'm facing exceptions "the request channel timed out while waiting for a reply"
many thanks in advance for your help.
In your code you are listening to the all devices but only after finish read all data from the first device so you are receiving "the request channel timed out while waiting for a reply".You should have a different threads each one handle a tcpClient.
so the code should be something like:
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("new client connected");
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleClient), client);//or use Task if 4.0 or new Thread...
}
}
private void HandleClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
Byte[] bytes = new Byte[256];
String data = null;
int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
Console.WriteLine(data);
}
1) Both. You should be able to listen for all devices, but you often cannot with your code because the listener thread is tied up waiting for the stream from a device that connected earlier.
2) Probably not. IIRC, NetworkStream.Read returns 0 when the connection is closed by the peer device. Is this your protocol - ie. the device connects, sends some data and disconnects? If so that will work, though slowly. Anyway, there is another problem. You should be concatenating the bytes received on your stream to data, not just replacing them - Read() my return multiple times for one communication, perhaps even with a single byte each time, (unlikely, but permitted with TCP streams). You could keep a count of bytes rx. so far and use the 'offset' parameter to do this.
3) You only need one listening thread, ie. the one that calls AcceptTcpClient(). This thread should not be making blocking calls to receive data from the socket returned by AcceptTcpClient(). Either create/allocate/depool/whatever a new client-server thread to run your Read() loop for each 'client' socket returned by AcceptTcpClient() or use asynchronous IO.
4) Your single listener/read thread will be non-responsive for new connections while it is waiting on the NetworkStream - other devices will be unable to connect. The listener should get back to AcceptTcpClient() quickly and not wait for slow networks/devices to send data.
Rgds,
Martin