Closed Micwi closed 5 months ago
I'm not sure why this issue was transferred here. I believe this will be a runtime issue, as this repo is for the MAUI UI project, which doesn't handle nor should it affect something like System.Net.TcpClient.
Xamarin.Forms ran on top of Mono, so my guess would be that there could be changes between how that was handled and what .NET itself does? I think this is the area where those errors are produced
@jonathanpeppers @rolfbjarne Should this issue be moved, or am I missing something here?
@jonathanpeppers @rolfbjarne Should this issue be moved, or am I missing something here?
This looks like something for dotnet/runtime to me.
Could you post minimal runable repro and complete exception @Micwi.
BTW I look at the code and it simply does
new Socket(_family, SocketType.Stream, ProtocolType.Tcp);
could you try that directly as well @Micwi ???
Hello @wfurt,
Thank you for responding to my thread.
I have some information to update this situation. It turns out the Android side has the same issue but not as frequent.
I am initializing it like this on both projects:
"protected TcpClient m_TcpClient = new TcpClient(AddressFamily.InterNetworkV6);"
if I sent the m_TcpClient.Client.DualMode to TRUE, then it ends up working. But occasionally is delayed with passing data (This happens on both Android and IOS)
If i do not set the dual mode, then I am thrown that "protocol is not supported" exception. Like i said in my original post, the c# file used to do this wasn't changed at all during the migration from Xamarin to .NET. I did not have the DualMode property being set. I just passed in an iPv4 address and it worked. I tried passing in an iPv6 address but it didnt work either.
I put code snippets from a sample .NET 8 IOS project from vscode using the .NET Maui and C# Dev kit extensions. It is a very basic project, just add create a new project, copy this code and a ip address and port number and hit debug (I have comments in code to show where).
`using System.Net; using System.Net.Sockets; using UIKit;
namespace MauiApp1;
public class vc : UIViewController { protected ushort m_Port = 0; protected string m_IPAddrStr = string.Empty; protected TcpClient m_TcpClient = new TcpClient(AddressFamily.InterNetworkV6); protected bool m_SocketClosed = false; protected NetworkStream m_TcpNetworkStream = null;
public vc()
{
}
public override void ViewDidLoad()
{
this.View!.AddSubview (new UILabel (new CGRect(100,100, 100, 100)) {
BackgroundColor = UIColor.SystemBackground,
TextAlignment = UITextAlignment.Center,
Text = "Hello, iOS!",
AutoresizingMask = UIViewAutoresizing.All,
});
m_IPAddrStr = ""; //pass in address here
m_Port = 0; //pass in port number here
OnTcpTimer();
}
//=================================================================================================
// TCP client is connected
//=================================================================================================
public int TCPIsConnected()
{
// returns -1 for error, 0 if successful
int result = -1;
try
{
if (m_TcpClient.Connected)
{
result = 0;
}
}
catch (Exception ex)
{
result = -1;
}
return result;
}
//=================================================================================================
// Close TCP client connection
//=================================================================================================
public int TCPClose()
{
// returns -1 for error, 0 if successful
int result = -1;
try
{
if (m_TcpNetworkStream != null)
{
m_TcpNetworkStream.Close();
}
if (m_TcpClient != null)
{
m_TcpClient.Close();
}
m_TcpNetworkStream = null;
m_TcpClient = new TcpClient(AddressFamily.InterNetworkV6);
m_SocketClosed = true;
result = 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + ex.StackTrace);
result = -1;
}
return result;
}
//=================================================================================================
// TCP client write data
//=================================================================================================
public int TCPWrite(ref byte[] buf, int cbBuf)
{
// returns -1 for error, 0 if successful
int result = -1;
try
{
if (m_TcpNetworkStream != null && !m_SocketClosed)
{
m_TcpNetworkStream.Write(buf, 0, cbBuf);
result = cbBuf;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + ex.StackTrace);
result = -1;
}
return result;
}
//=================================================================================================
// TCP Client read data
//=================================================================================================
public int TCPRead(ref byte[] buf, int cbBuf)
{
// returns -1 for error, 0 if successful
int result = -1;
try
{
if (m_TcpNetworkStream != null && !m_SocketClosed)
{
if (m_TcpNetworkStream.CanRead)
{
if (m_TcpNetworkStream.DataAvailable)
{
m_TcpNetworkStream.Read(buf, 0, cbBuf);
result = buf.Length;
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + ex.StackTrace);
result = -1;
}
return result;
}
private void OnTcpTimer()
{
bool closeSocket = false;
try
{
m_TcpNetworkStream = null;
m_SocketClosed = true;
try
{
// try using an IP address
IPAddress addr = new IPAddress(0);
addr = System.Net.IPAddress.Parse(m_IPAddrStr);
var result = m_TcpClient.BeginConnect(addr, m_Port, null, null);
result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (m_TcpClient.Connected)
{
m_TcpNetworkStream = m_TcpClient.GetStream();
m_SocketClosed = false;
m_TcpClient.EndConnect(result);
}
else
{
Console.WriteLine("TcpClient - Unable to connect");
closeSocket = true;
}
}
catch (SocketException ex)
{
if (ex.ErrorCode == 0x00002748 /*WSAEISCONN*/)
{
// Socket already connected
m_TcpNetworkStream = m_TcpClient.GetStream();
m_SocketClosed = false;
}
else
{
Console.WriteLine("TcpClient - Connection Socket Exception: " + ex.Message + " code: " + ex.ErrorCode.ToString() + ". Attempting to close socket and try again.");
closeSocket = true;
}
}
catch
{
try
{
m_TcpNetworkStream = null;
m_SocketClosed = true;
var result = m_TcpClient.BeginConnect(m_IPAddrStr, m_Port, null, null);
result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (m_TcpClient.Connected)
{
m_TcpNetworkStream = m_TcpClient.GetStream();
m_SocketClosed = false;
m_TcpClient.EndConnect(result);
}
else
{
Console.WriteLine("TcpClient - Unable to connect");
closeSocket = true;
}
}
catch (SocketException ex)
{
if (ex.ErrorCode == 0x00002748 /*WSAEISCONN*/)
{
// Socket already connected
m_TcpNetworkStream = m_TcpClient.GetStream();
m_SocketClosed = false;
}
else
{
closeSocket = true;
}
}
}
}
catch (SocketException ex)
{
if (ex.ErrorCode == 0x00002748 /*WSAEISCONN*/)
{
// Socket already connected
m_TcpNetworkStream = m_TcpClient.GetStream();
m_SocketClosed = false;
}
else
{
closeSocket = true;
}
}
catch (Exception ex)
{
Console.WriteLine("TcpClient - Error Connecting: " + ex.Message + ex.StackTrace);
}
if (closeSocket)
{
TCPClose();
}
}
}`
If i set the dual mode before it calls the BeginConnect() (Line 191), then it works and i don't get the exception.
Line 191 = "var result = m_TcpClient.BeginConnect(addr, m_Port, null, null);"
Here is the full exception:
"This protocol version is not supported. at System.Net.Sockets.Socket.ConnectAsync(SocketAsyncEventArgs e, Boolean userSocket, Boolean saeaCancelable) 2024-04-09 13:58:31.666508-0400 TempTCPIOSProject[2858:42096] at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ConnectAsync(Socket socket) at System.Net.Sockets.Socket.ConnectAsync(EndPoint remoteEP, CancellationToken cancellationToken) at System.Net.Sockets.Socket.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken) 2024-04-09 13:58:31.668193-0400 TempTCPIOSProject[2858:42096] at System.Net.Sockets.Socket.ConnectAsync(String host, Int32 port) at System.Net.Sockets.Socket.BeginConnect(String host, Int32 port, AsyncCallback requestCallback, Object state) 2024-04-09 13:58:31.668544-0400 TempTCPIOSProject[2858:42096] at System.Net.Sockets.TcpClient.BeginConnect(String host, Int32 port, AsyncCallback requestCallback, Object state) at MauiApp1.vc.OnTcpTimer() in Desktop/TempTCPIOSProject/vc.cs:line 191"
Thanks again for your time.
/cc: @simonrozsival
Any update on this?
Thanks
If i do not set the dual mode, then I am thrown that "protocol is not supported" exception. Like i said in my original post, the c# file used to do this wasn't changed at all during the migration from Xamarin to .NET. I did not have the DualMode property being set. I just passed in an iPv4 address and it worked. I tried passing in an iPv6 address but it didnt work either.
@Micwi the implementation of Socket
is quite different in .NET than it was in Xamarin.Forms (based on legacy Mono). While in most cases, things should work the same way as they used to, it this case the .NET Socket
implementation seems to require enabling DualMode
. The exception seems to be coming from this location which checks for DualMode in the case when there is a mismatch between the protocols:
https://github.com/dotnet/runtime/blob/ddff593e32e3f5d469f41a06ff4287948077862f/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L2775-L2778
https://github.com/dotnet/runtime/blob/ddff593e32e3f5d469f41a06ff4287948077862f/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L738-L749
Do I understand it correctly that after setting DualMode = true
, the app behaves as expected?
What address are you connecting to @Micwi ? I assumed you would connect to IPv4 since you are creating IPv6 socket. Are you not? If you trying to use IPv4 address you either need to construct IPv4 socket or use DualMode
.
Hello
Sorry for the delay.
@simonrozsival Thank you for narrowing down where the issue is. Setting dual mode or simply initializing the socket constructor to be for iPv4 (Internetwork) seems to resolve that exception being thrown. However, I am noticing a huge delay in communication between my app and the server.
@wfurt I am connecting to an iPv4 address but the app is setup with the iPv6 constructor. Like said above, i get passed the exception but there seems to be a huge delay with the data.
Unfortunately, I have to focus on another project and come back to this, is it possible to put this issue on hold? Mark is somehow? Otherwise, I would need to open another issue but I'd hate to start over and reexplain everything.
Thanks and sorry for the delay
Unfortunately, I have to focus on another project and come back to this, is it possible to put this issue on hold? Mark is somehow? Otherwise, I would need to open another issue but I'd hate to start over and reexplain everything.
I think it would be best to close this issue (titled "unable to establish IPv6 TCP connection") and later you can open a new issue for the delay you're experiencing with additional information and repro steps. You can then link to this issue as context for the issue.
Will do, thank you everyone for your time! Have a great day!
How much is the delay? You can try to set socket.NoDelay = false
. If it is just for connecting check DNS.
URL(s)
https://learn.microsoft.com/en-us/dotnet/maui/whats-new/dotnet-8?view=net-maui-8.0 https://learn.microsoft.com/en-us/dotnet/maui/migration/native-projects?view=net-maui-8.0
Description
I am in the process of converting an existing Xamarin IOS and Android app to .NET. I followed the steps to convert the project over and have finished converting the apps to .NET 8.
Now I have my .NET app (either IOS or Android, doesnt matter) and my problem is when I go to establish a TCP connection to my server. I am initializing the TCPClient constructor with the AddressFamily override using the IPv6 option (InterNetworkV6). I have tried initializing it with the IPv4 option and it didnt work on the .Net IOS app, but the Android app worked.
I am then shown an error "This protocol version is not supported. at System.Net.Sockets.Socket.ConnectAsync(SocketAsyncEventArgs e, Boolean userSocket, Boolean saeaCancelable)".
I have tried converting the apps to .NET 7 and it still didn't fix the issue.
I have made no changes to my class that handles the TCP connection. Both my original Xamarin project and this .NET project use the same class (Copied into project) and the Xamarin project works without any issues. I checked the documentation and it says this is supported up until .NET 9. https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.-ctor?view=netframework-4.7#System_Net_Sockets_TcpClient__ctor
Was there a change to how this library works on .Net? Am I missing something? Any advise or information is greatly appreciated.