I'm writing an https server which inherit from an existing http server.
The Http server using a ImprovedTCPServerSocket which wrap Socket and when send/receive he is locking the scope as you can see:
public class ImprovedTCPServerSocket
{
private readonly Object m_SocketLocker = new Object();
protected Socket m_Socket;
public ImprovedTCPServerSocket(Socket mSocket)
{
m_Socket = mSocket;
}
public void Send(byte[] buffer, int offset, int size)
{
Socket mySocket;
lock (m_SocketLocker)
{
mySocket = m_Socket;
}
mySocket.Send(buffer, offset, size, SocketFlags.None);
}
protected int Receive(int requiredBytesToRead, byte[] receivedBytes, TimeSpan timeout, bool doReceive)
{
try
{
Socket mySocket;
lock (m_SocketLocker)
{
mySocket = m_Socket;
}
while (some condition){
currentBytesOffset += InternalReceive(mySocket, receivedBytes);
}
}
catch() {
.....
}
}
protected virtual int InternalReceive(Socket mySocket, byte[] receivedBytesת int currentBytesOffset)
{
currentBytesOffset += mySocket.Receive(receivedBytes, // collect given input.
currentBytesOffset, // offset.
bytesAvailableToRead, // number of bytes to read
flags,
out socketError);
return currentBytesOffset;
}
public virtual void Close()
{
m_Socket.Close();
}
}
Now in order to implement an https server I created a new class ImprovedSslStream which wrap SslStream and inherit from ImprovedTCPServerSocket
I'm using SslStream Do I need to do the same lock to m_SslStream as we made to m_Socket or is it ok to use it like this?
Here is my code:
public class ImprovedSslStream : ImprovedTCPServerSocket
{
private X509Certificate m_Certificate;
private SslStream m_SslStream;
public ImprovedSslStream(Socket mSocket, X509Certificate serverCertificate) : base(mSocket)
{
m_Certificate = serverCertificate;
}
public void Send(byte[] buffer, int offset, int size)
{
//
sslStream.Write(.....)
}
protected override int GetCurrentByteOffset(Socket mySocket, byte[] receivedBytes, int currentBytesOffset,
int bytesAvailableToRead, bool doReceive)
{
m_SslStream=new SslStream(new NetworkStream(mySocket),false); //Do I need to lock it ?
try
{
m_SslStream.AuthenticateAsServer(m_Certificate,
false, SslProtocols.Tls, true);
currentBytesOffset+=m_SslStream.Read(receivedBytes, currentBytesOffset, bytesAvailableToRead);
}
catch (AuthenticationException e)
{
}
return currentBytesOffset;
}
}
}
Related
Currently my android app communicates with a server via tcp socket with synchronous read and write methods
private val addressString : String = "192.168.1.200"
private val port : Int = 33322
private var socketAddress: InetSocketAddress = InetSocketAddress(addressString, port)
private var socket: Socket? = null
fun connect(){
socket = Socket()
socketAddress = InetSocketAddress(addressString, port)
try{
socket!!.connect(socketAddress)
}catch(e : Exception){
socket!!.close()
}
}
fun disconnect(){
try {
socket?.shutdownOutput()
} catch (e: Exception) {}
try {
socket?.shutdownInput()
} catch (e: Exception) {}
try {
socket?.close()
} catch (e: Exception) {}
socket = null
}
fun send(data: ByteArray): Int {
var sentByteCount: Int = -1
try {
socket!!.getOutputStream().write(data)
sentByteCount = data.size
} catch (e: Exception) {
throw e
}
return sentByteCount
}
data class Wrapper<T>(
var value:T
)
fun receive(buffer: Wrapper<ByteArray>): Int {
val size = buffer.value.size
var receivedByteCount: Int = -1
try {
receivedByteCount = socket!!.getInputStream().read(buffer.value)
} catch (e: Exception) {
throw e
}
return receivedByteCount
}
However, the server, written in C#, always communicates with another device via socket but with an asynchronous reading method
public const int BUFFER_SIZE = 4096;
private string addressString = "192.168.1.200"
private int port = 33322
private int timeout = 5000
private byte[] _buffer = new byte[BUFFER_SIZE];
private TcpClient _client;
private SocketError _socketError;
private AsyncCallback _callback = new AsyncCallback(ReceiveCallback);
public void connect()
{
_client = TCpClient()
_client.ConnectAsync(addressString, port).Wait(timeout)
}
public void receive()
{
_client.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, _socketError, _callback, null)
}
private void receiveCallback(IAsyncResult ar)
{
//callback method when it has finished reading asynchronously
}
public void send()
{
_client.GetStream().Write(_buffer, 0, _buffer.Length);
}
public void disconnect()
{
if (_client.Connected)
_client.Close();
}
What I need is to communicate between my app and the device as the Server is already doing.
I tried to find out if even in kotlin there was the possibility of creating an asynchronous connection that would give me the possibility of being able to do an asynchronous reading as it can be done in C # and I found AsynchronousSocketChannel.
From the documentation, however, it has been deduced that the possibility of using this socket is linked to the fact that the server is an AsynchronousServerSocketChannel socket, in my case it is not possible to use it as I can only create the client.
Are there any other possibilities to recreate something similar to the C # code shown above in Kotlin?
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.
I've run it on c# console applications and it works fine
I've run it on Windows Forms application and it works fine
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've checked the firewalls, I've uninstalled and disable the
firewalls
I've checked the manifest and even there I tried after the (
must-have permissions ) I tried to enable all permissions.
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
I have a bunch of async methods that I want to expose via C# sockets. The general pattern in the MSDN documentaions Has the following form:
public static void StartListening()
{
...
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
...
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
...
}
public static void AcceptCallback(IAsyncResult ar)
{
...
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
...
StateObject state = (StateObject) ar.AsyncState;
...
CalculateResult(state);
...
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
...
}
So writing all this in a nice and clean form without repetition of code has been a challenge. I am thinking along these lines but have not been able to connect the dots:
public static void StartListeningMaster()
{
string ipAddress = "localhost";
IPHostEntry ipHost = Dns.GetHostEntry(ipAddress);
IPAddress address = ipHost.AddressList[0];
StartListening(50000, address, AcceptCallback1);
StartListening(50001, address, AcceptCallback2);
StartListening(50002, address, AcceptCallback3);
...
}
public static void StartListening(int port, IPAddress ipAddress,
Action<IAsyncResult> acceptCallback) {...}
public static void AcceptCallback1(IAsyncResult ar)
{
...
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize,
0, new AsyncCallback1(ReadCallback1), state);
}
...
This works fine up to this point. But to refactor it properly I would like to have one AcceptCallback method that takes as its parameter a generic ReadCallback that takes as its parameter a CalculateResult method. This way I would not have any repetition of code. However, if I modify my AcceptCallback method to take any more parameters than IAsyncResult (for example something like:
public static void StartListening(int port, IPAddress ipAddress, Action<IAsyncResult, Action<IAsyncResult>> acceptCallback) {...}
public static void AcceptCallback(IAsyncResult ar, Action<IAsyncResult> readCallback) {}
I break the AsyncCallback delegate contract.
public delegate void AsyncCallback(IAsyncResult ar);
Then I looked into extending the existing interfaces to allow the functionality. I looked into extending
public interface IAsyncResult
But that does not seem to be the right approach either. So, how do I write this code so I do not copy and paste pretty much the same code all over the place?
So the way I tackle this is by moving the basic components in to their own abstract objects. Then build upon those objects. For example, the server only needs to accept/track connections. So I would make a server object that looks something like this:
namespace MultiServerExample.Base
{
public interface IAsyncServerBase
{
void StartListening();
bool IsListening { get; }
void StopListening();
void WriteDataToAllClients(byte[] data);
}
public abstract class AsyncServerBase<TClientBase> : IAsyncServerBase
where TClientBase : IAsyncClientBase, new()
{
// implement a TcpListener to gain access to Active property
private sealed class ActiveTcpListener : TcpListener
{
public ActiveTcpListener(IPAddress localaddr, int port)
: base(localaddr, port) { }
public bool IsActive => Active;
}
// our listener object
private ActiveTcpListener Listener { get; }
// our clients
private ConcurrentDictionary<string, TClientBase> Clients { get; }
// construct with a port
public AsyncServerBase(int port)
{
Clients = new ConcurrentDictionary<string, TClientBase>();
Listener = new ActiveTcpListener(IPAddress.Any, port);
}
// virtual methods for client action
public virtual void OnClientConnected(TClientBase client) { }
public virtual void OnClientDisconnected(TClientBase client, Exception ex) { }
// start the server
public void StartListening()
{
if(!IsListening)
{
Listener.Start();
Listener.BeginAcceptTcpClient(OnAcceptedTcpClient, this);
}
}
// check if the server is running
public bool IsListening =>
Listener.IsActive;
// stop the server
public void StopListening()
{
if (IsListening)
{
Listener.Stop();
Parallel.ForEach(Clients, x => x.Value.DetachClient(null));
Clients.Clear();
}
}
// async callback for when a client wants to connect
private static void OnAcceptedTcpClient(IAsyncResult res)
{
var me = (AsyncServerBase<TClientBase>)res.AsyncState;
if (!me.IsListening) { return; }
try
{
TcpClient client = null;
try
{
client = me.Listener.EndAcceptTcpClient(res);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Warning: unable to accept client:\n{ex}");
}
if(client != null)
{
// create a new client
var t = new TClientBase();
// set up error callbacks
t.Error += me.OnClientBaseError;
// notify client we have attached
t.AttachClient(client);
// track the client
me.Clients[t.Id] = t;
// notify we have a new connection
me.OnClientConnected(t);
}
}
finally
{
// if we are still listening, wait for another connection
if(me.IsListening)
{
me.Listener.BeginAcceptSocket(OnAcceptedTcpClient, me);
}
}
}
// Event callback from a client that an error has occurred
private void OnClientBaseError(object sender, AsyncClientBaseErrorEventArgs e)
{
var client = (TClientBase)sender;
client.Error -= OnClientBaseError;
OnClientDisconnected(client, e.Exception);
client.DetachClient(e.Exception);
Clients.TryRemove(client.Id, out _);
}
// utility method to write data to all clients connected
public void WriteDataToAllClients(byte[] data)
{
Parallel.ForEach(Clients, x => x.Value.WriteData(data));
}
}
}
At this point all the basics of running a server have been accounted for. Now for the client that runs on the server:
namespace MultiServerExample.Base
{
public interface IAsyncClientBase
{
event EventHandler<AsyncClientBaseErrorEventArgs> Error;
void AttachClient(TcpClient client);
void WriteData(byte[] data);
void DetachClient(Exception ex);
string Id { get; }
}
public abstract class AsyncClientBase : IAsyncClientBase
{
protected virtual int ReceiveBufferSize { get; } = 1024;
private TcpClient Client { get; set; }
private byte[] ReceiveBuffer { get; set; }
public event EventHandler<AsyncClientBaseErrorEventArgs> Error;
public string Id { get; }
public AsyncClientBase()
{
Id = Guid.NewGuid().ToString();
}
public void AttachClient(TcpClient client)
{
if(ReceiveBuffer != null) { throw new InvalidOperationException(); }
ReceiveBuffer = new byte[ReceiveBufferSize];
Client = client;
try
{
Client.GetStream().
BeginRead(ReceiveBuffer, 0, ReceiveBufferSize, OnDataReceived, this);
OnAttachedToServer();
}
catch (Exception ex)
{
Error?.Invoke(this,
new AsyncClientBaseErrorEventArgs(ex, "BeginRead"));
}
}
public void DetachClient(Exception ex)
{
try
{
Client.Close();
OnDetachedFromServer(ex);
}
catch { /* intentionally swallow */ }
Client = null;
ReceiveBuffer = null;
}
public virtual void OnDataReceived(byte[] buffer) { }
public virtual void OnAttachedToServer() { }
public virtual void OnDetachedFromServer(Exception ex) { }
public void WriteData(byte[] data)
{
try
{
Client.GetStream().BeginWrite(data, 0, data.Length, OnDataWrote, this);
}
catch(Exception ex)
{
Error?.Invoke(this, new AsyncClientBaseErrorEventArgs(ex, "BeginWrite"));
}
}
private static void OnDataReceived(IAsyncResult iar)
{
var me = (AsyncClientBase)iar.AsyncState;
if(me.Client == null) { return; }
try
{
var bytesRead = me.Client.GetStream().EndRead(iar);
var buf = new byte[bytesRead];
Array.Copy(me.ReceiveBuffer, buf, bytesRead);
me.OnDataReceived(buf);
}
catch (Exception ex)
{
me.Error?.Invoke(me, new AsyncClientBaseErrorEventArgs(ex, "EndRead"));
}
}
private static void OnDataWrote(IAsyncResult iar)
{
var me = (AsyncClientBase)iar.AsyncState;
try
{
me.Client.GetStream().EndWrite(iar);
}
catch(Exception ex)
{
me.Error?.Invoke(me,
new AsyncClientBaseErrorEventArgs(ex, "EndWrite"));
}
}
}
}
Now all your base code is written. You don't need to change this in any way. You simply implement your own client and server to respond accordingly. For example, here is a basic server implementation:
public class MyServer : AsyncServerBase<MyClient>
{
public MyServer(int port) : base(port)
{
}
public override void OnClientConnected(MyClient client)
{
Console.WriteLine($"* MyClient connected with Id: {client.Id}");
base.OnClientConnected(client);
}
public override void OnClientDisconnected(MyClient client, Exception ex)
{
Console.WriteLine($"***** MyClient disconnected with Id: {client.Id} ({ex.Message})");
base.OnClientDisconnected(client, ex);
}
}
And here is a client that the server above uses for communication:
public class MyClient : AsyncClientBase
{
public override void OnAttachedToServer()
{
base.OnAttachedToServer();
Console.WriteLine($"{Id}: {GetType().Name} attached. Waiting for data...");
}
public override void OnDataReceived(byte[] buffer)
{
base.OnDataReceived(buffer);
Console.WriteLine($"{Id}: {GetType().Name} recieved {buffer.Length} bytes. Writing 5 bytes back.");
WriteData(new byte[] { 1, 2, 3, 4, 5 });
}
public override void OnDetachedFromServer(Exception ex)
{
base.OnDetachedFromServer(ex);
Console.WriteLine($"{Id}: {GetType().Name} detached.");
}
}
And to drive the point home, here is another client that simply would plug in to the same server implementation, but gives it different characteristics:
public class MyOtherClient : AsyncClientBase
{
public override void OnAttachedToServer()
{
base.OnAttachedToServer();
Console.WriteLine($"{Id}: {GetType().Name} attached. Writing 4 bytes back.");
WriteData(new byte[] { 1, 2, 3, 4 });
}
public override void OnDataReceived(byte[] buffer)
{
base.OnDataReceived(buffer);
Console.WriteLine($"{Id}: {GetType().Name} recieved {buffer.Length} bytes.");
}
public override void OnDetachedFromServer(Exception ex)
{
base.OnDetachedFromServer(ex);
Console.WriteLine($"{Id}: {GetType().Name} detached.");
}
}
As far as using this, here is a small test program that puts it through a stress-test:
class Program
{
static void Main(string[] args)
{
var servers = new IAsyncServerBase[]
{
new MyServer(50000),
new MyServer(50001),
new MyOtherServer(50002)
};
foreach (var s in servers)
{
s.StartListening();
}
RunTestUsingMyServer("1", 89, 50000);
RunTestUsingMyServer("2", 127, 50001);
RunTestUsingMyOtherServer("3", 88, 50002);
Console.Write("Press any key to exit... ");
Console.ReadKey(true);
foreach (var s in servers)
{
s.WriteDataToAllClients(new byte[] { 1, 2, 3, 4, 5 });
s.StopListening();
}
}
private static void RunTestUsingMyServer(string name, int clientCount, int port)
{
Parallel.For(0, clientCount, x =>
{
using (var t = new TcpClient())
{
t.Connect(IPAddress.Loopback, port);
t.GetStream().Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
t.GetStream().Read(new byte[512], 0, 512);
t.Close();
}
Console.WriteLine($"FINISHED PASS {name} #{x}");
});
}
private static void RunTestUsingMyOtherServer(string name, int clientCount, int port)
{
Parallel.For(0, clientCount, x =>
{
using (var t = new TcpClient())
{
t.Connect(IPAddress.Loopback, port);
t.GetStream().Read(new byte[512], 0, 512);
t.GetStream().Write(new byte[] { 1, 2, 3, 4, 5, 6 }, 0, 6);
t.Close();
}
Console.WriteLine($"FINISHED PASS {name} #{x}");
});
}
}
If interested, here is the full source code you can check out. Hopefully this gets you to where you want to be as it pertains to reusing code.
I don't know if this can help. You can define a state object with all the information related to every port:
public class StateObject
{
public string Name;
public Socket Listener;
public IPEndPoint LocalEndPoint;
//...
public StateObject(Socket listener, IPEndPoint endPoint, string name)
{
Listener = listener;
LocalEndPoint = endPoint;
Name = name;
}
}
Then, you can use it as you need:
public static void StartListeningMaster()
{
string ipAddress = "localhost";
IPHostEntry ipHost = Dns.GetHostEntry(ipAddress);
IPAddress address = ipHost.AddressList[0];
StartListening(50000, address, "Main port");
StartListening(50001, address, "Service port");
StartListening(50002, address, "Extra");
//...
}
public static void StartListening(int port, IPAddress ipAddress, string name = "")
{
//...
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
//...
StateObject state = new StateObject(listener, localEndPoint);
listener.BeginAccept(AcceptCallback, state);
//...
}
public static void AcceptCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
//...
handler.BeginReceive(client.buffer, 0, StateObject.BufferSize,
0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
// Always have the info related to every socket
Socket listener = state.Listener;
string address = state.LocalEndPoint.Address.ToString();
int port = state.LocalEndPoint.Port;
string name = state.Name;
//...
StateObject state = (StateObject)ar.AsyncState;
//...
CalculateResult(state);
//...
handler.BeginReceive(client.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
//...
}
The CalculateResult(state) method will have all the necessary info to do whatever. This way, you only have one StartListening(), one AcceptCallback() and one ReadCallback() for all the ports to manage.
I am Getting an Exception saying that Unable to cast object of type 'System.IO.Ports.SerialStream' to type 'System.Net.Sockets.NetworkStream
when i run below code
please give solution how to overcome this.
private NetworkStream GetStreams_USB_SER()
{
sp = new SerialPort();
NetworkStream Ns ;//= new NetworkStream();
Stream Is;
String KEYNAME3 = "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM";
string COMPORT = (string)Registry.GetValue(KEYNAME3, "\\Device\\USBSER000", "NOT VALID COM");
Console.WriteLine("\nOutput3: " + COMPORT);
sp.PortName = COMPORT;
sp.BaudRate = 115200;
//serialport.ReadTimeout = 1000;
sp.Open();
if (sp.IsOpen)
{
Console.WriteLine("Port Detected :");
Is = sp.BaseStream;
return (NetworkStream)Is;
}
else
{
return null;
}
}
C# is a type-safe language. That means that you can not assign an expression of a type to a variable of a different type and expect that the types automatically adjust (as opposed to some weakly typed languages like JavaScript). While NetworkStream and a SerialStream share a common base class (Stream), a NetworkStream is not a SerialStream and will never be. So you can not cast one to the other.
The SerialPort.BaseStream property is of type Streamand that's the guarantee this property gives you. You can try to cast it into another type (such as NetworkStream), but unless the stream actually is a NetworkStream, this will fail. Alas, the stream returned by the SerialPort class is not a network stream and the stream type that it is (SerialStream) is not accessible to you, because it is marked internal. So you can not cast it into any type that is available to you.
Your only choice in this case is to drop the cast and make your method return a Stream instead of a NetworkStream:
private Stream GetStreams_USB_SER()
and
return Is;
I created a new class which overrides the NetworkStream Class in that implemented my serial port functions.
public class USB_COMM
{
static private SerialPort SPRT = new SerialPort();
static String ComPortName = "";
static int BaudRate = 0;
public USB_COMM(String sCOMNAME, int iBaudRate)
{
ComPortName = sCOMNAME;
BaudRate = iBaudRate;
Sckt1 = new Socket(SocketType.Stream,ProtocolType.Tcp);
Server();
Sckt1.Connect(IPAddress.Parse("127.0.0.1"), 5000);
mns= new myStream();
}
public NetworkStream NsGetUsbStrm()
{
return mns;
}
private class myStream : NetworkStream
{
public myStream()
: base(Sckt1)
{
SPRT.PortName = ComPortName;
SPRT.BaudRate = BaudRate;
}
public int iOpenPort()
{
try {
SPRT.Open();
return 0;
}
catch
{
return 1;
}
}
public override bool DataAvailable
{
get
{
int AvilBytes = SPRT.BytesToRead;
if (AvilBytes > 0)
{
return true;
}
else
{
return false;
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int size)
{
if (buffer == null || offset < 0 || size < 0)
{
throw new ArgumentException();
}
if (!SPRT.IsOpen)
SPRT.Open();
return SPRT.Read(buffer, offset, size);
//return base.Read(buffer, offset, size);
}
public override void Write(byte[] buffer, int offset, int size)
{
if (buffer == null || offset < 0 || size < 0)
{
throw new ArgumentException();
}
if (!SPRT.IsOpen)
SPRT.Open();
SPRT.Write(buffer, offset, size);
//base.Write(buffer, offset, size);
}
}
private void Server()
{
const int PORT_NO = 5000;
const string SERVER_IP = "127.0.0.1";
//---listen at the specified IP and port no.---
IPAddress localAdd = IPAddress.Parse(SERVER_IP);
TcpListener listener = new TcpListener(localAdd, PORT_NO);
Console.WriteLine("Listening...");
listener.Start();
}
}
I keep getting this error:
"The IAsyncResult object was not returned from the corresponding asynchonous method on this class. Parameter name : aysncResult. Line 105.
This happens when I attempt to connect to a local server; It errors and won't connect.
Here's my client code:
public class Client
{
public delegate void OnConnectEventHandler(Client sender, bool connected);
public event OnConnectEventHandler OnConnect;
public delegate void OnSendEventHandler(Client sender, int sent);
public event OnSendEventHandler OnSend;
public delegate void OnDisconnectEventHandler(Client sender);
public event OnDisconnectEventHandler OnDisconnect;
Socket socket;
public bool Connected
{
get
{
if (socket != null)
{
return socket.Connected;
}
return false;
}
}
public Client()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void SendData()
{
}
public void Connect(string IP, int port)
{
if (socket == null)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
socket.BeginConnect(IP, port, new AsyncCallback(sendCallback), null);
}
private void connectCallback(IAsyncResult ar)
{
//try
//{
socket.EndConnect(ar);
if (OnConnect != null)
{
OnConnect(this, Connected);
}
//}
//catch
//{
//}
}
public void Send(byte[] data, int index, int length)
{
socket.BeginSend(BitConverter.GetBytes(length), 0, 4, SocketFlags.None, new AsyncCallback(sendCallback), null);
socket.BeginSend(data, index, length, SocketFlags.None, new AsyncCallback(sendCallback), null);
}
private void sendCallback(IAsyncResult ar)
{
try
{
int sent = socket.EndSend(ar); ( errrors here )
if (OnSend != null)
{
OnSend(this, sent);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
return;
}
}
public void Disconnect()
{
try
{
if (socket.Connected)
{
socket.Close();
socket = null;
if (OnDisconnect != null)
{
OnDisconnect(this);
}
}
}
catch
{
}
}
you should not have two pending BeginSend operations.
Send the size and then the buffer when it completes:
public void Send(byte[] data, int index, int length)
{
//add data as state
socket.BeginSend(BitConverter.GetBytes(length), 0, 4, SocketFlags.None, sendCallback, data);
}
private void sendCallback(IAsyncResult ar)
{
try
{
int sent = socket.EndSend(ar); ( errrors here )
// check if data was attached.
if (ar.AsyncState != null)
{
byte[] buffer = (byte[])ar.AsyncState;
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, null);
return;
}
if (OnSend != null)
{
OnSend(this, sent);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
return;
}
}
You can also use the BeginSend overload which takes a list of buffers.