select() not getting more than 1 action - c++

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.

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.

Continuously sending data from server to receiver using c++

I am coding in C++ using winsock api. I am making a multi- client server chat. The problem that I am encountering in my code is that my server is able to send the message to the client only once. But I want this to happen multiple times. I cannot put accept() function out of infinite loop in server code. I have used select() for multi client. I am doing it without threading.
Server:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Initialize winsock! Quitting" << endl;
return;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
// Add our first socket that we're interested in interacting with; the listening socket!
// It's important that this socket is added for our server or else we won't 'hear' incoming
// connections
FD_SET(listening, &master);
// this will be changed by the \quit command (see below, bonus not in video!)
bool running = true;
while (running)
{
// Make a copy of the master file descriptor set, this is SUPER important because
// the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
// are accepting inbound connection requests OR messages.
// E.g. You have a server and it's master file descriptor set contains 5 items;
// the listening socket and four clients. When you pass this set into select(),
// only the sockets that are interacting with the server are returned. Let's say
// only one client is sending a message at that time. The contents of 'copy' will
// be one socket. You will have LOST all the other sockets.
// SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!
fd_set copy = master;
// See who's talking to us
int socketCount = select(0, &copy, nullptr, nullptr, nullptr);
for (int i = 0; i < socketCount; i++) {
//Accept a new connection
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
//Add a new connection
FD_SET(client, &master);
string mssg = "Welcome to the awesome chat server\n";
//Send a welcome message to the connected client
send(client, mssg.c_str(), mssg.size() + 1, 0);
}
//Send a new message
string mssg;
getline(cin, mssg);
int bytes = send(sock, mssg.c_str(), mssg.size() + 1, 0);
for (int i = 0; i < master.fd_count; i++) {
SOCKET outsock = master.fd_array[i];
if (outsock != listening && outsock != sock) {
send(outsock, mssg.c_str(), mssg.size() + 1, 0);
}
}
}
}
// Remove the listening socket from the master file descriptor set and close it
// to prevent anyone else trying to connect.
FD_CLR(listening, &master);
closesocket(listening);
// Message to let users know what's happening.
string msg = "Server is shutting down. Goodbye\r\n";
while (master.fd_count > 0)
{
// Get the socket number
SOCKET sock = master.fd_array[0];
// Send the goodbye message
send(sock, msg.c_str(), msg.size() + 1, 0);
// Remove it from the master file list and close the socket
FD_CLR(sock, &master);
closesocket(sock);
}
// Cleanup winsock
WSACleanup();
system("pause");
}
Client code:
#include<iostream>
#include<ws2tcpip.h>
#include<string>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
void main() {
string ipAddress = "127.0.0.1"; //IP Address of the server
int port = 54000; //Listening port on the sever
//Initialize Winsock
WSADATA data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << " Can't initialize winsock " << endl;
return;
}
//Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
cerr << "Can't create a socket " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
//Fill in a hint structure
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
//Connect to the server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
cerr << " Can't connect to the server " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
//Do-While loop to send and receive data
//char b[4096];
//int bytes = recv(sock,b,4096, 0);
//cout << string(b, 0, bytes) << endl;
char buff[4096];
string userInput;
do {
//Prompt the user
//cout << ">";
//getline(cin, userInput);
//Send the result
//int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
//if (sendResult != SOCKET_ERROR) {
//ZeroMemory(buff, 0);
int bytesrecieved = recv(sock, buff, 4096, 0);
if (bytesrecieved > 0) {
//Echo response to console
cout << "SERVER> " << string(buff, 0, bytesrecieved) << endl;
}
//}
} while (true);
//Shut down everything
closesocket(sock);
WSACleanup();
}
EDIT:
You should do some modifications :
Use timeval for select to avoid the blocking select (wait until a
new connection was made or there is something to read).
Move the read/send message section out of the for loop.
Separate key input processing in an other thread.
Use a safe queue to share the input between the input thread and the communciation one(main thread).
Here is an example:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#include <thread>
#include <mutex>
#include <list>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
class safe_queue {
mutex m;
list<string> str_queue;
public:
safe_queue() {};
void add(const string &s) {
const lock_guard<mutex> lock(m);
str_queue.push_back(s);
}
bool pop( string &s ) {
const lock_guard<mutex> lock(m);
if (!str_queue.empty()) {
s = str_queue.front();
str_queue.pop_front();
return true;
}
return false;
}
};
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Initialize winsock! Quitting" << endl;
return 0;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return 0;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
// Add our first socket that we're interested in interacting with; the listening socket!
// It's important that this socket is added for our server or else we won't 'hear' incoming
// connections
FD_SET(listening, &master);
// this will be changed by the \quit command (see below, bonus not in video!)
bool running = true;
safe_queue sq;
auto io_thread = thread([&] {
string s;
while (running && getline(std::cin, s, '\n')){
sq.add(s);
}
});//thread.
while (running)
{
// Make a copy of the master file descriptor set, this is SUPER important because
// the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
// are accepting inbound connection requests OR messages.
// E.g. You have a server and it's master file descriptor set contains 5 items;
// the listening socket and four clients. When you pass this set into select(),
// only the sockets that are interacting with the server are returned. Let's say
// only one client is sending a message at that time. The contents of 'copy' will
// be one socket. You will have LOST all the other sockets.
// SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!
fd_set copy = master;
timeval tv = {0,0};
// See who's talking to us
int socketCount = select(0, &copy, nullptr, nullptr, &tv);
for (int i = 0; i < socketCount; i++) {
//Accept a new connection
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
//Add a new connection
FD_SET(client, &master);
string mssg = "Welcome to the awesome chat server\n";
//Send a welcome message to the connected client
send(client, mssg.c_str(), mssg.size() + 1, 0);
}
}//for.
string mssg;
if (sq.pop(mssg) ) {
std::cout << "Send :" << mssg << endl;
for (u_int i = 0; i < master.fd_count; i++) {
SOCKET outsock = master.fd_array[i];
if (outsock != listening) {
send(outsock, mssg.c_str(), mssg.size() + 1, 0);
}
}
}
}//while
// Remove the listening socket from the master file descriptor set and close it
// to prevent anyone else trying to connect.
FD_CLR(listening, &master);
closesocket(listening);
// Message to let users know what's happening.
string msg = "Server is shutting down. Goodbye\r\n";
while (master.fd_count > 0)
{
// Get the socket number
SOCKET sock = master.fd_array[0];
// Send the goodbye message
send(sock, msg.c_str(), msg.size() + 1, 0);
// Remove it from the master file list and close the socket
FD_CLR(sock, &master);
closesocket(sock);
}
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}

UDP socket in cpp loops for ever

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.

Nonblocking sockets even if not explicitly setting them as nonblocking

I have a TCP application written in C++, where a client and a server exchange data. I've istantiated a socket, believing that it would have been blocking by default; on the contrary, after server waits for a client, I have that client calls the recv function without waiting for data. This is the code in which I inizialize the socket fr the client.
int TCPreceiver::initialize(char* address, int port)
{
sock = socket (AF_INET, SOCK_STREAM, 0);
cout << "Socket: " << sock << endl;
sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons (port);
target.sin_addr.s_addr = inet_addr(address);
int fails=0;
while (connect(sock, (sockaddr*) &target, sizeof(target)) == -1)
{
fails++;
if (fails==10)
{
close(sock);
cout << "Error with connection to the server, try again"<< endl;
exit(-1);
}
}
cout << "Client connected (control channel)" << endl;
unsigned char text[10]; //Request message
//fill text[]
if(send(sock, (char*)text, 10, 0)==-1)
{
printf("send() failed with error code : %d" , -1);
exit(EXIT_FAILURE);
}
return 0;
}
I've tried adding this code:
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
exit(0);
}
opts = (opts & (~O_NONBLOCK));
if (fcntl(sock,F_SETFL,opts) < 0) {
perror("fcntl(F_SETFL)");
exit(0);
}
but it still doesn't work, and if I call the recv(), the application doesn't block (and recv() always returns 0). Here is the function where I call the recv():
void TCPreceiver::receive(char* text, int& dim)
{
int ret;
ret = recv(sock, text, dim, 0);
dim=ret;
if(ret == -1){
printf("recv() failed with error (%d)\n", ret);
//system("PAUSE");
exit(1);
}
}
Where am I wrong?
recv() returning zero indicates either (1) you passed a zero length, which is just a programming error which I won't discuss further here, or (2) end of stream. The peer has close the connection. This isn't a non-blocking situation, this is the end of the connection. You must close the socket and stop using it. It will never return anything. It zero ever again.
See the man pages.

Validate IP Address (host) exists prior to connecting (ping)

I have a problem where I need to determine if the host exists prior to connecting to it. This host does not work with the function gethostbyaddr() because it is not PC-based and does not return host information. It is IP-based only. Whenever I try to call gethostbyaddr() on the IP address, WinSock returns 11004 (WSANODATA).
Is there a similar function (besides ping) to determine if an IP is valid before trying to connect?
If you have some kind of control over the destination host, one way you could periodically check if the host is present without using up ephemeral ports would be to send a UDP datagram, and wait for the ICMP response to tell you that the datagram was refused by the host.
You do this by creating a SOCK_DGRAM socket, binding to a local port, and calling sendto() to send to a known remote port which is not listening. You can then poll and call recvfrom() which should give an error if your host got the ICMP response back. If the host is not up then you will not get the response. You can reuse the same socket with the same port to send as many datagrams as are required periodically.
Sending ICMP echo request requires high privileges on most system, so is hard to do directly from your code.
Here is some sample code which does roughly what I describe:
struct sockaddr_in local_address;
struct sockaddr_in remote_address;
int sfd;
char * remote_host;
int s;
fd_set fds;
struct timeval timeout;
remote_host = argv[1];
sfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sfd < 0) {
perror("socket");
}
memset(&local_address, 0, sizeof(struct sockaddr_in));
local_address.sin_family = AF_INET;
local_address.sin_addr.s_addr = INADDR_ANY;
local_address.sin_port = htons(6799);
s = bind(sfd,
(struct sockaddr*)&local_address,
sizeof(local_address));
if (s != 0) {
perror("bind");
exit(1);
}
memset(&remote_address, 0, sizeof(struct sockaddr_in));
remote_address.sin_family = AF_INET;
remote_address.sin_addr.s_addr = inet_addr(remote_host);
remote_address.sin_port = htons(6799);
s = sendto(sfd,
"MSG",
3,
0,
(struct sockaddr*)&remote_address,
sizeof(remote_address));
if (s != 3) {
perror("sento");
exit(1);
}
FD_ZERO(&fds);
FD_SET(sfd, &fds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
s = select(sfd + 1, &fds, 0, 0, &timeout);
if (s == 1) {
char buf[512];
printf("Got data, host is up\n");
s = recvfrom(sfd, &buf[0], 512, 0, 0, 0);
perror("recvfrom");
} else {
printf("Timeout, host is down\n");
}
I solved the problem by using the built-in Windows API for PING. I changed the gethostbyname() to inet_addr.
shown here: ICMP.DLL Method
dllping.cpp
// Borland C++ 5.0: bcc32.cpp ping.cpp
// Visual C++ 5.0: cl ping.cpp wsock32.lib
//
// This sample program is hereby placed in the public domain.
#include <iostream.h>
#include <winsock.h>
#include <windowsx.h>
#include "icmpdefs.h"
int doit(int argc, char* argv[])
{
// Check for correct command-line args
if (argc < 2) {
cerr << "usage: ping <host>" << endl;
return 1;
}
// Load the ICMP.DLL
HINSTANCE hIcmp = LoadLibrary("ICMP.DLL");
if (hIcmp == 0) {
cerr << "Unable to locate ICMP.DLL!" << endl;
return 2;
}
// Look up an IP address for the given host name
struct hostent* phe;
if ((phe = gethostbyname(argv[1])) == 0) {
cerr << "Could not find IP address for " << argv[1] << endl;
return 3;
}
// Get handles to the functions inside ICMP.DLL that we'll need
typedef HANDLE (WINAPI* pfnHV)(VOID);
typedef BOOL (WINAPI* pfnBH)(HANDLE);
typedef DWORD (WINAPI* pfnDHDPWPipPDD)(HANDLE, DWORD, LPVOID, WORD,
PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD); // evil, no?
pfnHV pIcmpCreateFile;
pfnBH pIcmpCloseHandle;
pfnDHDPWPipPDD pIcmpSendEcho;
pIcmpCreateFile = (pfnHV)GetProcAddress(hIcmp,
"IcmpCreateFile");
pIcmpCloseHandle = (pfnBH)GetProcAddress(hIcmp,
"IcmpCloseHandle");
pIcmpSendEcho = (pfnDHDPWPipPDD)GetProcAddress(hIcmp,
"IcmpSendEcho");
if ((pIcmpCreateFile == 0) || (pIcmpCloseHandle == 0) ||
(pIcmpSendEcho == 0)) {
cerr << "Failed to get proc addr for function." << endl;
return 4;
}
// Open the ping service
HANDLE hIP = pIcmpCreateFile();
if (hIP == INVALID_HANDLE_VALUE) {
cerr << "Unable to open ping service." << endl;
return 5;
}
// Build ping packet
char acPingBuffer[64];
memset(acPingBuffer, '\xAA', sizeof(acPingBuffer));
PIP_ECHO_REPLY pIpe = (PIP_ECHO_REPLY)GlobalAlloc(
GMEM_FIXED | GMEM_ZEROINIT,
sizeof(IP_ECHO_REPLY) + sizeof(acPingBuffer));
if (pIpe == 0) {
cerr << "Failed to allocate global ping packet buffer." << endl;
return 6;
}
pIpe->Data = acPingBuffer;
pIpe->DataSize = sizeof(acPingBuffer);
// Send the ping packet
DWORD dwStatus = pIcmpSendEcho(hIP, *((DWORD*)phe->h_addr_list[0]),
acPingBuffer, sizeof(acPingBuffer), NULL, pIpe,
sizeof(IP_ECHO_REPLY) + sizeof(acPingBuffer), 5000);
if (dwStatus != 0) {
cout << "Addr: " <<
int(LOBYTE(LOWORD(pIpe->Address))) << "." <<
int(HIBYTE(LOWORD(pIpe->Address))) << "." <<
int(LOBYTE(HIWORD(pIpe->Address))) << "." <<
int(HIBYTE(HIWORD(pIpe->Address))) << ", " <<
"RTT: " << int(pIpe->RoundTripTime) << "ms, " <<
"TTL: " << int(pIpe->Options.Ttl) << endl;
}
else {
cerr << "Error obtaining info from ping packet." << endl;
}
// Shut down...
GlobalFree(pIpe);
FreeLibrary(hIcmp);
return 0;
}
int main(int argc, char* argv[])
{
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
return 255;
}
int retval = doit(argc, argv);
WSACleanup();
return retval;
}
icmpdefs.h
// Structures required to use functions in ICMP.DLL
typedef struct {
unsigned char Ttl; // Time To Live
unsigned char Tos; // Type Of Service
unsigned char Flags; // IP header flags
unsigned char OptionsSize; // Size in bytes of options data
unsigned char *OptionsData; // Pointer to options data
} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;
typedef struct {
DWORD Address; // Replying address
unsigned long Status; // Reply status
unsigned long RoundTripTime; // RTT in milliseconds
unsigned short DataSize; // Echo data size
unsigned short Reserved; // Reserved for system use
void *Data; // Pointer to the echo data
IP_OPTION_INFORMATION Options; // Reply options
} IP_ECHO_REPLY, * PIP_ECHO_REPLY;
Here you can find the source of a short DNS resolver in C++.
DNS queries are not going to help you to establish whether the box is up (which is what you seem to be trying to do).
If you can run a process on the target box, you could run a heartbeat service of some sort, which would accept a TCP connection from the monitoring app, and send an "I'm alive" message every 2.5 seconds. The inability to connect or the lack of heartbeats would tell your monitoring app that there's a problem.
Alternatively (and perhaps more straightforwardly), why not use ICMP ping?
If you're only allowed a certain number of ephemeral ports, stop using ephemeral ports. Bind the source socket to a known port number before using it to attempt to connect to the other machine.
Alternatively, you don't say why you want to avoid ping. If it's just about doing it in code, you can generate an ICMP packet yourself and use that.