I've been having some trouble lately while trying to learn how to do an asynchronous receive using visual C#. I have a console based server program that receives data from a client and then sends it back. My problem is on the client side. It has to send data to the server every 100 or so milliseconds and then receive it back.
The problem is getting it back because I can't have the program stop and wait for data. Here's what it looks like so far...
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 16487);
TcpClient client = new TcpClient();
bool blnOnOFF;
private void SendServerData()
{
string strData = "TEST DATA";
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(strData);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
// Ticks Every 100ms
private void tmrDataTransfer_Tick(object sender, EventArgs e)
{
SendServerData();
}
private void btnStart(object sender, EventArgs e)
{
if (blnOnOFF == false)
{
tmrDataTransfer.Start();
blnOnOFF = true;
}
else
{
tmrDataTransfer.Stop();
blnOnOFF = false;
}
}
As you can see, all it does right now is send "TEST DATA". If there is another way to receive the data that is simpler than asynchronous please let me know, also i would like to learn how to do this for future projects.
thanks in advanced.
EDIT: added client sorry i forgot about it
Ok, so, what you need to do is when your app is waiting for incoming data, you need to employ the TcpListener class.
Try this SO answer
The TcpListener class listens for incoming connections, and when it finds one, it creates a TcpClient which does its thing. Meanwhile, the listener has already gone back to looking for new connections. It's pretty much only ever doing just that, and moving the work off to other places.
I think (70% sure) that the TcpClient it creates for a new connection will be operating on a different port than the one your listener is using. You're thus always listening on the same port, while your processing is done on other threads on other ports.
Make sense? I can elaborate more if desired.
Related
I have 2 applications: Xamarin.Android client app that send value from SeekBar over Wifi and WinForms server that receive this value in real time. Everything works good but every time after ~40sec of data transferring android app throws System.Net.Sockets.SocketException with message "Too many open files".
My server code thats receive data:
public void StartReceiving()
{
IPAddress localAdd = IPAddress.Parse(SERVER_IP);
TcpListener listener = new TcpListener(localAdd, PORT_NO);
listener.Start();
while (true)
{
Socket client = listener.AcceptSocket();
client.NoDelay = true;
var childSocketThread = new Thread( () =>
{
byte[] datareceived = new byte[1];
int size = client.Receive(datareceived);
for (int i = 0; i < size; i++)
{
Console.WriteLine(datareceived[0].ToString());
}
Console.WriteLine();
//client.Close();
});
childSocketThread.Start();
}
}
Client code which sends value from SeekBar:
private void Seek1_ProgressChanged(object sender, SeekBar.ProgressChangedEventArgs e)
{
TcpClient client = new TcpClient(SERVER_IP, PORT_NO);
NetworkStream nwStream = client.GetStream();
byte[] bytesToSend = new byte[1];
bytesToSend[0] = Convert.ToByte(e.Progress);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
}
So my question is, what causes this problem and how can I solve it?
Your problem is the following: you open a socket for each call of the ProgressChanged event handler. There is a limited number of sockets that you can open on a machine and if you open them fast enough, you will end up in a System.Net.Sockets.SocketException.
A solution to this problem would be to make sure that you close the TCP connection gracefully. In that way you will release the sockets for further usage.
My opinion is that TCP is a bit overkill for this kind of communication. You can use HTTP to transfer the data. Your desktop app will be the server and the Xamarin app will be the client. In that way you will be freed by things like synchronization, connections states, etc.
I believe what I am looking to create is a service that listens to a specific port, and when data is sent to that port, it sends off that data to another script for processing.
For some reason though, the service times out when I try to start it. My logs tells me TcpClient client = server.AcceptTcpClient(); is where it is stopping (actually, it is getting stuck on 'starting' in Services).
Since I have no experience with C#, making services, or working with servers in this manner, the code is pretty much just what I found online.
The OnStart method looks like this.
protected override void OnStart(string[] args)
{
try
{
TcpListener server = null;
// Set the TcpListener on port 13000.
Int32 port = 1234;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while (true)
{
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
}
finally
{
}
}
As per MSDN, TcpServer.AcceptTcpClient blocks, so you're probably never returning from your Service's OnStart method, which causes the service to never actually "start".
You might consider using another thread and return from OnStart as soon as possible.
Cheers
As far as creating the Windows service itself, you should be able to use this link, even though it's dated. This companion link shows how to have the service install and uninstall itself. Finally, use this link to understand how to have your service run constantly and how to properly respond to start and stop commands.
To have your service interact with the socket, you'll want to modify the WorkerThreadFunc() from the last link. This is where you should start listening for and processing inbound socket connections.
As many others here on SO I'm trying to create a networking library. The requirements basically look like this:
work asynchronously and get ready for real-time applications (I have FPS games in mind)
use UDP and set up a thin protocol layer on top as necessary
work with IPv6 natively
support multiple platforms (read: I want Mono support!)
Now after some reading about how to do this (most inspiring was Gaffer on Games) I set up my development environment, thought about how to do it and came up with this basic workflow:
Initialize a socket and tell it to use "UDPv6"
Bind that socket to a port and make exceptions not bother the user. There is a "Bound" propery that tells him that the socket is set up correctly.
Find out about the max MTU the NICs on the local machine support.
Initialize a number of SocketAsyncEventArgs, tell its Completed event to call the private dispatch method and set its buffer to the size of the max MTU from step 3.
Call the Sockets ReceiveFromAsync method with the first SAEA object around.
When data comes in, I do the following:
Call the ReceiveFromAsync method with the next free SAEA object
Get buffer and Sender information from the current SAEA object and make it available again
Fire a new event with the received message.
I did some testing on this approach and it is working quite good. I fired a message at it every 10 milliseconds with 200 bytes of data for 10000 cycles and there is pretty much no increase in CPU or memory load. Only NIC load is increasing. However I came up with some problems | questions:
When I dispose my PeerSocket class (that is holding the socket) I dispose every SAEA object. But since at least one of them is still listening for new messages, an ObjectDisposedException is thrown. Is there a way to tell it to stop listening?
The MTU may vary on the way to other peers, maybe the buffer of each SAEA object should use a different indicator for determining the buffers size?
I'm not sure how to handle fragmented datagrams yet. I will get on writing that "reliability header" into a datagram I am sending, but if a datagram is split I don't know about this header information, right?
The library will hopefully be of use to someone else one day and it's repository is publicly available. As of this question, the current commit can be found here
Wow, it is really huge subject. if you didn't learned about network sockets before you'd better learn. I can give you the gist but it is definitely not enough.
The Client:
public void Get()
{
string data;
string input;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(ipep);
}
catch (SocketException e)
{
Console.WriteLine("Unable to connect to server");
Console.WriteLine(e.ToString());
return;
}
NetworkStream ns = new NetworkStream(socket);
StreamWriter sw = new StreamWriter(ns);
StreamReader sr = new StreamReader(ns);
data = sr.ReadLine();
Console.WriteLine(data);
while (true)
{
input = Console.ReadLine();
if (input == "exite")
break;
sw.WriteLine(input);
sw.Flush();
data = sr.ReadLine();
Console.WriteLine(data);
}
Console.WriteLine("Disconnected from server...");
socket.Close();
ns.Close();
sr.Close();
sr.Close();
}
The Server:
public void Get()
{
string data;
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ipep);
socket.Listen(10);
Console.WriteLine("Waiting for a client...");
Socket client = socket.Accept();
IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with: {0}, at Port: {1}", newclient.Address, newclient.Port);
NetworkStream ns = new NetworkStream(client);
StreamReader sr = new StreamReader(ns);
StreamWriter sw = new StreamWriter(ns);
string welcome = "Welcome to my test server";
sw.Write(welcome);
sw.Flush();
while (true)
{
try
{
data = sr.ReadLine();
}
catch (IOException)
{
break;
}
Console.WriteLine(data);
sw.WriteLine(data);
sw.Flush();
}
Console.WriteLine("Disconnected from {0}", newclient.Address);
sw.Close();
ns.Close();
sr.Close();
}
Please try it out on Console application, see how it works.
Basically, the server opens the port (9050 in this example) waiting for the client connection then the client connects to the server and then starts the communication.
You mentioned you have to use UDP sockets, I presume you know about udp but if not you'd better check about the distinction between TCP and UDP especially about the way to verify that the data get to the desired destination (ad hoc concept and so on).
How can I make the server and the client to run unlimitedly and be able to exchange data(meaning, until the application is closed), instead of run for one exchange of information only.
Tried with while(true) but maybe didn't put it on the right place and then I can't really reach the methods for closing and stopping the socket and the listener.
Here's some of the code of the server:
public static void StartServer()
{
try
{
IPAddress ip = IPAddress.Parse("192.168.1.11");
TcpListener myListener = new TcpListener(ip, 8000);
myListener.Start();
Socket s = myListener.AcceptSocket();
byte[] b = new byte[100];
int k = s.Receive(b);
... some other actions ...
s.Close();
myListener.Stop();
}
and then then Main() where I invoke it.
With the Client is the same story.
You can create an infinite loop which contains the Receive function processing data, and returns to receive. That way the server always excepts data from the client until server, or client terminates.
while(true)
{
byte[] buffer = new byte[100];
s.Receive(buffer);
//Do something with data...
}
Beware through because in your current design only one client is supported. If you want to support multiple clients consider using threads.
I have created simple tcp server - it works pretty well.
the problems starts when we switch to the stress tests -since our server should handle many concurrent open sockets - we have created a stress test to check this.
unfortunately, looks like the server is choking and can not respond to new connection request in timely fashion when the number of the concurrent open sockets are around 100.
we already tried few types of server - and all produce the same behavior.
the server: can be something like the samples in this post(all produce the same behavior)
How to write a scalable Tcp/Ip based server
here is the code that we are using - when a client connects - the server will just hang in order to keep the socket alive.
enter code here
public class Server
{
private static readonly TcpListener listener = new TcpListener(IPAddress.Any, 2060);
public Server()
{
listener.Start();
Console.WriteLine("Started.");
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = listener.AcceptTcpClient();
Console.WriteLine("Connected!");
// each connection has its own thread
new Thread(ServeData).Start(client);
}
}
private static void ServeData(object clientSocket)
{
Console.WriteLine("Started thread " + Thread.CurrentThread.ManagedThreadId);
var rnd = new Random();
try
{
var client = (TcpClient)clientSocket;
var stream = client.GetStream();
byte[] arr = new byte[1024];
stream.Read(arr, 0, 1024);
Thread.Sleep(int.MaxValue);
}
catch (SocketException e)
{
Console.WriteLine("Socket exception in thread {0}: {1}", Thread.CurrentThread.ManagedThreadId, e);
}
}
}
the stress test client: is a simple tcp client, that loop and open sokets, one after the other
class Program
{
static List<Socket> sockets;
static private void go(){
Socket newsock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("11.11.11.11"), 2060);
try
{
newsock.Connect(iep);
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message );
}
lock (sockets)
{
sockets.Add(newsock);
}
}
static void Main(string[] args)
{
sockets = new List<Socket>();
//int start = 1;// Int32.Parse(Console.ReadLine());
for (int i = 1; i < 1000; i++)
{
go();
Thread.Sleep(200);
}
Console.WriteLine("press a key");
Console.ReadKey();
}
}
}
is there an easy way to explain this behavior? maybe c++ implementation if the TCP server will produce better results? maybe it is actually a client side problem?
Any comment will be welcomed !
ofer
Specify a huge listener backlog: http://msdn.microsoft.com/en-us/library/5kh8wf6s.aspx
Firstly a thread per connection design is unlikely to be especially scalable, you would do better to base your design on an asynchronous server model which uses IO Completion Ports under the hood. This, however, is unlikely to be the problem in this case as you're not really stressing the server that much.
Secondly the listen backlog is a red herring here. The listen backlog is used to provide a queue for connections that are waiting to be accepted. In this example your client uses a synchronous connect call which means that the client will never have more than 1 connect attempt outstanding at any one time. If you were using asynchronous connection attempts in the client then you would be right to look at tuning the listen backlog, perhaps.
Thirdly, given that the client code doesn't show that it sends any data, you can simply issue the read calls and remove the sleep that follows it, the read calls will block. The sleep just confuses matters.
Are you running the client and the server on the same machine?
Is this ALL the code in both client and server?
You might try and eliminate the client from the problem space by using my free TCP test client which is available here: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html
Likewise, you could test your test client against one of my simple free servers, like this one: http://www.lenholgate.com/blog/2005/11/simple-echo-servers.html
I can't see anything obviously wrong with the code (apart from the overall design).