C++ Threads + Networking, accept fails as soon as I introduce threads - c++

I am trying to implement a small c++ server. i want to receive connections from clients, and handle all of these connections in own threads. So far so good. As long as i introduce no threads, it works fine, but as soon as i try to create a thread for a client, accept returns with -1/error.
Here is my code:
void Server::run()
{
cout << "starting server on port " << this->port << "..." << endl;
this->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (this->socket_fd < 0) {
perror("creating socket");
exit(1);
}
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(this->port);
inet_aton("192.168.201.58", &myaddr.sin_addr);
if ( bind(this->socket_fd, (struct sockaddr*)&myaddr, sizeof(myaddr))) {
perror("bind");
exit(1);
}
if (listen(this->socket_fd, 5)) {
perror("listen");
exit(1);
}
/* waiting for clients */
cout << "waiting for connection..." << endl;
int client_fd;
struct sockaddr_in remote_addr;
socklen_t remote_addr_len;
while (this->running) {
client_fd = accept(this->socket_fd, (struct sockaddr*)&remote_addr, &remote_addr_len);
if (client_fd <= 0) {
perror("accept");
this->running = false;
continue;
}
cout << "got new client with address " << inet_ntoa(remote_addr.sin_addr) << endl;
Client new_client(client_fd, remote_addr.sin_addr);
//new_client.run();
std::thread t ( &Client::run, &new_client );
//t.detach();
}
}
when I am trying to connect via telnet, I get "accept: Invalid argument". As soon as I comment out the line where I create the thread
std::thread t ( &Client::run, &new_client );
everything works fine.
I would appreciate any hints.

Try:
std::thread t ( &Client::run, std::move(new_client) );
According to the documentation, that's how you should call it.

Related

App stucks in accept() when LAN interfaces changed

I created a small app on small router with 4 LAN ports. Router has been flashed with OpenWrt system, Linux kernel 5.4.154
Devices connected to LAN ports are sending date over TCP POSTs. The app is listening on specified TCP port and sends data to the server or stores it in SD card. Everything work fine until someone will start playing with plugs on the LAN side. Somethings is happening and app hangs in accept() function waiting for incomming data.
I assume (please correct me if I'm wrong) system changes?/resets? port routing and data are not delivered to the app socket any more.
Is there a simple solution to keep the 'subscription' of TCP port?
I've tried to rewrite app in async mode, but not everything is working correctly, is this the only solution for this problem?
Below simpyfied working(!) code in blocking mode (I removed all unnecesary stuff, so it may not compile)
int main() {
// Create server_socket as socket
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
cerr << "Can't create a socket! Quitting" << endl;
}
int enable = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
{
cout << GetTime() << "Can't use SO_REUSEADDR" << endl;
}
while (true) {
// Bind the ip address and port to a socket
listenningport = 55555;
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(listenningport);
inet_pton(AF_INET, "0.0.0.0", &hint.sin_addr);
if (bind(server_socket, (sockaddr*) &hint, sizeof(hint)) == -1) {
cerr << "Can't bind to IP/port" << endl;
}
// Tell Winsock the socket is for server_socket
if (listen(server_socket, SOMAXCONN) == -1) // handle multiconnections SOMAXCONN(4096, queue)
{
cerr << "Can't listen!" << endl;
}
// Wait for a connection
sockaddr_in client;
socklen_t clientSize = sizeof(client);
while (true) {
// Waiting for data on socket; block mode
int clientSocket = accept(server_socket, (sockaddr*) &client, &clientSize);
if (clientSocket == -1) {
cerr << "Problem with client connecting!" << endl;
// break the loop and try to renew socket connection
break;
}
else {
// receive all data till the end of message
int bytesReceived = 0;
while ((bytesReceived = recv(readSocket, out_data + msgSize, maxSizeOutData - msgSize - 1, 0)) > 0) {
msgSize += bytesReceived;
if (msgSize > maxSizeOutData + 1)
break;
}
// no data received
if (bytesReceived == -1) {
cerr << "Error in recv(). BytesReceived = -1" << endl;
}
close(clientSocket);
}
}
}

How to create a private message, change user_name function and channel message in winsock C++?

Like the title, I'm creating a simple chat app with Console Server and MFC Client. But now I have to create a change username function, private message func and send message in channel but I don't know how, I'm using select() to handle multiple clients with one thread. Here is my Server code, please help me:
// Server.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <WS2tcpip.h>
#include <list>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main()
{
list<SOCKET> gameChannel;
list<SOCKET> codeChannel;
list<SOCKET> filmChannel;
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0) {
cerr << "Can't init winsock" << endl;
return 0 ;
}
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "Can not create a socket" << endl;
return 0;
}
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(listening,(sockaddr*)&hint, sizeof(hint));
listen(listening, SOMAXCONN);
fd_set master;
FD_ZERO(&master);
FD_SET(listening, &master);
SOCKET client;
while (true) {
fd_set copy = master;
int socketCount = select(0, &copy, nullptr, nullptr, nullptr);
for (int i = 0; i < socketCount; i++) {
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept new connect
client = accept(listening, nullptr, nullptr);
//add new connect to the list of connect clients
FD_SET(client, &master);
cout << "user " << client << " connected to Server" << endl;
string msg = "Welcome to server !!";
//send(client, msg.c_str(), msg.size() + 1, 0);
}
else {
//Receive msg
char buff[4096];
ZeroMemory(buff, 4096);
int byteIn = recv(sock, buff, 4096, 0);
if (byteIn <= 0) {
closesocket(sock);
FD_CLR(sock, &master);
}
else {
cout << buff << endl;
if (strcmp(buff, "NICK") == 0) {
cout << "user " << client << " change name success" << endl;
}
else if (strcmp(buff, "PRIVMSG") == 0) {
cout << "Private message" << endl;
}
//Send msg to other clients
else {
for (int i = 0; i < master.fd_count; i++) {
SOCKET outSock = master.fd_array[i];
if (outSock != listening && outSock != sock) {
send(outSock, buff, byteIn, 0);
}
}
}
}
}
}
}
WSACleanup();
}
You can copy this code to visual studio and run it, for clients you can use PuTTY, IP HOST is 127.0.0.1 and Port is 54000.
Thank you !!
One more question based on that server code, how can I get clients info like port or IP of connected clients ?
Thanks.

Clients unable to connect after server shutdown and restart

I have a problem with my C++ networking code(a test server that receives strings and displays it). Occasionally, when I turn off my server(Ctrl C) and then restart it, clients fail to connect to it. If I wait for around a minute and try connecting with a client again, it works perfect. Doing a ps -A | grep my_server I don't find the process running. However, if I'd try to connect in about 2 minutes it would work just fine.
I find this rather strange.
I'm used to a slightly similar problem in Python, where I have trouble connecting to a port after pressing Ctrl+C. In that case, the process might still be running and I'd have to manually kill the process and try connecting again(and it would work just fine then).
Is there any code that you'd like me to paste in particular? I'm accepting the connections as follows :-
NetworkManager* start_listening(char* host, int port) {
keep_running = true;
signal(SIGINT, signal_handler);
int listenfd, connfd, n;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
pid_t pid;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
#ifdef DEBUG
std::cout << "[+] Starting to listen at port " << port << std::endl;
#endif
#ifdef DEBUG
std::cout << "[+] Binding to port" << std::endl;
#endif
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
#ifdef DEBUG
std::cout << "[+] Starting to listen" << std::endl;
#endif
listen(listenfd, 1024);
clilen = sizeof(cliaddr);
while ( keep_running ) {
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
#ifdef DEBUG
if ( connfd == -1 ) {
std::cout << "Yikes got an error with errno = " << errno << std::endl;
}
sockaddr_in* pV4Addr = (struct sockaddr_in*)&cliaddr;
int ipAddr = pV4Addr->sin_addr.s_addr;
char str[20];
inet_ntop(AF_INET, &ipAddr, str, 20);
std::cout << "[+] Incoming connection from " << str << std::endl;
std::cout << "[+] Using socket " << connfd << std::endl;
#endif
if ( (pid=fork()) == 0 ) {
close(listenfd);
NetworkManager *nm = new NetworkManager(connfd);
return nm;
} else {
close(connfd);
}
}
if (!keep_running) {
// #TODO kill all children
#ifdef DEBUG
std::cout << "[+] Killing server" << std::endl;
#endif
exit(0);
}
return 0;
}
The problem is that you're not checking your return values. For example, to bind. Which could be failing. For example, because you aren't using REUSEADDR to allow binding to a port which was recently in use. There's a timeout on these things, and that was a dead giveaway when you mentioned that it works again after two minutes. But really, check your return values--this is C after all!

C++ Socket Connection automatically establishing?

I am currently programming a C++ module that creates a socket server thread, which polls the accept() function every 1ms. I have a test module that spoofs a client connection that is also running. The test module initiates the creation of the server thread. After the thread is created and verified to be running, the client runs the connect() command as a test. My code states that a connection was established, returning a 0 on the connect command. However, the accept() running in my server thread never receives the connection.
The server is bound to accepting any IP:50000, and the client is not bound, but has 127.0.0.1:50000 set as its destination. Is my Linux environment automatically accepting this connection?
Here is the code for my server's socket:
int nSocket;
int nOn = 1;
int nControl;
struct sockaddr_in sServerAddress;
nSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(nSocket < 0)
{
std::cout << "Failed to create socket\n";
}
if(setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, &nOn, sizeof(int)) < 0)
{
std::cout << "failed to set socket option\n";
}
nControl = fcntl(nSocket, F_GETFL);
if(fcntl(nSocket, F_SETFL, O_NONBLOCK | nControl) < 0)
{
std::cout << "set not blocking failed\n";
}
memset(&sServerAddress, 0x00, sizeof(struct sockaddr_in));
sServerAddress.sin_family = AF_INET;
sServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
sServerAddress.sin_port = htons(mtListenPort);
if(bind(nSocket, (struct sockaddr*)&sServerAddress, sizeof(struct sockaddr_in)) < 0)
{
std::cout << errno << "bind failed\n";
}
if(listen(nSocket, MAXPENDING) < 0)
{
std::cout << "listen failed\n";
}
Here is the code for my test client's socket:
int nSocket;
nSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(nSocket < 0)
{
std::cout << "Failed to create socket\n";
}
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
inet_aton(LOCAL_HOST, &serverAddress.sin_addr);
serverAddress.sin_port = htons(LISTEN_PORT00);
char msg[] = "Hello World.";
usleep(10000);
if (connect(nSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
{
std::cout << errno << "Could not connect to the server.\n";
}
usleep(10000);
if (sendto(nSocket, msg, strlen(msg), 0, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
{
std::cout << errno << "Could not send data to the server.\n";
}
Here is a small part of the thread that runs the accept code.
while(mbListening)
{
nMessengerSocket = accept(mnSocket, (struct sockaddr*)&sClientAddr, &tClientAddrLength);
if(nMessengerSocket >= 0)
{
std::cout << "Accepted connection from " << inet_ntoa(sClientAddr.sin_addr) << std::endl;
mnConnections++;
mbListening = false;
}
mThreadRunningTime++;
usleep(1000);
}
Make sure tClientAddrLength is initialized to sizeof sClientAddr before calling accept(). That is a common error.
Don't silently ignore errors. Examine the error code in errno because it tells you what went wrong.
Are you using sendto? That's for UDP... Use send.
Also, check if the port is free:
telnet localhost 50000
netstat -a

C++ strange socket data

Hey guys, here is my code.
int main() {
char buffer[BUFSIZE];
// define our address structure, stores our port
// and our ip address, and the socket type, etc..
struct sockaddr_in addrinfo;
addrinfo.sin_family = AF_INET;
addrinfo.sin_port = htons(PORT);
addrinfo.sin_addr.s_addr = INADDR_ANY;
// create our socket.
int sock;
if ( (sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) {
cout << "Error in creating the socket.";
}
// bind our socket to the actual adress we want
if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) {
cout << "Error in binding.";
}
// open the socket up for listening
if (listen(sock, 5) != 0) {
cout << "Error in opening listener.";
}
cout << "Waiting for connections...." << endl;
char *msg = "Success! You are connected.\r\n";
// continuously accept new connections.. but no multithreading.. yet
while(1) {
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof(client_addr);
if(int client = accept(sock, (struct sockaddr*)&client_addr, &sin_size)) {
cout << "Recived new connection from " << inet_ntoa(client_addr.sin_addr) << endl;
send(client, msg, strlen(msg), 0);
while(1) {
send(client, buffer, recv(client, buffer, BUFSIZE, 0), 0);
cout << buffer << endl;
strcpy(buffer, "");
}
} else {
cout << "Error in accepting new connection." << endl;
}
}
close(sock);
return 0;
}
Now, I'm very new to sockets, Im just sort of trying to get a feel for them but I do have some experience with sockets in PHP. I'm using telnet via putty on my linux machine to test this, I don't know if thats causing any issues but the server is outputting some strange characters and I don't know why. I think it has something to do with the buffer, but I'm not really sure. I can send things like "hi" to the server via telnet and it outputs them just fine and sends them back to me but when I send things like "hoobla" it starts the funky character stuff. Any suggestions would be helpful!
Thanks in advance!
You're getting rubbish printed out because recv does not null-terminate your buffer.
The important section in the below code is:
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0); // <<-- Nice to have.
send(client, buffer, num, 0);
buffer[num] = '\0'; // <<-- Really important bit!
if (buffer[num-1] == '\n') // <<-- Nice to have.
buffer[num-1] = '\0'; // <<-- Nice to have.
cout << buffer << endl;
which will properly terminate your buffer before trying to print it, as well as remove the trailing newline if present (and allow the client to distinguish between input and echoed lines).
This one (a complete program) works a little better:
using namespace std;
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUFSIZE 1000
#define PORT 1234
int main() {
char buffer[BUFSIZE];
// define our address structure, stores our port
// and our ip address, and the socket type, etc..
struct sockaddr_in addrinfo;
addrinfo.sin_family = AF_INET;
addrinfo.sin_port = htons(PORT);
addrinfo.sin_addr.s_addr = INADDR_ANY;
// create our socket.
int sock;
if ( (sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) {
cout << "Error in creating the socket.";
return -1;
}
// bind our socket to the actual adress we want
if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) {
cout << "Error in binding.";
return -1;
}
// open the socket up for listening
if (listen(sock, 5) != 0) {
cout << "Error in opening listener.";
return -1;
}
char *msg = "Success! You are connected.\r\n";
// continuously accept new connections.. but no multithreading.. yet
while(1) {
cout << "Waiting for connections...." << endl;
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof(client_addr);
if(int client =
accept(sock, (struct sockaddr*)&client_addr, &sin_size))
{
cout << "Recieved new connection from "
<< inet_ntoa(client_addr.sin_addr) << endl;
send(client, msg, strlen(msg), 0);
while(1) {
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0);
send(client, buffer, num, 0);
buffer[num] = '\0';
if (buffer[num-1] == '\n')
buffer[num-1] = '\0';
cout << buffer << endl;
strcpy(buffer, "");
}
} else {
cout << "Error in accepting new connection." << endl;
}
}
close(sock);
return 0;
}
On the client side:
$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Success! You are connected.
hello
>> hello
my name is pax
>> my name is pax
and you?
>> and you?
<CTRL-D>
Connection closed by foreign host.
and, on the server side:
$ ./testprog
Waiting for connections....
Recived new connection from 127.0.0.1
hello
my name is pax
and you?
Waiting for connections....
The problem is that buffer is not guaranteed to contain a string-terminating null character. Add the line buffer[BUFSIZE-1] = '\0' just before your cout << buffer.
Even better, actually record how many bytes were received, and use that information to determine if you overran your buffer.