I am experimenting with client-server applications using the System.Net namespace in C#. I am currently using the following TcpListener code to listen for incoming connections:
TcpListener listener = new TcpListener(IPAddress.Any, 62126);
List<Connection> ClientConnections = new List<Connection>();
while (true)
{
listener.Start();
while (true)
{
if (listener.Pending())
{
ClientConnections.Add(new Connection(listener.AcceptTcpClient()));
break;
}
}
}
(Where Connection is a class that takes the accepted TcpClient via public Connection(TcpClient client) { ... } and maintains the connection on a separate thread.)
Do I need to invoke listener.Start() every time an incoming connection is accepted or is that unnecessary?
You're busy waiting if no pending connection requests exist. This is not necessary. Just delete that if. Make sure you understand why it is not necessary.
I do not understand why there are two nested loops. You only need one. Call Start only once.
I can tell that you have not read the documentation. Quite dangerous. You are capable of answering these questions yourself.
No. Start needs to be called only once. Remove the outer while loop
Related
I am new to c# and I am building server / client application.
I have created both the server and the client successfully , but when any client connects to the server... I need to save that client because the server is supposed to send them a message after 10 minutes .
private void Form1_Load(object sender, EventArgs e) {
TcpListener myList;
myList = new TcpListener(IPAddress.Any, 8001);
while (true)
{
TcpClient client = myList.AcceptTcpClient();
MessageBox.Show("Connection accepted from " + client.Client.LocalEndPoint.ToString());
}
}
Now , my problem is how to save "client" id or anything about this client which is connected, to send message after 10 minutes from server to this client.
Can anyone help please?
Form onLoad is rather bad place to accept clients. Instead use ,for example, Background Worker. Also you might want to avoid using while(true) without any way to break the loop.
Object storage must be outside of method (event handler) to preserve connections from evil Garbage Collector. There are many ways to store object, it might be array (bothersome) or some collection, which although heavier to compute are pleasant to use. You can even use Concurent collections which will take care of thread synchronization on their own.
Dictionary<string,TcpClient> clientDict;
List<TcpClient> clientList;
...
void acceptClients()
{
TcpListener myList;
myList = new TcpListener(IPAddress.Any, 8001);
while (true)
{
TcpClient client = myList.AcceptTcpClient();
clientDict.Add("client nickname, id etc.",client);
clientList.Add(client);
MessageBox.Show("Connection accepted from " + client.Client.LocalEndPoint.ToString());
if (clientList.count>=8 || clientDict.count>=8)
{
break; // I want to break freeeeee!!!!
}
}
}
...
void sendToClient(string nick)
{
if (clientDict.ContainsKey(nick))
{
TcpClient client = clientDict[nick];
//and use selected client.
}
}
void broadcast()
{
foreach(TcpClient client in clientList) //clientList can be replaced with clientDict.Values
{
//and use selected client.
}
}
you would have to store the TCPClient in some list/dictionary. Regarding identifying connections you can use IP/Port in the TCPClient to differentiate between different connections.
Below is one such article i have posted to create a multi-threaded TCP chat application. it might be helpful.
http://shoaibsheikh.blogspot.com/2012/05/multi-threaded-tcp-socket-chat-server.html
The only possible way is to keep the connection open. Because many clients connect from behind NAT devices (corporate access points, home routers etc) is not possible to ask the client for a 'call back' address (IP:port).
What that mean in C# code, you need a reference to the client object you created in AcceptTcpClient. When you want to send something, you must retrieve this object and Write something into the client's stream (obtained via client.GetStream()). How exactly this is accomplished, it depends entirely on your code. A Dictionary perhaps? Do expect the connection to had closed by then for various reasons, even if KeepAlive is set.
Note that having a large number of accepted connections is not feasible (for many reasons).
preface:
I've been stumped on this for awhile now and am not having much luck finding what I need.
I have a C# (.NET 3.5) Service. One thread acts as an asynchronous listener for incoming TCP connections. When data comes in I spawn off a new worker thread to handle the data, and sends an acknowledgement back.
On a second thread in the same service we send commands out, until today it would gather information from the data base, build a new socket, connect then ship the command and I'm using the Socket.Receive to invoke blocking and wait for a response (or until a timeout occurrs).
Everything has been working great until a new client has a need to send data to us so fast (5-10 second intervals) that we can no longer open a new socket to get a command through. So I started looking into when a command needs to be sent that the "listener" thread has a client connected. If that client is connected currently use that socket instead of creating a new one.
Issue:
I'm to the point where I can send my command back on the same socket the listener receives, but when the client sends data back as the response it takes twice for the Socket.Receive method to actually fire thinking it received data. The first time it gets into my listener class, the 2nd time, in my command class where I actually want it to be.
Question:
Is there some option or something I need to do before calling my Socket.Receive method to ensure the data gets to the correct place?
In my listener class I have a list of objects "CSocketPacket"
public class CSocketPacket
{
public CSocketPacket(System.Net.Sockets.Socket socket)
{
thisSocket = socket;
this.IpAddress =
((System.Net.IPEndPoint)socket.RemoteEndPoint).Address.ToString();
}
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[BUFFER_SIZE];
public string IpAddress; //Use this to search for the socket
}
Then when I send a command I'm creating a new tcp socket object:
client = new Socket(
AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(
IPAddress.Parse(Strings.Trim(ipAddress)), port);
IPEndPoint LocalIp = new IPEndPoint(IPAddress.Parse(
System.Configuration.ConfigurationManager.AppSettings["SourceIP"]), port);
then I'm looking into my listener class list to see if that socket is connected:
if (listener.SocketExists(ipAddress))
{
// set the client socket in this class to the
// instance of the socket from the listener class
SocketIndex = listener.FindSocketInList(ipAddress);
if (SocketIndex != -1)
{
// might need to figure out how to avoid copying the socket
// to a new variable ???
client = listener.ConnectedSockets[SocketIndex].thisSocket;
SocketBeingReUsed = true;
}
}
else
{
// try to connect to the client
client.Connect(ep);
}
finally I go through my steps of sending and receiving
if (client.Connected)
{
if (client.Poll(1000, SelectMode.SelectWrite))
{
int sentAmount = Send(ref client);
client.ReceiveTimeout = 90000; //90 seconds
returnData = ReceiveData(ref client, sentAmount);
}
}
everything works up to the point in my ReceiveData(ref client, sentAmount) method where I call the Socket.Receive(data, total, Socket.ReceiveBufferSize, SocketFlags.None); method.
I've been using a tool called Hercules to test sending/receiving packets across two machines on my home network.
Does anyone have any ideas of what I can do to solve this? I do apologize for such a lengthy question but I want to try to give as much info and not paste my entire project. I'm up for any suggestions.
Disclaimer: I wrote this code approx 3 years ago, so I'm pry doing things I shouldn't be I'm sure :P
Thanks to all who read this.
Sincerely,
Chris
OK, so now I'm following along! Given what you've said in the comments above, then the way to solve the problem is to have a single class/thread that reads from the socket (which is the correct way to read from sockets anyway) and then it will coordinate which class gets the data. I think it might work a little like the Command Design Pattern.
Say I have a TcpClient that I accept from a TcpServer in c#, and for some reason it keeps defaulting with blocking off. Is there some other force that can change how the socket blocking is set? Like say is it affected by the remote connection at all?
I know I set blocking to fale a few builds back, but I changed it, and even introduced the TcpClient instead of a straight socket. I haven't specifically changed the blocking back to true, I just commented blocking = false out. Is that something that persists maybe with the endpoint?
I don't know though it just seemed that as I was programming one day my sockets just became unruley without any real change in their code.
public void GetAcceptedSocket(TcpClient s)
{
try
{
sock = s;
IPEndPoint remoteIpEndPoint = s.Client.RemoteEndPoint as IPEndPoint;
strHost = remoteIpEndPoint.Address.ToString();
intPort = remoteIpEndPoint.Port;
ipEnd = remoteIpEndPoint;
sock.ReceiveTimeout = 10000;
boolConnected = true;
intLastPing = 0;
LastPingSent = DateTime.Now;
LastPingRecieved = DateTime.Now;
handleConnect(strHost, intPort);
oThread = new Thread(new ThreadStart(this.run));
oThread.Start();
}
catch (Exception e)
{
handleError(e, "Connect method: " + e.Message);
}
}
Like say is it affected by the remote
connection at all?
Nope.
It would have been better if you show some code where you create Socket or TcpClient in server side. I cannot find TcpServer class in C#. Are you talking about TcpListener?
If you are, please make it sure that you set Socket's Blocking true if you use AcceptSocket to create a new socket. If you call AcceptTcpClient, you should not worry about blocking or non-blocking mode as TcpClient is always blocking mode.
The TcpClient class provides simple
methods for connecting, sending, and
receiving stream data over a network
in synchronous blocking mode.
from MSDN.
There really is no answer, I've never duplicated this, and after a few months, and a fresh windows install, picked the code up, and didn't have the problem anymore. Very weird though, defiantly couldn't find a programmatic reasoning for it happening. Like I said, after a few months it just kinda worked?
They should really have an 'Unawnserable' option :p.
Probably just watch this video: http://screencast.com/t/OWE1OWVkO
As you see, the delay between a connection being initiated (via telnet or firefox) and my program first getting word of it.
Here's the code that waits for the connection
public IDLServer(System.Net.IPAddress addr,int port)
{
Listener = new TcpListener(addr, port);
Listener.Server.NoDelay = true;//I added this just for testing, it has no impact
Listener.Start();
ConnectionThread = new Thread(ConnectionListener);
ConnectionThread.Start();
}
private void ConnectionListener()
{
while (Running)
{
while (Listener.Pending() == false) { System.Threading.Thread.Sleep(1); }//this is the part with the lag
Console.WriteLine("Client available");//from this point on everything runs perfectly fast
TcpClient cl = Listener.AcceptTcpClient();
Thread proct = new Thread(new ParameterizedThreadStart(InstanceHandler));
proct.Start(cl);
}
}
(I was having some trouble getting the code into a code block)
I've tried a couple different things, could it be I'm using TcpClient/Listener instead of a raw Socket object? It's not a mandatory TCP overhead I know, and I've tried running everything in the same thread, etc.
Maybe it's some kind of dns resolve? Are you using IP address to access your server's host or some name which is being resolved by your DNS? The code ParmesanCodice gave should work with no delay unless there's something wrong on client/network side.
Try to add following line to your windows\system32\drivers\etc\hosts:
127.0.0.1 localhost
it may solve your problem or just connect as 127.0.0.1:85
You should consider accepting your clients asynchronously, this will most likely remove the lag you are seeing.
I've modified your code slightly
public IDLServer(System.Net.IPAddress addr,int port)
{
Listener = new TcpListener(addr, port);
Listener.Start();
// Use the BeginXXXX Pattern to accept clients asynchronously
listener.BeginAcceptTcpClient(this.OnAcceptConnection, listener);
}
private void OnAcceptConnection(IAsyncResult asyn)
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener) asyn.AsyncState;
// Get the newly connected TcpClient
TcpClient client = listener.EndAcceptTcpClient(asyn);
// Start the client work
Thread proct = new Thread(new ParameterizedThreadStart(InstanceHandler));
proct.Start(client);
// Issue another connect, only do this if you want to handle multiple clients
listener.BeginAcceptTcpClient(this.OnAcceptConnection, listener);
}
Doesn't the debugger add overhead ?
I had issues like this when I was building my MMO server.
can't remember how I got round it now.
I think this has something to do with resource allocation on services, I use the approach suggested by ParmesanCodice (well a similar one at least) and during testing I found that the first 5 to 10 connections were rubbish but after that the service seems to hammmer out new connections like theres no tomorrow ...
Maybe its a socket thing in the framework.
Have you tried a load test?
Throw say 1000 connections at it and see what happens, it should get faster after handling each one.
You could avoid the entire Listener.Pending while loop. AcceptTcpClient() is a blocking call so you could just let your code run and pend on that. I don't know why that loop would take 1 second (instead of 1 millisecond) but since you indicate that is where the lag is, you can get rid of it.
i am using c# sockets Asynchronous mode.
i need to serve only one connection in my application from a server point of view. once one is connected then i would like to refuse any more connection requests.
also the server only serves to connect to a single client. when the communication is done the server has to be restarted.
but from what i have read on the topic, it is not possible to close beginaccept.
i would like some ideas regarding how get around this situation.
Normally, in the BeginAccept async callback you would call BeginAccept again so that another connection can be accepted. However, you can omit this step if you do not want to allow another connection. So that the connection is refused in a timely manner, consider also closing the listening socket in the callback. The accepted Socket will remain open in this case for you to use even though the listening socket is closed.
class SocketTest
{
private Socket m_Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Test()
{
m_Listener.Bind(new IPEndPoint(IPAddress.Loopback, 8888));
m_Listener.Listen(16);
m_Listener.BeginAccept(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult ar)
{
Socket s = m_Listener.EndAccept(ar);
m_Listener.Close();
/* Use s here. */
}
}