Ok so I am new to socket programing and I'm making a game that is going to run from a server. I am going to try to be able to get a hundred clients to run off my server. Should I make one listener instance or one for every client? Also I've tried to make a hundred listeners all at 100 different ports but when I run my server I get an error while trying to start my listeners. The game is going to be a 3D RPG/MMORPG. Most of the game logic is in the clients though. What do you think that I should do?
If you are going to use TCP sockets, then you should create one listener socket (i.e. create a socket, bind it to a specific port and call Listen() on it). Then, when you Accept a connection and get another socket, which you use for receiving/sending data from/to client:
Socket socketListener;
// create listening socket
socketListener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 30120); // use port 30120
//bind to local IP Address.
socketListener.Bind(ipLocal);
//start listening
socketListener.Listen(4);
while (true) // loop that accepts client connections
{
Socket socketWorker = socketListener.Accept();
HandleClientConnection(socketWorker); // your routine where you communicate with a client
}
Also, consider using sockets in asynchronous mode, that will be more efficient in terms of performance.
You only ever have one listener per server endpoint. The listener will then create a connection for the client that uses a different port. It is this connection you actually use for communication.
Related
I am going to create multiple synchronous clients . I need some explanation about below code.
When i am creating a socket like below and call connect what is happening at network level.
I believe when we create a socket and call connect, a TCP/IP connection a tunnel made between client socket and server socket.
Once this sender(socket) connect with server ,that client & server will have a unique tunnel between them.
if i create another client it will have another unique tunnel between them.
In case if we got an error, that the client is not connected, always we should reconnect using existing socket(sender) then we will access the same data/connection that we had.
And we should not create a new socket then we will have a new tunnel and we will lost the previous connection and data.
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
sender.Connect(remoteEndpoint)
Please clarify if i am wrong.
What you call tunnel is really called a connection. Broken connections cannot be revived. Data loss is to be expected.
When you reuse an existing socket object to connect again you are creating a new connection. Reusing socket objects is not recommended (by me) because it is confusing.
Note, that TCP does not know what a socket is. The spec does not contain that word. Sockets are OS-level things.
Most of the examples online are examples of a multithreaded tcp server, whereby the server listens for multiple incoming connections from the client.
What I'm looking for is for the "server", to initiate the connections. If I have 100 devices (all different IP address of course), my server will have to make 100 individual connections to each device and receive data from the devices.
This is how I would make my connection to a device
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
_socket.SendTimeout = 2000;
_socket.ReceiveTimeout = 2000;
_socket.Connect(new IPEndPoint(IPAddress, TCPPort));
But I would like to know if there's any component out there, that would fulfill the following
establish as many tcp connections as I want to the devices
receive & send data through the connection
handle tcp timeouts/disconnects/etc & re-establish connection to the IP
If there aren't any of such components, are there any tips as to how I should go about doing it? e.g., 1 connection per thread, or how do I handle if the data is received in multiple packets, etc?
Any insights would be greatly appreciated
There are several existing components out there that you could use to achieve what you want. Checkout http://www.networkcomms.net and http://code.google.com/p/lidgren-network-gen3/.
Having said that people always prefer to add that there is nothing stopping you writing everything from scratch yourself as per the example you give.
Disclaimer: I'm a developer for NetworkComms.Net.
This is my listening function and connection function
Socket Listen
public void Listen(){
IPEndPoint ep = new IPEndPoint(IPAddress.Any, PortNumber);
Listen.Bind(ep);
Listen.Listen(10);
Listen.BeginAccept(new AsyncCallback(NewConnection), null);}
public void NewConnection(IAsyncResult asyn)
{
Socket Accepted = Listen.EndAccept(asyn);
Listen.BeginAccept(new AsyncCallback(NewConnection), null);
SomeFunction(Accepted);
}
the code works fine and there is no problem - I traced the code to see how to work with different clients and I understand the flow. However, I don't understand how can 1 socket serve different clients. Does it time multiplex between the clients over the socket?
I read on MSDN that Accepted in my code can be only used for the established connection and can't be used any further - that part I don't understand. What actually happens when the client tries to connect to the server socket? Does EndAccept return a totally different socket with different port to establish the connection and keep listening with the same socket to accept more requests at the same time?
What you've said is basically correct, based on my understanding. The Accepted socket is not the same as Listen. After you EndAccept, you can kick off another BeginAccept async call with your listen socket, and you can use the newly created socket to communicate with your remote peer.
To verify, you can check the local port of the listen socket and the connected socket; they should be different.
So ideally, I am looking for a way to unite TCP and UDP on the server and manage both these connections under individual client threads. Currently, I am wondering if it is possible to accept a TCP connection and set up UDP communication from that.
Here is my ideal setup:
Client connects on TCP to server via TCPClient.connect()
Server accepts TCP connection via TCPListener
when server accepts TCP connection, it also gets the IPEndpoint from the TCP connection
and uses that to begin UDP communcation with:
serverUDPSocket.BeginReceiveFrom (byteData, 0, 1024,
SocketFlags.None, ref (Endpoint)ThatIPEndpointThatIJustMentioned,
new AsyncCallback(client.receiveUDP),
(Endpoint)ThatIPEndpointThatIJustMentioned);
^so this is where I am running into a little bit of a theoretical issue. From my understanding, the endpoints for TCP and UDP would be formatted differently. How can I resolve this issue? I would like to avoid having the client connect to UDP on a separate thread and then uniting these threads under a single managing class.
EDIT:
Here is the code that I am trying to implement:
//Listening for TCP
TcpClient newclient = listenTCP.AcceptTcpClient(); //Accept the client
Client clientr = new Client(newclient); //Create a new Client class to manage the connection
clientr.actionThread = new Thread(clientr.action); //This thread manages the data flow from the client via the TCP stream
clientr.actionThread.Start(clientr);
EndPoint endPoint = newclient.Client.RemoteEndPoint; //so this is the sketchy part. I am trying to get the endpoint from the TCP connection to set up a UDP "connection". I am unsure about the compatibility as UDP and TCP sockets are different.
UDPSocket.BeginReceiveFrom(new byte[1024],0,1024, SocketFlags.None,ref endPoint, new AsyncCallback(clientr.receiveUDP), null); //the AsyncCallBack is like the manager thread for UDP (same as in TCP)
clients.Add(clientr);
There is no problem in creating two listeners in one application, even if they use different protocol. I suppose you are not asking if you can do it on the same port (there is no point to do it anyway).
However listener is consuming thread so it need different thread if there is gui or some process to do in application (for example calculations meanwhile).
If you want to do everything in one thread you must first receive message from first listener, then setup second one. There is no possibility to setup 2 listeners in one thread at the same time because if you setup first listener it will consome whole thread waiting for message.
This was due to a lack of understanding of UDP on my part from the code level.
I ended up setting up the other method I described where it would accept initial UDP packets individually and then direct the communication (EndPoint + Message) towards a managing client class by comparing IP addresses.
I have some problems with a device brought for signal capturing (vilistus), as its software is supposed to send data to a tcp port (#123) during capturing and I used a c# code with a tcp listener to receive the data from the same port but the program is blocked at the accepttcpclient() command line and no data is received.
TcpClient client = this.tcpListener.AcceptTcpClient();
It sounds like a client isn't connecting to the listener. When you call AcceptTcpClient on a TcpListener the application will hang there waiting for a client to connect which seems to be the issue you're having.
You can get around this issue by doing a BeginAcceptTcpClient which will free the application and allow the program to continue executing while you wait for a client. When a client then connects a delegate will be called and then you can start processing the client, reading data etc. So for example:
class Comms
{
TcpListener listener;
TcpClient client;
// Starts listening for a tcp client
public void StartListener()
{
listener = new TcpListener(IPAddress.Any, 123);
listener.BeginAcceptTcpClient(new AsyncCallback(ClientCallback), listener);
}
// Callback for when a client connects on the port
void ClientCallback(IAsyncResult result)
{
listener = (TcpListener)result.AsyncState;
try
{
client = listener.EndAcceptTcpClient(result);
// From here you can access the stream etc and read data
}
catch (IOException e)
{
// Handle any exceptions here
}
}
}
Providing the client connects correctly you will then be free to access the clients NetworkStream and then read and write data to the client. Heres a quick reference and example for you to take a look at:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient.aspx
When it comes to the reading and writing of data you will have a similar lock up problem with the client's NetworkStream Read and Write functions. For this problem you have two possible solutions:
Set a timeout for the read and write functions, by setting the ReadTimeout and WriteTimeout properties of the NetworkStream.
Use a similar callback method as with BeginAcceptTcpClient by using the BeginRead and BeginWrite functions found in the NetworkStream.
Personally I prefer the second option as the first won't free the program until the timeout occurs but they're both viable options and it depends which one you'd prefer to implement. You can go here for more information about the NetworkStream:
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx
Hope this helps
It sounds strange that the device is being the client. Are you sure that you should not use tcpClient.Connect() to the device on port 123?
Why?
How should the device know that you got a server running? It can't try to connect forever.
How do the device know that port 123 is free for your application in your PC?