UDP socket in cpp loops for ever - c++

I had a code that implemented several threads in c++ and it worked fine. One of those threads is a UDP server that receives messages from a UDP client. So for so good.
Now I wanted to implement a TCP server on a different thread so both a UDP client and a TCP client would be able to send messages to its proper server (they are running on different ports). After doing this, the UDP server would go nuts ... (I really do not know how to explain nuts). Please, try to follow me:
Minimal Code:
// How to compile using mysql.h
// g++ -o aserver aserver.cpp $(mysql_config --libs) -lpthread
//
//// to operate with I/O functions
#include <iostream>
#include <fstream>
// to operate with strings
#include <string>
// to operate with string streams
#include <sstream>
// to opereta with time
#include <time.h>
// to operate with directories
#include <dirent.h>
// to operate with sleep function
#include <unistd.h>
// to operate with threads
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
// to operate with sockets
#include <sys/socket.h>
#include <sys/types.h>
// Defines the structure of the socket
#include <netinet/in.h>
// Uses memset to clear the structure
#include <string.h>
#include <cerrno>
using namespace std;
// **************************************************************
// * GLOBAL VARIABLES *
// **************************************************************
int logto_id;
int udp_port;
int tcp_port;
int sock;
const int success = 0;
const int general_error = -1;
const string general_error_str = "Error";
void logto(string text, int debug_id) {
int append_status;
switch (debug_id) {
case 1:
cout << text + "\n";
break;
case 2:
break;
case 3:
break;
default:
cout << "";
}
}
int create_udp_socket() {
// UDP Socket Variables
unsigned int serverlen;
sockaddr_in udpServer;
int bind_status = 0;
string function_name="create_udp_socket: ";
/* Create the UDP socket */
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) {
cout << function_name + "Could not create UDP socket...\n";
return general_error;
}
/* Construct the server sockaddr_in structure */
memset(&udpServer, 0, sizeof(udpServer)); /* Clear struct */
udpServer.sin_family = AF_INET; /* Internet/IP */
udpServer.sin_addr.s_addr = htonl(INADDR_ANY); /* Any IP address */
udpServer.sin_port = htons(udp_port); /* server port */
/* Bind the socket */
serverlen = sizeof(udpServer);
bind_status= bind(sock, (struct sockaddr *) &udpServer, serverlen);
if (bind_status < 0) {
cout << function_name + "Could not bind UDP socket...\n";
return general_error;
} else {
cout << function_name + "UDP Socket created and binded...\n";
return success;
}
}
int create_tcp_socket() {
// TCP Socket Variables
unsigned int serverlen;
sockaddr_in tcpServer;
int bind_status = 0;
int listen_status = 0;
string function_name="create_tcp_socket: ";
/* Create the TCP socket */
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
cout << function_name + "Could not create TCP socket...\n";
return general_error;
}
/* Construct the server sockaddr_in structure */
memset(&tcpServer, 0, sizeof(tcpServer)); /* Clear struct */
tcpServer.sin_family = AF_INET; /* Internet/IP */
tcpServer.sin_addr.s_addr = htonl(INADDR_ANY); /* Any IP address */
tcpServer.sin_port = htons(tcp_port); /* server port */
/* Bind the socket */
serverlen = sizeof(tcpServer);
bind_status = bind(sock, (struct sockaddr *) &tcpServer, serverlen);
if (bind_status < 0) {
cout << function_name + "Could not bind TCP socket...\n";
return general_error;
} else {
cout << function_name + "TCP Socket created and binded...\n";
/* Listen */
listen_status = listen(sock,10);
if (listen_status < 0) {
cout << function_name + "Could not listen on the TCP socket...\n";
return general_error;
} else {
cout << function_name + "TCP Socket listening...\n";
return success;
}
}
}
void *thread_udp_server(void *arg) {
// **************************************************************
// * LOCAL VARIABLES *
// * we define this internal variables that before were Global *
// **************************************************************
/* here we store the SQL INSERT query */
string node_query;
/* here we find the data to build the query
* this variable is always passed by reference to all the functions
*/
string node_line;
/* UDP Socket related variables */
char udp_buffer[255];
int received = 0;
unsigned int echolen, clientlen;
sockaddr_in udpClient;
// Name of thread
string thread_name = (char*)arg;
// We start the whole thing ...
if (create_udp_socket()==success) {
/* Endless loop */
//for(;;) {
while(1) {
logto(udp_buffer,logto_id);
/* Receive a message from the client */
clientlen = sizeof(udpClient);
received = recvfrom(sock, udp_buffer, 255, 0, (struct sockaddr *) &udpClient, &clientlen);
if (received < 0) {
logto(thread_name + " Failed to receive message",logto_id);
std::cout << "Something went wrong! errno " << errno << ": ";
std::cout << strerror(errno) << std::endl;
} else {
logto("\n---------\n" + thread_name,logto_id);
/* We now copy the content of the buffer into 'node_line' */
node_line=udp_buffer;
logto(thread_name + node_line,logto_id);
}
}
} else {
logto(thread_name + " Could not bring up UDP socket...",logto_id);
std::cout << "Something went wrong! errno " << errno << ": ";
std::cout << strerror(errno) << std::endl;
return NULL;
}
}
void *thread_tcp_server(void *arg) {
// **************************************************************
// * LOCAL VARIABLES *
// * we define this internal variables that before were Global *
// **************************************************************
/* here we store the SQL INSERT query */
string node_query;
/* here we find the data to build the query
* this variable is always passed by reference to all the functions
*/
string node_line;
/* TCP Socket related variables */
char tcp_buffer[255];
int recTcp = 0;
unsigned int echolen, clientlen;
sockaddr_in tcpClient;
// Name of thread
string thread_name = (char*)arg;
// We start the whole thing ...
if (create_tcp_socket()==success) {
/* Endless loop */
for(;;) {
logto(tcp_buffer,logto_id);
/* Receive a message from the client */
clientlen = sizeof(tcpClient);
recTcp = accept(sock, (struct sockaddr *) &tcpClient, &clientlen);
if (recTcp < 0) {
logto(thread_name + " Failed to receive message",logto_id);
std::cout << "Something went wrong! errno " << errno << ": ";
std::cout << strerror(errno) << std::endl;
} else {
logto("\n---------\n" + thread_name,logto_id);
/* We now copy the content of the buffer into 'node_line' */
node_line=tcp_buffer;
logto(thread_name + node_line,logto_id);
}
}
} else {
logto(thread_name + " Could not bring up TCP socket...",logto_id);
std::cout << "Something went wrong! errno " << errno << ": ";
std::cout << strerror(errno) << std::endl;
return NULL;
}
}
// -----------------
// - main function -
// -----------------
int main () {
// **************************************************************
// * VARIABLES *
// **************************************************************
// Labels of the threads
string label_udp = "UDP_thread";
string label_tcp = "TCP_thread";
// We define the threads...
pthread_t udp_server_id=20;
pthread_t tcp_server_id=50;
udp_port = 10101;
tcp_port = 10102;
logto_id = 1;
// **************************************************************
// * START *
// **************************************************************
if ( pthread_create( &udp_server_id, NULL, thread_udp_server, (void*) label_udp.c_str()) ) {
logto("Error creating thread_udp_server...",logto_id);
return general_error;
}
if ( pthread_create( &tcp_server_id, NULL, thread_tcp_server, (void*) label_tcp.c_str()) ) {
logto("Error creating thread_tcp_server...",logto_id);
return general_error;
}
if ( pthread_join ( udp_server_id, NULL ) ) {
logto("UDP_thread couldn't join the main thread...",logto_id);
return general_error;
}
if ( pthread_join ( tcp_server_id, NULL ) ) {
logto("TCP_thread couldn't join the main thread...",logto_id);
return general_error;
}
}
After starting the program, the errno are the following, depending on which socket were brought up:
TCP ok!:
./aserver
create_tcp_socket: TCP Socket created and binded...
create_tcp_socket: TCP Socket listening...
create_udp_socket: Could not bind UDP socket...
UDP_thread Could not bring up UDP socket...
Something went wrong! errno 22: Invalid argument
UDP ok!:
./aserver
create_udp_socket: UDP Socket created and binded...
create_tcp_socket: TCP Socket created and binded...
create_tcp_socket: Could not listen on the TCP socket...
TCP_thread Could not bring up TCP socket...
Something went wrong! errno 95: Operation not supported
There is also a third case, where the UDP is brough up (the TCP socket remains down) and for some reasing, I get these messages scrolling all along the window...
./aserver
create_tcp_socket: Could not bind TCP socket...
TCP_thread Could not bring up TCP socket...
Something went wrong! errno create_udp_socket: UDP Socket created and binded...
22: UDP_thread Failed to receive message
Something went wrong! errno 107: Transport endpoint is not connectedInvalid argument
UDP_thread Failed to receive message
Something went wrong! errno 107: Transport endpoint is not connected
UDP_thread Failed to receive message
Something went wrong! errno 107: Transport endpoint is not connected
UDP_thread Failed to receive message
Something went wrong! errno 107: Transport endpoint is not connected
However, if I comment out either thread (TCP or UDP) the remaining one works ok ...
Bottom line: I cannot get both threads (UDP and TCP) to live together at the same time...
Could anyone give me a hint on this. I'm really lost on why both threads at the same time break my application ... :-(
Thanks in advance,
Lucas

It looks like you are using the same, global socket for the two threads.
int sock;
If the create_udp_socket function runs first, the socket that it creates will get overwritten by create_tcp_socket, and vice versa.
Possible solutions, either use two global sockets:
int tcp_sock;
int udp_sock;
or (better) make the create_xxx_socket functions return the sockets directly to the callers, avoiding the use of global variables.
Here's an example of the latter (error handling omitted for clarity).
int create_tcp_socket()
{
int sock;
/* Create the TCP socket */
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
/* Bind and listen... */
return sock;
}
The TCP thread would call create_tcp_socket like this.
void *thread_tcp_server(void *arg)
{
/* ... */
int sock = create_tcp_socket();
if(sock < 0)
{
logto(thread_name + " Could not bring up TCP socket...", logto_id);
return NULL;
}
/* Socket created, start accept'ing connections */
}
Global variables are bad for a number of reasons.
In multithreaded code particularly, keeping data (sock in this case) private means there is less doubt about ownership.
The code might make assumptions about who owns a global variable, but as programs grow in size this becomes impossible to manage in practice.
Contrast this with returning sock from one of the creation methods; It is easy to see that initially, sock is owned by the creation method. When the creation method returns, ownership of the socket is passed to the caller. There is never more than one function or thread with access to the socket, so concurrent access to the socket is never an issue.
Knowing who owns the data also makes it easier to release or deallocate resources when they are no longer needed. In this case, if a server thread were to exit, it - being the owner of the socket - would be responsible for closing it on its way out. And it can do so safely because no-one else could be using the socket.

Related

UDP signal from Matlab to C++

I want to send random trigger signals (A and B) from Matlab to a C++ Code. The point where I stuck now is, that whenever I am not sending this trigger signal/message, the C++ Code keeps waiting for it and doesn't continue its process.
How can I make the C++ Code keep running (to collect data) without waiting for the next trigger message. Because now only once it receives the message (UDP transfers trigger signal) it gives me the specific outcome.
----------- BEGIN MATLAB CODE ---------------------
send_trigger_signal = instrfind('Type', 'udp', 'LocalHost', '127.0.0.1','RemoteHost', '192.168.0.100', 'RemotePort', 8888, 'LocalPort', 8844, 'Tag', '');
% Create the udp object if it does not exist otherwise use the object that was found.
if isempty(send_trigger_signal)
send_trigger_signal = udp('127.0.0.1', 'RemotePort', 8888, 'LocalPort', 8844);
else
fclose(send_trigger_signal);
send_trigger_signal = send_trigger_signal(1);
end
send_trigger_signal.DatagramTerminateMode='off';
send_trigger_signal.Timeout=0.0001;
send_trigger_signal.Timerperiod=0.01;
%send_trigger_signal.
% Connect to instrument object, send_trigger_signal.
fopen(send_trigger_signal);
% Communicating with instrument object, send_trigger_signal.
on_trigger_command=typecast(swapbytes(uint16([1 1 0 0])),'uint8'); %trigger on
off_trigger_command=typecast(swapbytes(uint16([0 0 0 0])),'uint8'); %trigger off
while(true)
for i=1:1
fprintf(send_trigger_signal, 'A');
WaitSecs(5);
end
end
fclose(send_trigger_signal);
send_trigger_signal=instrfindall;
delete(send_trigger_signal);
instrfindall;
----------- END MATLAB CODE ---------------------
This is the C++ code which should receive the random trigger signals from Matlab (A and B), while collecting gyro data between those signals.
To test it here the message is send every 5sec. The problem is that I cannot collect the gyro data in within those 5sec. The UDP communication is interrupting the data collection - because it is waiting those 5sec.
----------- START C++ CODE ---------------------
#include <iostream>
#include <winsock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib") // Winsock Library
#pragma warning(disable:4996)
#define BUFLEN 512
#define PORT 8888
int receiver(void)
{
int value = 5;
system("title UDP Server");
sockaddr_in server, client;
// initialise winsock
WSADATA wsa;
printf("Initialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code: %d", WSAGetLastError());
exit(0);
}
printf("Initialised.\n");
// create a socket
SOCKET server_socket;
if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
printf("Could not create socket: %d", WSAGetLastError());
}
printf("Socket created.\n");
// prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
// bind
if (bind(server_socket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code: %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done.");
while (true)
{
printf("Waiting for data...");
fflush(stdout);
char message[BUFLEN] = {};
// try to receive some data, this is a blocking call
int message_len;
int slen = sizeof(sockaddr_in);
if (message_len = recvfrom(server_socket, message, BUFLEN, 0, (sockaddr*)&client, &slen) == SOCKET_ERROR)
{
printf(message);
printf("recvfrom() failed with error code: %d", WSAGetLastError());
exit(0);
}
if (message[0] == 'A')
{
value = 6;
break;
}
if (message[0] == 'B')
{
value = 7;
break;
}
// print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
printf("Data: %s\n", message);
return 0;
}
closesocket(server_socket);
WSACleanup();
return value;
}
int main()
{
while (true)
{
// Reading some gyro data here
// Listening UDP
receiver();
}
return 0;
}
----------- END C++ CODE ---------------------
With a few structural tweaks:
Using non-blocking socket.
You don't want to restart winsock and rebind the socket every time you read from it, so that's spun off to different functions (an RAII wrapper class in the case of winsock).
C-style IO replaced with C++ IO.
exit(0) means the program succeeded, but was used in many cases where failure occurred. Consistently using exit(EXIT_FAILURE);. Might be worth throwing an exception, but it's annoying to get the error code into the exception text.
Removed some of the output because it would be spammed out now that the receive function can immediately return .
Your program could look something like this:
#include <iostream>
#include <winsock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib") // Winsock Library
#pragma warning(disable:4996)
// using modern C++ constants
constexpr int BUFLEN = 512;
constexpr int PORT = 8888;
//RAII wrapper to make sure winsock is created and disposed of responsibly
struct winsock_RAII
{
winsock_RAII()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
std::cerr << "Failed to initialize winsock. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
}
~winsock_RAII()
{
WSACleanup(); // what are we gonna do if it fails? Not much we can do.
}
};
//socket initialization
SOCKET init_sock()
{
SOCKET server_socket;
if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
std::cerr << "Failed to get socket. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
u_long iMode = 1;
//setr socket non-blocking
if (ioctlsocket(server_socket, FIONBIO, &iMode) != NO_ERROR)
{
std::cerr << "Failed to get socket. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
// prepare the sockaddr_in structure
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
// bind
if (bind(server_socket, (sockaddr*) &server, sizeof(server)) == SOCKET_ERROR)
{
std::cerr << "Bind failed. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
return server_socket;
}
// read from socket
int receiver(SOCKET server_socket)
{
// try to receive some data, this is a non-blocking call
int slen = sizeof(sockaddr_in);
sockaddr_in client;
char message[BUFLEN + 1]; // no need to clear the whole buffer. We'll know
// exactly where to put the null thanks to message_len
// +1 makes sure we have room for terminator
int message_len = recvfrom(server_socket, message,
BUFLEN,
0,
(sockaddr*) &client,
&slen);
int value = 5;
if (message_len != SOCKET_ERROR)
{
message[message_len] = '\0'; // place terrminator
if (message[0] == 'A')
{
value = 6;
}
if (message[0] == 'B')
{
value = 7;
}
// print details of the client/peer and the data received
std::cout << "Received packet from " << inet_ntoa(client.sin_addr) << ':' << ntohs(client.sin_port) << '\n'
<< "Data: " << message << '\n';
}
else if (WSAGetLastError() != WSAEWOULDBLOCK)
{
// printf(message); no point to printing message. There isn't one
std::cerr << "recvfrom() failed . Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
return value;
}
int main()
{
winsock_RAII winsock; // scoped winsock initializer
SOCKET server_socket = init_sock();
while (true)
{
// Reading some gyro data here
receiver(server_socket);
}
closesocket(server_socket);
return 0;
}
You might want to use select with a short timeout to throttle the loop because it can be a serious and unnecessary CPU-eater if the gyro reading code is also quick.

select() not getting more than 1 action

I made a server socket in C++ for Unix (TCP), that accepted only one client socket. Today, I attempted to make it accept multiple ones. For some reason, it ends up only accepting 1, and it's not receiving messages sent by the client that IS able to connect. I believe that the select function isn't working properly. FYI: I'm new to socket programming, so please understand if it's a stupid mistake.
Here's the code:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#define PORT 8080
#define MAXCLIENTS 30
int main()
{
//create a socket
int listening = socket(AF_INET, SOCK_STREAM, 0); //(returns int) - makes socket (returns what socket it is in terms of an int)
if(listening < 0) //check if we were able to make a socket!
{
std::cerr << "Can't create socket!" << std::endl;
return -1;
}
//bind the socket to an IP/Port
sockaddr_in hint{}; // This creates a structure for the ipv4 info of the socket.
hint.sin_family = AF_INET; //set the family to ipv4
hint.sin_port = htons(PORT); //set the port to the macro set above (use host-to-network-short to conver the int to the port)
hint.sin_addr.s_addr = INADDR_ANY; //set the ip to any address
if(bind(listening, (sockaddr*)&hint, sizeof(hint)) < 0) //attempt to bind socket (inticated by what number the `listening` socket is) to ip/port
{
std::cerr << "Can't bind to IP/Port" << std::endl;
return -1;
}
//mark the socket for listening
if(listen(listening, MAXCLIENTS) < 0 /*SOMAXCONN = maximum amount of connections, defined by sys/socket.h*/) //attempt to listen on the socket number indicated by `listening`
{
std::cerr << "Can't listen on the socket!" << std::endl;
return -1;
}
//FD_CLR() = Remove 1 from set
//FD_SET() = Add to set
//FD_ZERO() = Remove everything from set
//FD_ISSET() = Check if something is part of a set
fd_set master; //define the set
int max_sd;
int client_socks[MAXCLIENTS]{};
while (true)
{
FD_ZERO(&master); //make sure it's cleared
FD_SET(listening, &master); //add the listening socket (server) to the set
max_sd = listening; //max socket descriptor set to the listening socket (need this for the select func)
for (int i = 0; i < MAXCLIENTS; i++) {
if (client_socks[i] > 0) //make sure the particular socket exists
{
FD_SET(client_socks[i], &master); //add it to the set
}
if (client_socks[i] > max_sd) //if the socket is greater than our current maximum socket descriptor
{
max_sd = client_socks[i];
}
}
//wait for some action on any socket within the master fd (this will set the master fd_set to be equal to whatever socket had some action on it)
int activity = select(max_sd + 1, &master, nullptr, nullptr, nullptr);
if (activity < 0) //error!
{
std::cerr << "Error while trying to select!" << std::endl;
}
int addrlen = sizeof(hint);
if (FD_ISSET(listening, &master)) //if the select got that there was action on the listening (server) socket - most likely, a client socket is trying to connect!
{
int client_socket;
client_socket = accept(listening, (sockaddr *) &hint, &addrlen); //accept the first client "waiting to get in"
if (client_socket < 0) {
std::cerr << "Something went wrong when trying to accept a client socket!" << std::endl;
break;
}
std::cout << "New connection: " << inet_ntoa(hint.sin_addr) << " on port " << ntohs(hint.sin_port) << std::endl;
if (send(client_socket, "Welcome to the socket party!", strlen("Welcome to the socket party!"), 0) != strlen("Welcome to the socket party!")) { //greetings!
std::cerr << "Error when sending welcome message." << std::endl; //something went wrong ;(
}
for (int i = 0; i < MAXCLIENTS; i++) //for each index, set client_sock to the address of the index of client_socks, so that we can set the value of it!
{
if(client_socks[i] == 0) //if this position is null (0)
{
client_socks[i] = client_socket;
}
}
}
//else, there was action on a client socket (most likely a message is being sent!
char buffer[2048]; //we need somewhere to store clients messages!
for (int &client_sock : client_socks) //loop through the client sockets
{
if (client_sock != 0)
{
if (FD_ISSET(client_sock, &master) == 0) //check if the select got action on the particular index in the client_socks array
{
memset(&buffer, 0, sizeof(buffer)); //make sure the buffer is clear!
if (read(client_sock, &buffer, 2048) == 0) //check if nothing was recieved from the client
{
getpeername(client_sock, (sockaddr*)&hint, (socklen_t*)&addrlen) < 0; //gets networking info, based off of which socket is passed (the if statement checks for errors). In addition, it sets the values of hint to the info from the passed socket
//print that the client disconnected
std::cout << "A client has disconnected! IP: " << inet_ntoa(hint.sin_addr) << " Port: " << ntohs(hint.sin_port) << std::endl;
close(client_sock); //close the socket
client_sock = 0; //set its value in the array to 0, so that we can reuse it!
}
//else, we got message from the client
for (int &socket : client_socks)
//if (socket != client_sock)
send(socket , buffer , strlen(buffer) , 0 );
}
}
}
return 0;
}
}
Your client_socks variable must be initialised, as Igor said - just append braces: int client_socks[MAXCLIENTS]{};.
Then your for (int &client_sock : client_socks) loop doesn't ignore 0 values (which you obviously want to be a sentinel given "if(client_socks[i] == 0) //if this position is null (0)"). Inside that loop, add "if (client_sock[i] == 0) continue;. Because you try to read` from descriptor 0, it will block waiting for keyboard input.
Further, if you wanted your code to be robust, you would make the listening socket non-blocking, as it's possible for that socket to select readable, but by the time your application goes to accept from it, the client connection attempt has already been dropped: then you'd block waiting to accept another client connection attempt that might never come, and not be servicing existing clients.

How to connect multiple clients to a single server in c++ on Windows - Visual Studio? [duplicate]

This question already has answers here:
Single TCP/IP server that handles multiple clients (in C++)?
(2 answers)
Closed 5 years ago.
I have written a server program in C++ and also a client program in C++.
Both are working fine but when if one client is communicating with the server then other client can't get connected to the same server. If suppose when I close the client 1 then also my 2nd client can't connect to the server. I have started my Server with multiple threads to connect to multiple clients but only one client is connecting.
MY server Program:
#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include <thread>
#pragma comment(lib,"ws2_32.lib")
static const int num_of_threads = 2;
void client_disconnected(SOCKET Socket);
void start_server()
{
WSADATA WsaDat;
if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
{
std::cout<<"WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
}
SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Socket==INVALID_SOCKET)
{
std::cout<<"Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
}
SOCKADDR_IN serverInf;
serverInf.sin_family=AF_INET;
serverInf.sin_addr.s_addr=INADDR_ANY;
serverInf.sin_port=htons(8888);
if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
{
std::cout<<"Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
}
listen(Socket,3);
SOCKET TempSock=SOCKET_ERROR;
while(TempSock==SOCKET_ERROR)
{
std::cout<<"Waiting for incoming connections...\r\n";
Sleep(5000);
TempSock=accept(Socket,NULL,NULL);
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);
Socket=TempSock;
std::cout<<"Client connected!\r\n\r\n";
// Main loop
for(;;)
{
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0)
{
client_disconnected(Socket);
break;
}
char *szMessage="Welcome to the server!\r\n";
send(Socket,szMessage,strlen(szMessage),0);
Sleep(2000);
}
}
void client_disconnected(SOCKET Socket)
{
std::cout<<"Client disconnected!\r\n";
// Shutdown our socket
shutdown(Socket,SD_SEND);
// Close our socket entirely
closesocket(Socket);
WSACleanup();
}
int main()
{
//starting multiple threads for invoking server
std::thread threads[num_of_threads];
//This statement will launch multiple threads in loop
for (int i = 0; i < num_of_threads; ++i) {
threads[i] = std::thread(start_server);
Sleep(2000);
}
for (int i = 0; i < num_of_threads; ++i) {
threads[i].join();
}
return 0;
}
My Client Program:
#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include "client.h"
#pragma comment(lib,"ws2_32.lib")
void MultipleClient :: receiveToClient(void*data)
{
WSADATA WsaDat;
if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
{
std::cout<<"Winsock error - Winsock initialization failed\r\n";
WSACleanup();
system("PAUSE");
}
// Create our socket
SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Socket==INVALID_SOCKET)
{
std::cout<<"Winsock error - Socket creation Failed!\r\n";
WSACleanup();
system("PAUSE");
}
// Resolve IP address for hostname
struct hostent *host;
if((host=gethostbyname("localhost"))==NULL)
{
std::cout<<"Failed to resolve hostname.\r\n";
WSACleanup();
system("PAUSE");
}
// Setup our socket address structure
SOCKADDR_IN SockAddr;
SockAddr.sin_port=htons(8888);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);
// Attempt to connect to server
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0)
{
std::cout<<"Failed to establish connection with server\r\n";
WSACleanup();
system("PAUSE");
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);
// Main loop
for(;;)
{
// Display message from server
char buffer[1000];
memset(buffer,0,999);
int inDataLength=recv(Socket,buffer,1000,0);
std::cout<<buffer;
//end client when server is disconnected
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0)
{
std::cout<<"Winsock error code: "<<nError<<"\r\n";
std::cout<<"Server disconnected!\r\n";
// Shutdown our socket
shutdown(Socket,SD_SEND);
// Close our socket entirely
closesocket(Socket);
break;
}
Sleep(2000);
}
WSACleanup();
system("PAUSE");
}
class Client{
public:
static unsigned int __stdcall receiveMessageThread(void *p_this)
{
MultipleClient* mc = static_cast<MultipleClient*>(p_this);
mc-> receiveToClient(p_this); // Non-static member function!
return 0;
}
void startThread()
{
HANDLE myhandleA;
myhandleA = (HANDLE)_beginthreadex(0,0,&Client::receiveMessageThread,this,0, 0);
WaitForSingleObject(myhandleA, INFINITE);
}
};
int main(void)
{
Client *c = new Client;
c->startThread();
return 0;
}
Please help me how to make multiple clients to connect with a single server. A sample code will be very useful(sorry for asking).
Your way of distributing work among threads is wrong.
You want one thread to open the listening socket and wait for incoming connections there. Note that you cannot have more than one listening socket per port, so you definitely don't want multiple threads trying to listen on the same port simultaneously.
If a connection comes in, accept will give you a new socket object. You still have the original listening socket, which waits for new connections, but you also have a second socket now with an already established connection to a client.
Now you can split the work: Have one thread go back to calling listen on the original socket and await new connections, while the other thread grabs the new socket and performs the necessary I/O to interact with the client.
In this simple scheme, you will always have one thread per client connection plus an additional thread for the listening socket. Since all of these threads will spent a large amount of time just waiting for network I/O to complete, you can use asynchronous I/O to share the workload between fewer (or even a single) threads, but that is slightly more complex to pull off, so I'd suggest you leave that for a second draft.
Using threads. Use one thread for socket server to accept all the Request Connections that coming from clients.
Each thread will have the socket that was assigned by method accept something like this:
Server. This method (run) is running under a new thread. I don't show the method connectionRequest to be practical but keep in mind that this method create the new thread that will attend the Remote End Point.
void SocketServer::run()
{
int err = 0;
err = initSocketServer();
//Fallo el inicio de socket server.
if (err != NO_ERROR)
{
stringstream out;
out << "There was a problem to bind Native Port: " << _port;
log->writeError(out.str());
bKeepRunning = false;
}
else
bKeepRunning = true;
stringstream out;
out << "Native Port stablished on port: " << _port;
log->writeInfo(out.str());
while (bKeepRunning)
{
stringstream out;
SOCKET socket;
socket = accept(server, NULL,NULL);
if (bKeepRunning)
{
bool reuseadd = true;
bool keepAlive = true;
setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseadd, sizeof(bool));
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keepAlive, sizeof(bool));
//This method will create a new Thread wihc recives the socket.
connectionRequest(socket);
// It is ready to accept the nexto connection...
}
}
serverStoped();
}
Attending the Remote End Point. The new thread that has been created by Connection request, must be attendig the Remote End Point to recive a send. Here is a sample on how the execute the other
It isn't my intention to show how to send and recive data by sockets.
void SocketClient::run()
{
stringstream out;
bKeepRunning = true;
bool wasClosed = false;
int error = 0;
error = 0;
do
{
if(bSocketSet)
log->writeDebug(_dlevel,"Socket Previamente asignado, No hay conexion");
else
log->writeDebug(_dlevel, "SIN Socket Previamente asignado, Se conectara");
if(!bSocketSet) //If the socket has not been set
bConnected = openConnection();
if (bConnected)
{
if (!bSocketSet) //If the socket has not been set
{
out.str("");
out.clear();
out << "Connected to Server [" << _host << ":" << _port << "]";
log->writeInfo(out.str());
}
//The readMessage will performed a loop to read data an report.
error = readMessage(&wasClosed);
if ((error != 0 && bKeepRunning) || wasClosed)
{
out.str("");
out.clear();
out << "There was an error on reading data. The connection colud be closed.";
log->writeError(out.str());
//if(!wasClosed)
//closeConnection();
bConnected = false;
}
} // if (bConnected)
else
{
if (!bSocketSet)
{
out.str("");
out.clear();
out << "It was not possible to connect to Server [" << _host << ":" << _port << "]";
log->writeError(out.str());
waitForResume(15000); //Wait for 15 second to try to reconect
}
} //Else Not Connected
} while (bKeepRunning && !bSocketSet); //do while The socket is not a Socket set by SocketServer
if (bConnected)
closeConnection();
}//SocketClient::run()
By each Thread that attend each Remote End Point you can send a recive many data as the protocol sets it but at the end you must close the connection to release the socket to be used as soon as possible by OS.

TCP failing to reconnect to server from client

I am writing a TCP communication library for my codebase. I have implemented this library with an acceptor class (to be run on server), and connector class (to be run on client) and a stream class (handle sending and receiving data).
For the most part, everything works. The one problem I have is that if I disconnect the ethernet wire between client and server, and attempt to connect, I get the error that the destination was unreachable. Upon further attempts to connect, whether the ethernet cable is connected or not, I get an error that operation is in progress.
Note that if connect is called, even when reconnecting, everything works if a connection is possible.
Also, please note in my code during connect I am setting the socket option to SO_REUSEADDR, I am using SO_LINGER, and that after a failed connection I am closing all sockets.
TCPConnector class:
/** #file TCPConnector.cpp
* #brief cpp file to TCPConnector class, which encapsulates the socket mechanisms to actively
* connect to a server.
* #author Austin Small.
*/
#include "TCPConnector.h"
#include <iostream>
#include <errno.h>
/** #brief This method establishes a connection with the server (robot).
*
* #param server Server IP address.
* #param port Server port number.
* #param timeoutSec Number of seconds before timout of connect method.
*/
TCPStream* TCPConnector::connect(const char* serverIP, int port, int timeoutSec)
{
std::cout << "connect was called" << std::endl;
struct sockaddr_in address;
// Store all zeros for address struct.
memset(&address, 0, sizeof(address));
// Configure address struct.
address.sin_family = AF_INET;
address.sin_port = htons(port); // Convert from host to TCP network byte order.
inet_pton(PF_INET, serverIP, &(address.sin_addr)); // Convert IP address to network byte order.
// Create a socket. The socket signature is as follows: socket(int domain, int type, int protocol)
int sd = socket(AF_INET, SOCK_STREAM, 0);
int optval = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) == -1)
{
std::cout << "failed to set socket option" << std::endl;
}
// Set socket to terminate all communications when close is called.
struct linger so_linger;
so_linger.l_onoff = true;
so_linger.l_linger = 0;
if (setsockopt(sd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger) == -1)
{
std::cout << "failed to set socket option" << std::endl;
}
// Set socket to be non-blocking.
int arg;
arg = fcntl(sd, F_GETFL, NULL);
arg |= O_NONBLOCK;
fcntl(sd, F_SETFL, arg);
// Connect with time limit.
fd_set set;
FD_ZERO(&set); // Clear the set.
FD_SET(sd, &set); // Add our file descriptor to the set.
struct timeval timeout;
timeout.tv_sec = timeoutSec;
timeout.tv_usec = 0;
// If the connect call returns 0, then the connection was established. Otherwise,
// check if the three-way handshake is underway.
if (::connect(sd, (struct sockaddr *)&address, sizeof(address)) < 0)
{
// If the handshake is underway.
if (errno == EINPROGRESS)
{
std::cout << "handshake in progress" << std::endl;
// Designate timeout period.
int ret = select(sd + 1, NULL, &set, NULL, &timeout);
std::cout << "return value from select : " << ret << std::endl;
// Check if timeout or an error occurred.
if (ret <= 0)
{
std::cout << "return less than 0" << std::endl;
std::cout << "closing socket descriptor" << std::endl;
if (close(sd) < 0)
{
char * newerrorMessage = strerror( errno); // get string message from errn
std::string newmsg (newerrorMessage);
std::cout << newmsg << std::endl;
std::cout << "failed to close socket descriptor" << std::cout;
}
return NULL;
}
else
{
// Check if select returned 1 due to an error.
int valopt;
socklen_t len = sizeof(int);
getsockopt(sd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len);
if (valopt)
{
char * errorMessage = strerror( errno); // get string message from errn
std::string msg (errorMessage);
std::cout << msg << std::endl;
std::cout << "closing socket descriptor" << std::endl;
if (close(sd) < 0)
{
char * newerrorMessage = strerror( errno); // get string message from errn
std::string newmsg (newerrorMessage);
std::cout << newmsg << std::endl;
std::cout << "failed to close socket descriptor" << std::cout;
}
return NULL;
}
}
}
else
{
std::cout << "error but not EINPROGRESS" << std::endl;
char * errorMessage = strerror( errno); // get string message from errn
std::string msg (errorMessage);
std::cout << msg << std::endl;
if (close(sd) < 0)
{
char * newerrorMessage = strerror( errno); // get string message from errn
std::string newmsg (newerrorMessage);
std::cout << newmsg << std::endl;
std::cout << "failed to close socket descriptor" << std::cout;
}
return NULL;
}
}
// Return socket to blocking mode.
arg = fcntl(sd, F_GETFL, NULL);
arg &= (~O_NONBLOCK);
fcntl(sd, F_SETFL, arg);
// Create stream object.
return new TCPStream(sd, &address);
}
TCPStream Class:
/** #file TCPStream.cpp
* #brief cpp file to TCPStream class, which provides methods to send and receive
* data over a TCP/IP connection.
* #author Austin Small.
*/
#include "TCPStream.h"
#include <iostream>
/** #brief TCPStream class constructor.
*
* #param argsd Socket descriptor.
* #param address sockaddr_in struct.
*/
TCPStream::TCPStream(int argsd, struct sockaddr_in* address) :
sd(argsd)
{
char ip[50];
// Convert a numeric address into a text string.
// struct sockaddr_in
// {
// short sin_family;
// unsigned short sin_port;
// struct in_addr sin_addr;
// char sin_zero[8];
// };
//
inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip));
peerIP = ip;
// Convert from network byte order to host byte order.
peerPort = ntohs(address->sin_port);
}
/** #brief TCPComputerComm class destructor.
*
*/
TCPStream::~TCPStream()
{
std::cout << "closing fd" << std::endl;
if (close(sd) < 0)
{
std::cout << "file descriptor not closed successfully" << std::endl;
}
}
/** #brief Wrapper function to send data.
*
* #param buffer Pointer to first character of string.
* #param len Size of input string.
* #param timeoutSec Timeout period for write command.
*
* #return Number of bytes written, -1 if a non-timeout error occured, and -2 if a timeout occurred.
*/
ssize_t TCPStream::send(const char* buffer, size_t len, int timeoutSec)
{
// Attempt to send data with a timeout on write.
fd_set set;
FD_ZERO(&set); // Clear the set.
FD_SET(sd, &set); // Add our file descriptor to the set.
struct timeval timeout;
timeout.tv_sec = timeoutSec;
timeout.tv_usec = 0;
int ret;
ret = select(sd + 1, NULL, &set, NULL, &timeout);
// First check if an error or timeout occurred. Otherwise, call accept method.
if (ret == -1)
{
return -1;
}
else if (ret == 0)
{
return -2;
}
else
{
return write(sd, buffer, len);
}
}
/** #brief Wrapper function to receive data.
*
* #param buffer Pointer to first character of buffer to store received string.
* #param len Max number of bytes to read from file descriptor.
* #param timeoutSec Timeout period for read command.
*
* #return Number of bytes read or -1 if a non-timeout error occurred and -2 if a timeout occurred.
*/
ssize_t TCPStream::receive(char* buffer, size_t len, int timeoutSec)
{
// Attempt to send data with a timeout on write.
fd_set set;
FD_ZERO(&set); // Clear the set.
FD_SET(sd, &set); // Add our file descriptor to the set.
struct timeval timeout;
timeout.tv_sec = timeoutSec;
timeout.tv_usec = 0;
int ret;
ret = select(sd + 1, &set, NULL, NULL, &timeout);
// First check if an error or timeout occurred. Otherwise, call read method.
if (ret == -1)
{
return -1;
}
else if (ret == 0)
{
return -2;
}
else
{
//std::cout << "attempting to read" << std::endl;
return read(sd, buffer, len);
}
}
/** #brief Get peerIP address.
*
* #return peerIP address.
*/
string TCPStream::getPeerIP(void)
{
return peerIP;
}
/** #brief Get peer port.
*
* #return Peer port.
*/
int TCPStream::getPeerPort(void)
{
return peerPort;
}

C++ connect() in UNIX-socket based client program does not establish a connection to the server

I have written a simple socket server in c++ in CentOS 7.0 using the famous Berkeley socket interface. I run it, on whatever port, and it waits for the connections.
I then run my simple client program also written with c++ and send a request to
192.168.122.1 (this IP is found through executing command ip addr) but it refuses to connect. Being concerned with the firewall, I stop the httpd.service (APACHE) and do the procedure on port 80, but to no avail and I receive the error "Connection Refused".
What should I do?
** UPDATE 001 **
when I run the command netstat -l I get the following output:
.
.
tcp 0 0 0.0.0.0:9005 0.0.0.0:* LISTEN
.
.
** END OF UPDATE 001 **
Here are the outputs:
Client --> Connection Refused
Server --> [Waiting...]
Here are the codes:
CLIENT:
#include <iostream>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
namespace TCP {
class Client {
public :
static bool Connect(int argc, char *argv[]) {
int returnStatus = 0;
char* buffer[256];
if (3 != argc) {
// warn that the port MUST be specified.
fprintf(stderr, "Incorrect parameter for port and server's address. Usage: %d <port>.\n", argv[0]);
exit(1); // shut down the application
}
// streaming socket is the same as server's one.
// Note: we use TCP Streaming and not UDP's datagram.
int socketObject = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
struct sockaddr_in serverObject;
short int portNumber = atoi(argv[1]);
/**
* We use memset() of cstring header
* to set all uninitialized values of
* the struct serverObject to zero.
*/
memset(&serverObject,
0, sizeof(serverObject));
// now set the values properly
serverObject.
sin_family = AF_INET;
serverObject.sin_addr.s_addr = inet_addr(argv[2]);
serverObject.
sin_port = htons(portNumber);
// we need now to connect to the server by porting out
// out socketObject
returnStatus = connect(socketObject, (sockaddr *)&serverObject, sizeof(serverObject));
if (returnStatus == 0) {
fprintf(stdout, "Connect successfully done.");
}
else {
fprintf(stderr, "Connection failed! Error %s\n", strerror(errno));
close(socketObject);
exit(errno);
}
// now it's time to read the data from the server by using read()
// we read it up to the point of our buffer size
returnStatus = read(socketObject, buffer, sizeof(buffer));
if (returnStatus == -1) {
fprintf(stderr, "cannot read the data.");
close(socketObject);
exit(1);
}
else if( returnStatus > 0)
{
cout << buffer << endl;
close(socketObject);
}
}
};
}// end of namespaCE
SERVER
#include <iostream>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <cstring>
#include <unistd.h>
using namespace std;
const char DATA_BACK_TO_CLIENT[] = "A simple socket server!";
namespace TCP {
class Server {
public :
static bool Connect(int argc, char *argv[]) {
int returnStatus = 0;
if (2 != argc) {
// warn that the port MUST be specified.
fprintf(stderr, "Incorrect parameter for port. Usage: %d <port>.\n", argv[0]);
exit(1); // shut down the application
}
int socketObject = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in serverObject;
int portNumber = atoi(argv[1]);
/**
* We use memset() of cstring header
* to set all uninitialized values of
* the struct serverObject to zero.
*/
memset(&serverObject,
0, sizeof(serverObject));
// now set the values properly
serverObject.
sin_family = AF_INET;
serverObject.sin_addr.
s_addr = htonl(INADDR_ANY);
serverObject.
sin_port = htonl(portNumber);
returnStatus = bind(socketObject, (struct sockaddr *) &serverObject,
sizeof(serverObject));
if (returnStatus != 0) {
fprintf(stderr, "Cannot do the binding. Socket closed.");
close(socketObject);
exit(1);
}
returnStatus = listen(socketObject, 5); // 5 is a typical value for backlog
// which denotes the number of allowed connections in queue, After linux 2.2,
// only completed connections are counted in the queue.
if (returnStatus == -1) {
fprintf(stderr, "Cannot listen on the socketl.");
close(socketObject);
exit(1);
}
while (1) {
cout << "Server has started successfully. Info:" << endl;
cout << "Port Number Listening to: " << portNumber << endl;
int simpleChildSocket = 0;
struct sockaddr clientSocket = {0};
int simpleClient = 0;
socklen_t clientNameLength = sizeof(clientSocket);
cout << "Listening Status:" << returnStatus << endl;
/** blocking-state. accept() is a blocking
* function essentially.
* **/
simpleChildSocket = accept(socketObject, &clientSocket,
&clientNameLength);
cout << "Accept Connection Status: " << simpleChildSocket << endl;
if (simpleChildSocket == -1) {
fprintf(stderr, "Cannot accept connectios.\n");
close(socketObject);
exit(1);
}
/**
* Handle the incoming request
* write received data from the server
*/
write(simpleChildSocket, DATA_BACK_TO_CLIENT, sizeof(DATA_BACK_TO_CLIENT));
// closing the child socket
close(simpleChildSocket);
}
close(socketObject);
}
};
}// end of namespaCE
The port number needs to be set with htons(), not htonl().