I want to learn about socket communication so I decided to try to write WP 8.1 text communicator. It is based on TCP sockets. I almost managed to finish it, but I am searching for improvemenets.
What is worth mentioning I use a socket server between phones (console application), to avoid problems with private ip addresses. It contains information about all connected users and forwards messages to clients (for instance user A sends message to user B, so firstly message goes to server and server forward it to destination address).
The problem appeared when i realized that I need to send special messages from server to client and vice versa (for example when two clients want to have conversation, they send request to server, so it knows where to forward messages).
This is my connection listener method from server application
private void ConnectionListener()
{
IPEndPoint localDataEndPoint = new IPEndPoint(IPAddress.Parse(LocalIpAddress), 1234);
IPEndPoint localMessageEndPoint = new IPEndPoint(IPAddress.Parse(LocalIpAddress), 4321);
Socket dataConnectionListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket messageConnectionListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
dataConnectionListener.Bind(localDataEndPoint);
dataConnectionListener.Listen(100);
messageConnectionListener.Bind(localMessageEndPoint);
messageConnectionListener.Listen(100);
while (true)
{
TcpSocket.clientDone.Reset();
IAsyncResult tmp1 = dataConnectionListener.BeginAccept(ConnectionCallback, null);
IAsyncResult tmp2 = messageConnectionListener.BeginAccept(ConnectionCallback, null);
TcpSocket.clientDone.WaitOne();
Socket dataSocket = dataConnectionListener.EndAccept(tmp1);
Socket messageSocket = messageConnectionListener.EndAccept(tmp2);
TcpSocket tmpTcpSocket = new TcpSocket(dataSocket, messageSocket);
tmpTcpSocket.Start();
connectedUsersSockets.Add(tmpTcpSocket);
UpdateConnectedUserList();
}
}
catch (Exception ex)
{
Log.E("Connection listener ran into an exception", ex);
}
}
As you can see I have created two TCP sockets to liesten on different ports. dataSocket is for normal messages and messageSocket is for special messages (sorry for confusing names, I have to refractor code).
On client side it works the same way: there are two different socket to communicate with and through the server.
I wanted to avoid managing two sockets rather then one. But the only way I can imagine is that on every received message server would have to check if it's special (and handle it in special way) or just send to client.
The question: Is there a better way to manage these special messages?
Thanks to all in advance!
P.S.
Sorry for my poor english, it's not my native language
Related
I'm trying to make two applications. One will be sending data to a specific udp port, and the other will be reading it.
I am having 2 problems:
when running on the same machine, I get an error: "Only one usage
of each socket address (protocol/network address/port) is normally
permitted" so I need to figure out how to test it if I cannot have
multiple socket connections at the same port.
when I tried using
an internal ip of another computer within my network, I did not get
any reading at all.
server:
private Socket sock;
private const int PORT = 5000;
public void start()
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.ReceiveTimeout = 1;// seconds
sock.SendTimeout = 1;// seconds
IPEndPoint iep = new IPEndPoint(IPAddress.Any, PORT);
EndPoint ep = (EndPoint)iep;
sock.Bind(iep);
MulticastView view_obj = new MulticastView();
while(true)
{
try
{
if (sock.Connected)
{
sock.Send(Serializer.ObjectToByteArray(view_obj));
}
}catch(Exception ex){
Console.WriteLine(ex);
}
Thread.Sleep(1000); // milliseconds
}
}
client:
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint iep = new IPEndPoint(ip, PORT);
EndPoint ep = (EndPoint)iep;
UdpClient client = new UdpClient(PORT);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// or using: Byte[] receiveBytes = client.Receive(ref ep);
Byte[] receiveBytes = client.Receive(ref RemoteIpEndPoint);
MulticastView view;
view = (MulticastView)Serializer.ByteArrayToObject(receiveBytes);
Note that I need separate apps (on separate processes).
You can't have 2 separate sockets open on the same IP address / port. Each IP/Port is a unique mailbox, so to speak. (Technically, it is possible to have 2 processes attached to the same socket, under certain circumstances, but that isn't relevant to your problem). The rule is simple, but the workarounds are several.
I would ask if the client really needs to have a standard port number. Normally, UDP/TCP clients just use a random socket and communicate with the server. The server is usually the only side of the connection that needs a standard, fixed port. The UdpClient.Receive() method will populate the IPEndPoint with the ip/port of the sender of the packet so that you can reply to it.
Either don't bind to IPAddress.Any (that causes it to bind to all interfaces). Replace the Any with a specific IP address (one machine can have multiple if you setup IP aliasing or multiple adapters), or simpler, change the port number of the client to differ from the server. You should be able to bind one end to the primary ethernet interface IP address, and bind the client to the loopback (127.0.0.1) address.
Even though this is an old question, I think it would be good to point out an exception to the one port rule.
If you are using multicast (which is UDP to a multicast address), you can set the SO_REUSEADDR option to use the port for multiple sockets.
I've got a little problem with the .Net Sockets in C#.
I programmed a client and a server working with TCP.
As the client is opened it sends a handshake to the server. The server answers with it's state (clientexists, clientaccepted,...). After that the application sends a getdata-request, abandons the connection and listens for the server's 'response'. Now, the server builds a connection to the client and sends all the data the client needs.
The code and everything else works, but the problem:
On our company testserver it works fine, on the live server only the handshake works. After it the client doesn't receive any more data. Serverapplication is the same on both servers.
I thought the problem was caused by some firewall (server wants to build a tcp connection to the client -> not good), but the system administrator said there is no firewall that could block that.
Now I'm searching for a ('cheap') solution that doesn't take too much time and changes in code. If anyone knows how to theoretically solve that, that would be great.
BTW: I am not allowed to do anything on the live server other than run the serverapplication. I don't have the possibility to debug on this server.
I can't publish all of my code, but if you need to see specific parts of it, ask for it please.
---EDIT---
Client-Server communication
1) Client startup
Client send handshake (new tcp connection)
2) Server validates handshake and saves IP
Server responds with it's client state (same tcp connection)
3) Client acknowledges this response and abandons this connection
Client sends getdata-request (new tcp connection)
Client abandons this tcp connection, too
4) Server receives getdata-request and collects the needed data in the main database
Server sends all the collected data to the client (multiple tcp connections)
5) Client receives all data and displays it in it's GUI (multiple tcp connections and the order of the data is kept by working with AutoResetEvents and Counts of sockets to send)
This is the main part my code does. It's by far not the best but it was for me as I wrote it I guess. Step one, two and three work as intended. The processing of the data works fine, too.
Another thing i forgot to mention is that the solution uses two Ports '16777' and '16778'. One to receive/listen and one to send.
My code is based on the MSDN example of the asynchronous server and client.
Sending a handshake (and getdata-request)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
Server listener
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
Socket send
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket send all data part (answer to getdata-request | socToHandle should be the socket of the previous connection of the getdata-request)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
Looking through my old code I have one idea =>
Could I send everything over the same connection by changing:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(which creates a new connection) to something that uses the same connection?
If that would work, how can I do that?
And would the listener part of the client still receive single packets?
Servers and their environment are configured to handle incoming requests properly. Clients are usually behind a router, which by default make them unable to receive incoming connections from outside their network (a good thing).
To enable incoming connections, you could configure your router to forward all requests for a certain port number to your machine. No one else on your network would be able to run the client then, though.
This is why in a typical multiple clients-single server environment, the client makes all the connections, and only the server requires any changes to the network landscape.
I don't know why you chose to connect to the clients from the server side, but I would strongly advise against this - any cheap solution that uses this mechanism may turn out to be very expensive in the end.
I am just learing about networking and I belive there's something called "dynamic ports".
I can't get my head around that, how would I implement a server, that uses dynamic ports? When setting up a socket, I'll have to bind to a specific port just like:
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234);
socket.Bind(endPoint);
socket.Listen(10);
using (Socket handler = socket.Accept())
{
/* ... */
}
}
I needed to definly set the port I wantet to listen on (1234).
As far as I understand dynamic ports, a client sends a request to a random port and the server somehow dermines which application will get those request and make a response.
How would the client say
I would like my request to be responded my the "MyCustomService01" application?
Can someone please clarify and give some sample code?
socket is your listener, that despatches onto ephemeral ports; if you look carefully at handler, in particular at .LocalEndPoint and .RemoteEndPoint, you should find it is already configured as a dynamic port. Basically, you shouldn't have to do anything special here - just communicate via handler.
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.
I read 2 C# chat source code & I see a problem:
One source uses Socket class:
private void StartToListen(object sender , DoWorkEventArgs e)
{
this.listenerSocket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp);
this.listenerSocket.Bind(new IPEndPoint(this.serverIP , this.serverPort));
this.listenerSocket.Listen(200);
while ( true )
this.CreateNewClientManager(this.listenerSocket.Accept());
}
And other one uses TcpListener class:
server = new TcpListener(portNumber);
logger.Info("Server starts");
while (true)
{
server.Start();
if (server.Pending())
{
TcpClient connection = server.AcceptTcpClient();
logger.Info("Connection made");
BackForth BF = new BackForth(connection);
}
}
Please help me to choose the one. I should use Socket class or TcpListener class. Socket connection is TCP or UDP? Thanks.
UDP is connectionless, but can have a fake connection enforced at both ends on the socket objects. TCP is a stream protocol (what you send will be received in chunks on the other end), and additionally creates endpoint sockets for each accepted socket connection (the main listening socket is left untouched, although you'd probably need to call listen() again). UDP uses datagrams, chunks of data which are received whole on the other side (unless the size is bigger than the MTU, but that's a different story).
It looks to me like these two pieces of code are both using TCP, and so as the underlying protocol is the same, they should be completely compatible with each other. It looks as if you should use the second bit of code since it's higher level, but only the server can really use this, the client needs a different bit of code since it doesn't listen, it connects... If you can find the 'connecting' code at the same level of abstraction, use that.