0
votes

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?

1
assume the system admin lies. try to run your server and test connection using technet.microsoft.com/en-us/sysinternals/jj729731.aspx on the port. upload a version of the code that tries to ping your client IP. also both sides should always test for firewall/connection problems and log them.Nahum
You don't have to show us "all of my code" - and, indeed, that would be counter-productive. What would be useful is for you to create a MCVE.Damien_The_Unbeliever
A common error on TCP implementations relates to the processing of the received stream. The reception process must take into account that a send request may be received in different blocks. One need to encapsulate a send data either with Length-value method or with separators, e.g. STX and ETX.Graffito
You seem to have given up due to a minor network routing problem. Just fix the problem. Clearly, the code works on your machine. (Closing this question, though, because there is not enough information here to answer. This seems to be a routing problem, nothing more.)usr
I'm pretty sure your problem is in the ReadCallback code. It seems like you're ignoring message framing (you're not sending the length of the string, nor is there a terminator; but it's impossible to tell for sure without the ReadCallback code) - TCP is a stream, not a bunch of messages. Windows handles local TCP completely differently, which can often lead to applications working (mostly) fine on localhost, but failing utterly when tested over a real network connection. Internet communication tends to exponse more issues.Luaan

1 Answers

1
votes

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.