I'm trying to use a udp socket as server in Flutter. I'd like to bind this socket on my localhost at 6868 port always in listening. Unfortunately when i try to send something from a client,it never prints the string "RECEIVED".
Here's the code:
static Future openPortUdp(Share share) async {
await RawDatagramSocket.bind(InternetAddress.anyIPv4,6868)
.then(
(RawDatagramSocket udpSocket) {
udpSocket.listen((e) {
switch (e) {
case RawSocketEvent.read:
print("RECEIVED");
print(String.fromCharCodes(udpSocket.receive().data));
break;
case RawSocketEvent.readClosed:
print("READCLOSED");
break;
case RawSocketEvent.closed:
print("CLOSED");
break;
}
});
},
);
}
Am I doing something wrong?
Anyway this is the client side, it is written is Lua:
local udp1 = socket.udp()
while true do
udp1:setpeername("192.168.1.24", 6868)
udp1:send("HI")
local data1 = udp1:receive()
if (not data1 == nil) then print(data1) break end
udp1:close()
end
I tested it with another server and it works well, so i don't think the client is the problem.
Thanks!
If it can help you, here my code for my SocketUDP (as singleton) in my app.
I used it in localhost and it works very well :
class SocketUDP {
RawDatagramSocket _socket;
// the port used by this socket
int _port;
// emit event when receive a new request. Emit the request
StreamController<Request> _onRequestReceivedCtrl = StreamController<Request>.broadcast();
// to give access of the Stream to listen when new request is received
Stream<Request> get onRequestReceived => _onRequestReceivedCtrl.stream;
// as singleton to maintain the connexion during the app life and be accessible everywhere
static final SocketUDP _instance = SocketUDP._internal();
factory SocketUDP() {
return _instance;
}
SocketUDP._internal();
void startSocket(int port) {
_port = port;
RawDatagramSocket.bind(InternetAddress.anyIPv4, _port)
.then((RawDatagramSocket socket) {
_socket = socket;
// listen the request from server
_socket.listen((e) {
Datagram dg = _socket.receive();
if (dg != null) {
_onRequestReceivedCtrl.add(RequestConvert.decodeRequest(dg.data, dg.address));
}
});
});
}
void send(Request requestToSend, {bool isBroadCast:false}) {
_socket.broadcastEnabled = isBroadCast;
final String requestEncoded = RequestConvert.encodeRequest(requestToSend);
List<int> requestAsUTF8 = utf8.encode(requestEncoded);
_socket.send(requestAsUTF8, requestToSend.address, _port);
}
}
Related
I am building an app that requires to connect to a videoconference device in order to send call commands.
My problem comes when the device gets disconnected because it's powered off, cable disconnection, or any other issue. In that scenario, I am able to show it in the app thanks to the vcfConnected variable. However, I can never get the connection back to work (only by restarting the app, which is not desirable)
I am connecting to the device via dart socket like follows. The idea behind this implementation is to try to reconnect whenever there is a problem. However, is not working fine.
Does anybody know how to better handle the connection state?
Is it better to connect to the device each time I have to send a command and close the socket after that each time?
void connect(){
Socket.connect('192.168.5.107', 55003).then((Socket socket) {
sock = socket;
vcfConnected = true;
socket.listen((data) {
String response = hex.encode(data);
dataHandler(context, response);
},
onError: (error) => errorHandler(error),
onDone: () => reconnect()
);
// Init protocol message
sendCommand('&IPV');
getMicMuteState();
getReceiveVolume();
timer = Timer.periodic(Duration(seconds: 10), (Timer t) => checkVcfStatus());
}).timeout(Duration(seconds: 15), onTimeout: () => onTimeout());
}
FutureOr<Null> onTimeout(){
reconnect();
}
void reconnect(){
print('VCF disconnected');
vcfConnected = false;
if (timer != null){
timer.cancel();
}
if (sock != null) {
sock.close();
}
sock = null;
connect();
}
void errorHandler(, error){
print('Error: $error');
reconnect();
}
void checkVcfStatus() {
sendCommand('?S');
}
I'm creating a cross platform application that uses Artnet and UDP protocol to communicate with a device on the network. I know Artnet is also UDP.
Where it works:
Windows OS:
Ethernet. Direct Link and Router controlled.
Wifi. Direct Link and Router Controlled.
Android OS:
Ethernet. N/A
Wifi. Direct Link only.
iOS:
Ethernet. N/A
Wifi. Direct Link only.
Don't understand why there's 0 communication when there's a router involved on Android and iOS. I tried all the suggested codes I could find online and ticked all the capabilities that I could find for Android and iOS.
Wireshark shows there is transmission going on, but my App doesn't capture the packets.
Snipets:
var artnet = new ArtNetSocket(); // using System.Net.Sockets;
artnet.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
artnet.Bind(new IPEndPoint(LocalIP, 6454));
artnet.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
EndPoint localPort = new IPEndPoint(IPAddress.Any, Port);
ArtNetData data= new ArtNetData();
artnet.BeginReceiveFrom(recieveState.buffer, 0, recieveState.bufferSize, SocketFlags.None, ref localPort, new AsyncCallback(WhenRecieved), data);
private void WhenRecieved(IAsyncResult state)
{
//1.Do something when received
//2.Begin receive again
}
How I look for IPs:
NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface Interface in Interfaces)
{
if (Interface.NetworkInterfaceType != NetworkInterfaceType.Loopback )
{
UnicastIPAddressInformationCollection UnicastIPInfoCol = Interface.GetIPProperties().UnicastAddresses;
foreach (var info in UnicastIPInfoCol)
{
if (info.Address.AddressFamily == AddressFamily.InterNetwork)
{
IPsets.Add(new IPCouples(info.Address, info.IPv4Mask));
}
}
}
}
It's so weird it's probably something simple...
Ok, because I was creating sockets for each IP group, packets weren't captured on public networks, unless the APP was on a Microsoft OS device. If I create a UDPClient and bind it to a port, instead of the localIP address, it will capture everything coming on that port, regardless of the sender's IP Address. If you check the IP address of the socket, it will be 0.0.0.0:PortNumber.
public class Something: UdpClient
{
public int LocalPort;
public Something(int LocalPort) : base(LocalPort)
{
EnableBroadcast = true;
this.LocalPort = LocalPort;
StartListening();
}
private void StartListening()
{
//IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
try
{
StateObject state = new StateObject();
state.workSocket = Client;
BeginReceive(received, state);
}
catch (SocketException e)
{
Console.WriteLine(e);
}
}
private void received(IAsyncResult ar)
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
StateObject state = (StateObject)ar.AsyncState;
var message = EndReceive(ar, ref remoteEndPoint);
if (message.Length > 0)
{
var messageString = (Encoding.UTF8.GetString(message));
//Do Something
}
StartListening();
}
public SendToAll(string message)
{
var callMessage = Encoding.ASCII.GetBytes(message);
UnicastIPAddressInformationCollection UnicastIPInfoCol = Interface.GetIPProperties().UnicastAddresses;
foreach (UnicastIPAddressInformation UnicatIPInfo in UnicastIPInfoCol)
{
if (UnicatIPInfo.Address.AddressFamily == AddressFamily.InterNetwork)
{
EnableBroadcast = true;
Send(callMessage, callMessage.Length, new IPEndPoint(GetBroadcast(UnicatIPInfo.Address,UnicatIPInfo.IPv4Mask) , LocalPort));
}
}
}
private IPAddress GetBroadcast(IPAddress someAddress, IPAddress someMask)
{
//Do something to get broadscat
return Broadcast;
}
}
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 256;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
It works on all platform. Carefull which port you use.
I have a sample Socket application that communicates between two devices using and IP address and port. The IPV4 IP-addresses work fine in the application but I cannot seem to get the correct information for the IPV6 IP-addresses.
I believe I understand what is being talked about in this article with regarding to the Zone ID for an IPV6 address
https://howdoesinternetwork.com/2013/ipv6-zone-id
and I also believe I understand what is being said here within that document:
If you want to ping a neighbor computer, you will need to specify the neighbor’s IPv6 Link-Local address plus the Zone ID of your computer’s network adapter that is going towards that computer.
i.e. I need to use the remote IPV6 address with the local device's Zone ID.
My problem is I cannot seem to figure out what the local device's (ios, android) Zone ID is for IPV6 addresses. I have uploaded my sample Xamarin Forms socket server and client code to GitHub and it can be accessed here.
Server Code: https://github.com/gceaser/AsyncSocket
Client Code: https://github.com/gceaser/AsyncSocketClient
I have the IP Addresses and ports defined in the App.xaml.cs for each project and a switch in each project to go back and forth between an IP V4 and V6 connection. (You should update the IP Addresses for your environment if you are trying to test this.) The V4 connection works but I cannot get the V6 connection to work. Any help would be greatly appreciated.
NOTE: To the best of my knowledge you cannot run the client and server on the same windows machine. Something weird about sockets not being able to communicate that way as I have document in one of my other StackOverflow post. Thus to test please run the server on a Windows box and the Client within iOS.
UPDATE:
Here is the code for the Server Socket connection:
using System;
using
System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
using System.Collections.Generic;
namespace AsyncSocketServer
{
public class AsynchronousSocketListener
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
public delegate void onMessageReceivedComplete(object sender, string message);
public delegate void onResponseMessageSent(object sender, string message);
public static event onMessageReceivedComplete MessageReceivedComplete;
public static event onResponseMessageSent ResponseMessageSent;
public AsynchronousSocketListener()
{
}
public async static Task StartListening(IPAddress pobj_IPAddress, int pi_Port)
{
try
{
//IPAddress ipAddress = IPAddress.Parse(pobj_IPAddress);
IPEndPoint localEndPoint = new IPEndPoint(pobj_IPAddress, pi_Port);
Socket listener = new Socket(pobj_IPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
//ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_Listening;
await Task.Delay(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + pobj_IPAddress + " at port " + pi_Port.ToString() + "...");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine("StartListening Error" + e.ToString());
}
Debug.WriteLine("Read To end class");
}
public static void AcceptCallback(IAsyncResult ar)
{
try
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
//If we have shut down the socket dont do this.
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception e)
{
Debug.WriteLine("AcceptCallback Error" + e.ToString());
}
}
public static void ReadCallback(IAsyncResult ar)
{
try
{
string ls_ReceivedCommunicationContent = string.Empty;
string ls_ReturnCommunicationContent = string.Empty;
//string content = string.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
ls_ReceivedCommunicationContent = state.sb.ToString();
if (ls_ReceivedCommunicationContent.IndexOf("<EOF>") > -1)
{
//We need to take off the end of file marker
string ls_WorkContent = ls_ReceivedCommunicationContent.Replace("<EOF>", "");
ls_ReturnCommunicationContent = ls_WorkContent;
//Different than app
Device.BeginInvokeOnMainThread(() => {
MessageReceivedComplete(null, ls_WorkContent);
});
Send(handler, ls_ReturnCommunicationContent);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
catch (Exception e)
{
Debug.WriteLine("ReadCallback Error" + e.ToString());
}
}
private static void Send(Socket handler, String data)
{
try
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
Device.BeginInvokeOnMainThread(() => {
ResponseMessageSent(null, data);
});
}
catch (Exception e)
{
Debug.WriteLine("Send Error" + e.ToString());
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Debug.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Debug.WriteLine("SendCallback Error" + e.ToString());
}
}
}
}
Here is the client Code:
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace AsyncSocketClient
{
// This template use base socket syntax to change Pattern. (like Send, Receive, and so on)
// Convert to Task-based Asynchronous Pattern. (TAP)
public static class AsynchronousClientSocket
{
public static async Task<string> SendMessage(string ps_IPAddress, int pi_Port, string ps_Message)
{
string ls_response = "";
try
{
string ls_ReturnMessage = "";
// Establish the remote endpoint for the socket.
IPAddress ipAddress = IPAddress.Parse(ps_IPAddress);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, pi_Port);
// Create a TCP/IP socket.
var client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
var isConnect = await client.ConnectAsync(remoteEndPoint).ConfigureAwait(false);
if (!isConnect)
{
Console.WriteLine("Can not connect.");
return ls_ReturnMessage;
}
// Send test data to the remote device.
var bytesSent = await client.SendAsync(ps_Message + "<EOF>").ConfigureAwait(false);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Receive the response from the remote device.
ls_response = await client.ReceiveAsync().ConfigureAwait(false);
// Write the response to the console.
Console.WriteLine("Response received : {0}", ls_response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
return ls_response;
}
private static Task<bool> ConnectAsync(this Socket client, IPEndPoint remoteEndPoint)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (remoteEndPoint == null) throw new ArgumentNullException(nameof(remoteEndPoint));
return Task.Run(() => Connect(client, remoteEndPoint));
}
private static bool Connect(this Socket client, EndPoint remoteEndPoint)
{
if (client == null || remoteEndPoint == null)
return false;
try
{
client.Connect(remoteEndPoint);
return true;
}
catch (Exception)
{
return false;
}
}
private static async Task<string> ReceiveAsync(this Socket client, int waitForFirstDelaySeconds = 3)
{
if (client == null) throw new ArgumentNullException(nameof(client));
// Timeout for wait to receive and prepare data.
for (var i = 0; i < waitForFirstDelaySeconds; i++)
{
if (client.Available > 0)
break;
await Task.Delay(1000).ConfigureAwait(false);
}
// return null If data is not available.
if (client.Available < 1)
return null;
// Size of receive buffer.
const int bufferSize = 1024;
var buffer = new byte[bufferSize];
// Get data
var response = new StringBuilder(bufferSize);
do
{
var size = Math.Min(bufferSize, client.Available);
await Task.Run(() => client.Receive(buffer)).ConfigureAwait(false);
response.Append(Encoding.ASCII.GetString(buffer, 0, size));
} while (client.Available > 0);
// Return result.
return response.ToString();
}
private static async Task<int> SendAsync(this Socket client, string data)
{
var byteData = Encoding.ASCII.GetBytes(data);
return await SendAsync(client, byteData, 0, byteData.Length, 0).ConfigureAwait(false);
}
private static Task<int> SendAsync(this Socket client, byte[] buffer, int offset,
int size, SocketFlags socketFlags)
{
if (client == null) throw new ArgumentNullException(nameof(client));
return Task.Run(() => client.Send(buffer, offset, size, socketFlags));
}
}
}
When I start the serer, switch it to IPV6 and start it, I get the message that it is waiting for a connection as follows:
Waiting for a connection on fe80::cda4:ea52:29f5:2c7c at port 8080...
When I start the Client, switch it to IPV6 and attempt to send a message, I get the error:
2020-06-19 09:32:51.029902-0400 AsyncSocketClient.iOS[33593:9360848] Can not connect.
My dart application it's listening to a socket I want to return the socket reply on the command(...) function after it is processed in the dataHandler event.
import 'dart:io';
import 'dart:async';
class TeamSpeak3{
Socket socket;
String command;
String _ip;
int _port;
TeamSpeak3(String ip, int port) {
this._ip = ip;
this._port = port;
}
Future<int> connect() async {
await Socket.connect(_ip, _port)
.then((Socket sock) {
socket = sock;
socket.listen(
dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: false);
}).catchError((AsyncError e) {
print("Connection failed: $e");
exit(1);
});
socket.done;
return 1;
}
void auth(String name, String pass){
socket.write("login $name $pass\n");
}
void send(String cmd){
command = cmd;
socket.write('$cmd\n');
//return reply from dataHandler
}
void dataHandler(data){
var reply = new String.fromCharCodes(data).trim();
//return $reply on the send function
}
void errorHandler(error, StackTrace trace){
print(error);
}
void doneHandler(){
print("Connection termiated!");
socket.destroy();
exit(0);
}
}
First of all, you don't know for sure that the entire response to your send arrives in one packet, so you might not have the entire response.
Let's assume that you do (otherwise you'll have to do more processing in dataHandler to collect the response before delivering it).
The canonical way to allow a callback to be called when something has happened in the future, is to return a Future. You will also need a way to complete that future, so you create a Completer and store it until you need it. Since you can probably do more sends, you need to remember more than one completer. So, all in all, I'd write this as:
Queue<Completer<String>> _queue = Queue();
Future<String> send(String cmd){
socket.writeln(cmd);
var completer = new Completer<String>();
_queue.add(completer);
return completer.future;
}
void _dataHandler(data){
var reply = new String.fromCharCodes(data).trim();
// Add some sanity checking here. Make sure you have the entire response before
// executing the code below.
_queue.removeFirst().complete(reply);
}
(I made _dataHandler private because you probably don't want the user calling send to alse be able to call dataHandler).
I don't get it, my friend and I are developing an API and our WebSocket services works, but not the mobile side.. I tried with a couple of clients, on the web, our echo messaging and everything works.
The thing is, I mean, the things seem like the socket is mono-directional. I tried the example of https://github.com/rdavisau/sockets-for-pcl#a-tcp-client:
var address = "127.0.0.1";
var port = 11000;
var r = new Random();
var client = new TcpSocketClient();
await client.ConnectAsync(address, port);
// we're connected!
for (int i = 0; i<5; i++)
{
// write to the 'WriteStream' property of the socket client to send data
var nextByte = (byte) r.Next(0,254);
client.WriteStream.WriteByte(nextByte);
await client.WriteStream.FlushAsync();
// wait a little before sending the next bit of data
await Task.Delay(TimeSpan.FromMilliseconds(500));
}
await client.DisconnectAsync();
First, after I get connected with this :
public async void ConnectSocketToAPIAsync()
{
SocketClient = new TcpSocketClient();
await SocketClient.ConnectAsync("my.ws.service", 4242);
ActiveSocketExchange();
}
public async void ActiveSocketExchange()
{
var bytesRead = -1;
var buf = new byte[1];
while (bytesRead != 0)
{
bytesRead = await SocketClient.ReadStream.ReadAsync(buf, 0, 1);
if (bytesRead > 0)
MessagingCenter.Send((App)Current, SOCKET_Message, System.Text.Encoding.UTF8.GetString(buf, 0, bytesRead));
}
}
Everything's fine, my TcpClient is well initialized (even the web-link becomes the http's API addr)
From my page view, when I'm done writing my text, I'm pressing the done button of the keyboard and this code is called:
private void InitSocketPart()
{
MessagingCenter.Subscribe<App, string>((App)Application.Current, App.SOCKET_Message, (sender, text) =>
{
SocketResponseText = text;
});
}
private async void OnTextCompleted(object sender, EventArgs ea)
{
var bytes = Encoding.UTF8.GetBytes(TextToSend);
try {
if (App.SocketClient.WriteStream.CanRead)
Debug.WriteLine("canRead");
if (App.SocketClient.WriteStream.CanWrite)
Debug.WriteLine("canWrite");
App.SocketClient.WriteStream.Write(bytes, 0, TextToSend.Length);
App.SocketClient.WriteStream.Flush();
} catch (Exception e)
{
Debug.WriteLine(e);
}
}
So now CanWrite && CanRead are true, but nothing at all happens, even with the use of Async methods... Why so? I don't get it..
The use of messaging center is just to have only one point of incoming message. I'm using it for other things and it works perfectly :)
Thank for any help..