1

I have a server side on my raspberry pi written on C++. I have all sockets logic in another thread, so it should not affect to my main thread. Here is the Servers.hpp:

#pragma once

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <thread>
#include <chrono>

using namespace std;

#define S_OUT_PORT 63253

class TestServer
{
public:
    static void Start();
private:
    static bool threadIsRunning;
    static void LoopOut();
};

Here is the .cpp file:

#include <Servers.hpp>

bool TestServer::threadIsRunning = true;

void TestServer::Start()
{
    threadIsRunning = true;
    thread th(LoopOut);
    th.detach();
}

void TestServer::LoopOut()
{

        try
        {
            int server_fd, new_socket;
            struct sockaddr_in address;
            int opt = 1;
            int addrlen = sizeof(address);

            if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
            {
                // logging
                return;
            }

            if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
            {
                // logging
                return;
            }
            address.sin_family = AF_INET;
            address.sin_addr.s_addr = INADDR_ANY;
            address.sin_port = htons(S_OUT_PORT);

            if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0)
            {
                // logging
                return;
            }

            if (listen(server_fd, 3) < 0)
            {
                // logging
                return;
            }

            if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0)
            {
                // logging
                return;
            }

            cout << "SC got connection" << endl;

            while (true)
            {
                 //SendString(new_socket, "null:null", 9);
                int strLen = 9;
                string str = "null:null";

                char b[4] = { (strLen & 0xff), ((strLen >> 8) & 0xff), ((strLen >> 16) & 0xff), ((strLen >> 24) & 0xff) };
                const char* p = reinterpret_cast<const char*>(b);
                send(new_socket, p, 4, 0);
                send(new_socket, str.c_str(), strLen, 0);

                this_thread::sleep_for(chrono::milliseconds(20));
            }
        }
        catch (const std::exception& e)
        {
            cout << "SC error" << endl;
        }
    cout << "SC thread exited" << endl;
}

And I start this server just calling TestServer::Start() in main:

int main()
{
    try
    {
        TestServer::Start();

        while (true)
        {
            cout << "Test" << endl;
        
            this_thread::sleep_for(chrono::milliseconds(3000));
        }
    }
    catch (const std::exception& e)
    {
        cout << "Main error" << endl;
    }
    
    return 0;
}

Then when I'm trying to connect to the server from my pc using C# everything is ok. But when I close the socket from C# side, C++ just terminates. Here is how I shut down connection on C# side:

sct.Shutdown(SocketShutdown.Both);
sct.Close();

What could be the reason of this? Why does socket's shutdown and close kill my main thread in C++?
EDIT 1: Here is the output on the server side:

Test
Test
Test
SC got connection
Test
pi@raspberrypi:~/picadCpp/build $ 

And the loop in LoopOut method removed, but result is the same...

crackanddie
  • 688
  • 1
  • 6
  • 20
  • Not a solution, but having `using namespace std;` in a header may give issues down the line. – DS_London Nov 06 '21 at 16:18
  • @DS_London thanks, didn't know about that! – crackanddie Nov 06 '21 at 16:19
  • 1
    What’s the output on the server side? – DS_London Nov 06 '21 at 16:46
  • Most likely the server side crashes. The code in `LoopOut()` needs to be changed considerably. You should only call `socket()`, `bind()` and `listen()` once. The should be moved outside the loop. And there needs to be some way of detecting that the client has closed the connection. – Codo Nov 06 '21 at 16:49
  • @Codo I have this loop only to be able to reconnect to the server. I removed it, but the result is the same. Question is updated. – crackanddie Nov 06 '21 at 16:59
  • The typical server calls `socket()`, `bind()` and `listen()` once and then many connections from clients using `accept()`. Often `accept()` creates a new thread so multiple clients can be handled concurrently. The code handling the communication with the client ends the thread if the client disconnect. Your current code can accept a single client and has no way of gracefully ending if the client disconnects. It cannot handle multiple clients, neither concurrently nor serially. – Codo Nov 06 '21 at 17:07
  • 1
    @Codo Thanks for the comment! But I don't need for multiple connections to one server. I just want to reconnect to it, after dissconnetion. But that's not the point. Even if it can't handle multiple connection, why does it stop my main thread? Or what should I do, so my program can gracefully end if client disconnects? – crackanddie Nov 06 '21 at 17:12
  • And it seems you aren’t catching any exceptions anyway? Maybe try adding `catch(…)` clauses, as ,AFAIK, the std::exception class is only for exceptions thrown by the std library: ie not the socket library. – DS_London Nov 06 '21 at 17:46
  • @DS_London thanks for the comment. But where could I find all possible exception that could be thrown by socket library? I searched some sites but can't find anything about it. And I tried to write AFAIK instead of std::exception, but cmake gave me errors, that it doesn't know what is AFAIK (Maybe I do something wrong, I don't understand it). But anyway. If it doesn't catch with std::exception, then it should write the error message to bash. isn't it? – crackanddie Nov 06 '21 at 18:00
  • AFAIK =“ as far as I know”. Instead of `catch (const std::exception& e)` use `catch(…)`. The ellipsis (…) means “catch anything that hasn’t already been caught”. That said I dont know how Pi manifests exceptions. – DS_London Nov 06 '21 at 18:04
  • @DS_London Oh, really, it was quite funny :) But anyway it didn't help – crackanddie Nov 06 '21 at 18:08
  • Some hints: Aside from the SIGPIPE signal, `send()` will return 0 or a negative number if the connection closes. No signal is triggered, if the client uses a half close. The socket library you are using is a C library. C does not have exceptions. So no exceptions are thrown. To reconnect, just call `accept()` again. As it is currently, the server socket is still open after the client disconnect. Opening it a second time will fail. – Codo Nov 06 '21 at 22:14
  • ok, thanks to all of You. I'll try it all – crackanddie Nov 07 '21 at 10:47

0 Answers0