I have a strange problem. I have 2 binaries by the name cpp and another is called mnp_proxy_server.
cpp will start mnp_proxy_binary by calling a method executeScript. The code of this method is
int executeScript(string script, unsigned int scriptTmOut)
{
fd_set readfd;
const int BUFSIZE = 1024;
//stringstream strBuf;
char buf[ BUFSIZE];
time_t startTime = time(NULL);
struct timeval tv;
int ret, ret2 = 0;
FILE * pPipe = popen(script.c_str(), "r");
if (pPipe == NULL)
{
// cout << "popen() failed:"<< strerror(errno) << endl;
return -1;
}
while(1)
{
FD_ZERO(&readfd);
FD_SET(fileno(pPipe), &readfd);
/** Select Timeout Hardcode with 1 secs **/
tv.tv_sec = scriptTmOut;
tv.tv_usec = 0;
ret = select(fileno(pPipe)+1, &readfd, NULL, NULL, &tv);
if(ret < 0)
{
// cout << "select() failed " << strerror(errno) << endl;
}
else if (ret == 0)
{
// cout << "select() timeout" << endl;
break;
}
else
{
//cout << "Data is available now" <<endl;
if(FD_ISSET(fileno(pPipe), &readfd))
{
if(fgets(buf, sizeof(buf), pPipe) != NULL )
{
//cout << buf;
//strBuf << buf;
}
/** No Problem if there is no data ouput by script **/
#if 1
else
{
//ret2 = -1;
// cout << "fgets() failed " << strerror(errno) << endl;
break;
}
#endif
}
else
{
ret2 = -1;
// cout << "FD_ISSET() failed " << strerror(errno) << endl;
break;
}
}
/** Check the Script-timeout **/
if((startTime + scriptTmOut) < time(NULL))
{
// cout<<"Script Timeout"<<endl;
break ;
}
}
pclose(pPipe);
return ret2;
}
cpp is a server which listens on various ports 7001 and 7045. Once mnp_proxy_server is started it connects to 7001 port and starts sending messages.
Now coming to the problem. when i send ctr^c signal to cpp the signal is propagated to mnp_proxy_server and if i kill cpp process then all the ports on which cpp was listning now becomes the part of mnp_proxy_server process.
output of netstat after killing cpp process
[root#punith bin]# netstat -alpn | grep mnp_pr
tcp 0 0 0.0.0.0:7045 0.0.0.0:* LISTEN 26186/mnp_proxy_ser
tcp 0 0 0.0.0.0:7001 0.0.0.0:* LISTEN 26186/mnp_proxy_ser
I know it has something to do with the way I am executing the startup script of mnp_proxy_server through cpp.
There is a signal handler in both the binaries. And also to exit the socket select when ctr^c is pressed I have used pipes in select, so when ctr^c is pressed i close the write end of the pipe so that select is notified and select comes out and breaks the run loop.
Both of them are written in c++ and I am using rhel
Any clue will greatly help me in solving this. Thanking in advance.
You should set the flag CLOEXEC on the server sockets of cpp so that they are closed in the child process:
fcntl(fd, F_SETFD, FD_CLOEXEC);
While using socket like in your processes, I would suggest use fork and exec instead of popen to be able to close or manage all sockets between fork and exec, but the flag CLOEXEC might be enough to solve your problem.
Related
I am trying to find a way to close a server safely while it is listening for incoming client connection without using the classic ctrl+C in linux. I would like to terminate the program for example by keyboard input of Q or -quit etc... and do so instantly after pressing enter, not after accepting, for example, a client connection. How should I implement this?
Here is my sample code.
int startSocketConnection() {
socketFD = socket(AF_INET, SOCK_STREAM, 0);
//TODO exceptions
if (socketFD < 0) {
std::cout << "\nError establishing socket...\nexiting..." << std::endl;
return (-1);
}
std::cout << "\nSocket server has been created..." << std::endl;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(portNum);
//TODO exceptions
if ( (bind(socketFD, (struct sockaddr*) &server_addr, sizeof(server_addr))) < 0 ) {
std::cout << "Error binding connection, Socket has already been established" << std::endl;
return (-1);
}
std::cout << "Listening for incoming client connection..." << std::endl;
listen(socketFD, 1);
size = sizeof(client_addr);
while (sessionActive) {
newSocketFD = accept(socketFD, (struct sockaddr *) &client_addr, &size);
if (newSocketFD < 0) error("ERROR on accept");
//fork() returns child pid to parent, 0 to the child process.
pid = fork();
if (pid < 0) error("ERROR on fork");
//if child process...
if (pid == 0) {
close(socketFD);
//process client query...
sessionActive = dostuff(newSocketFD);
signal(SIGCHLD, SIG_IGN);
std::cout << "Child process terminated!" << std::endl;
exit(0);
}
else {
close(newSocketFD);
}
}
close(socketFD);
return 0;
}
You need to either add another thread that reads from stdin and unceremoniously exits your application when it sees those commands, or change your code to use a command like select or poll to see which descriptors have input available: add the descriptor for stdin (for your purposes, you can trust it to be 0) alongside the descriptor for the listening socket, and when either or both have input events your select or poll will return and - if it tells you stdin has data - you can read from it without blocking: if you see your termination command, exit.
For select/poll, you should set the socket you're calling accept on to non-blocking, as it's possible to be notified of an incoming connection attempt but by the time you go to accept that connection may have already failed - you don't want accept to block and stop your select or poll call monitoring stdin too for you.
Of the two, the extra thread is easiest - here's a minimal program illustrating how to start it and have it monitor stdin while your main thread's doing its own stuff. On Linux, link with -lpthread.
#include <thread>
#include <iostream>
#include <string>
#include <unistd.h> // for sleep
int main()
{
std::thread t{
[] {
std::string s;
while (std::cin >> s)
if (s == "exit")
{
std::cout << "exit command given on stdin\n";
exit(0);
}
}
};
t.detach();
while (true)
{
sleep(2);
std::cout << "beat\n";
}
}
(It does get a bit more complicated if you want "orderly" shutdown, where destructors for objects in the main thread are guaranteed to run....)
I'm following the tutorial (big code block near the bottom of that section)
here:http://beej.us/guide/bgnet/output/html/multipage/advanced.html#select
And the main server code code is like so:
while (true)
{
read_fds = master;
if (select(fd_max + 1, &read_fds, NULL, NULL, NULL) == -1)
{
cerr << "ERROR. Select failed" << endl;
return -1;
}
for (int i = 0; i <= fd_max; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == welcome_socket)
{
cout << "NEW CONNECTION" << endl;
client_len = sizeof(struct sockaddr_in);
client_sock = accept(welcome_socket, (struct sockaddr *) &client_addr, &client_len);
if (client_sock != -1)
{
FD_SET(client_sock, &master);
if (client_sock > fd_max)
{
fd_max = client_sock;
}
}
}
else
{
int length, total_read = 0;
// CONNECTION CLOSED BY CLIENT
if (safe_recv(client_sock, &length, sizeof(int)) <= 0)
{
cout << "CONNECTION CLOSED" << endl;
close(i);
FD_CLR(i, &master);
}
else
{
char *message = (char *)memset((char *)malloc(length + 1), 0, length);
// while ((total_read += safe_recv(client_sock, message + total_read, length - total_read)) < length) {}
safe_recv(client_sock, message, length);
// RESPOND WITH MESSAGE
cout << "MESSAGE: " << message << endl;
write(client_sock, process(message), length);
free(message);
}
}
}
}
}
What I'm doing is first sending (from the client) the length of the string, then the string itself. Then the server sends back process(message).
When I only have 1 connection, I'm seeing correct behaviour. However if 1 is connected already and I connect a new client, what I'm seeing is:
1st client no longer sends or receives anything from server (concluded because nothing is printed to stdout on client side)
2nd client is working as expected
When 2nd connection exits, server counts that as both connections exiting (prints CONNECTION CLOSED twice)
I've tried to keep this very similar to the tutorial code. I've run the tutorial server, and that works as intended with several clients.
I'm new to network programming, so I apologise if this is a beginner problem or just something dumb I overlooked.
The code reads from and writes to only client_sock, and client_sock is replaced with the new socket in the accept handling portion of the code.
Most likely you want to interact with i rather than client_sock.
I read about select() and also read many examples of it, but I can't understand when can I use it?
I understood that I can use it in the accept() function, in case I want few people to connect to the server, but it has confused me.
I need to built a server that receive data only from 2 clients, 1 every time. The first user sends to the server a string, the string responds and then the second user sends a string.
Can someone help me with combining the select() function in the recv() function?
I've added my server.cpp code. Thank you!
server:
#include <iostream>
#include <winsock2.h>
#include <string>
#include <windows.h>
#include <vector>
#pragma comment(lib,"ws2_32.lib")
#define MAX_NUMBER_OF_PLAYERS 1
#define BUFFER_SIZE 1024
#define LIMIT 1
// server side
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30
// client side
#define MOVE 10
using namespace std;
int main()
{
WSADATA WsaDat;
SOCKET clientsock[2];
int minsock = 0;
int numsocks = MAX_NUMBER_OF_PLAYERS;
if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
{
std::cout << "WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
std::cout << "Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKADDR_IN serverInf;
serverInf.sin_family = AF_INET;
serverInf.sin_addr.s_addr = INADDR_ANY;
serverInf.sin_port = htons(8888);
if (bind(serverSocket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
{
std::cout << "Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
listen(serverSocket, 5);
clientsock[0] = accept(serverSocket, NULL, NULL);
cout << "Client 1 has connected." << endl;
clientsock[1] = accept(serverSocket, NULL, NULL);
cout << "Client 2 has connected." << endl;
for (int i = 0; i < 2; i++)
{
cout << "Client " << i+1 << " Has Connected!" << endl;
}
char client1_buffer[BUFFER_SIZE];
char client2_buffer[BUFFER_SIZE];
char* clientBuffer;
// until there isn't a mate.
bool gameRunning = true;
// user represents if it's user1 (0), or user2(1)
bool user = 0;
while (gameRunning)
{
if (!user)
clientBuffer = client1_buffer;
else
clientBuffer = client2_buffer;
int in = recv(clientsock[user], clientBuffer, BUFFER_SIZE, 0);
cout << in << endl;
if (in > 0)
{
// CHECKS
// MOVE COMMAND
// IF worked, send the board to both clients. if current user = 1 ==> do user to 0 | if the user = 0 => do user to 11
// ELSE, send the current client (clientsock[user]) Error message and ask for a command again.
cout << clientBuffer << endl;
cout << " IN RECV";
char* szMessage = "15";
send(clientsock[user], szMessage, sizeof(szMessage), 0);
}
else if (in == 0)
{
// The connection has closed.
// REMEMBER : SAVE THE GAME SITUATION.
}
else
{
printf("recv failed: %d\n", WSAGetLastError());
// SEND ERROR MESSAGE TO BOTH CLIENTS
}
user = !user;
}
// Shutdown our socket
shutdown(serverSocket, SD_SEND);
// Close our socket entirely
closesocket(serverSocket);
WSACleanup();
system("pause");
return 0;
}
Ok, now that you corrected your code, I have to do some work.
I suggest you remove this
user = !user
and add this immediately after the beginning of the while loop:
{
int nfds = 0; // smallest number higher than all socket descriptors
fd_set set; // this contains garbage from the stack, thus ...
FD_ZERO(&set); // first clean it and then add both client sockets:
FD_SET(clientsock[0],&set); if(nfds<=clientsock[0]) nfds=clientsock[0]+1;
FD_SET(clientsock[1],&set); if(nfds<=clientsock[1]) nfds=clientsock[1]+1;
select(nfds,&set,0,0,0); // this uses and changes the content of set
bool next = !user; // next is the other user, and we try to serve it:
if(FD_ISSET(clientsock[next],&set)) user=next;
}
By the way, I like your creative way of using bool as an index, though once you have more than 2 clients, you might have to change that concept.
My code implements a little bit of scheduling policy: If there is data available from both clients, it reads from that client from which it did not read data the previous time. If, instead, you want to read lots of data from one client and then lots of data from the other, replace the lines containing next by
if(!FD_ISSET(clientsock[user],&set)) user=!user;
The first version tries to alternate as often as possible, while the second tries to read as much data as possible from the same client before switching to the other.
I've had my socket class working for a while now, but I wanted to add a timeout using select(). Seems pretty straight forward but I always have 0 returned from select(). I've even removed the select() check so it reads data regardless of select() and the data gets read, but select() still reports that data is not present. Any clue on how to get select() to stop lying to me? I've also set the socket to non-blocking. Thanks.
Code:
char buf [ MAXRECV + 1 ];
s = "";
memset ( buf, 0, MAXRECV + 1 );
struct timeval tv;
int retval;
fd_set Sockets;
FD_ZERO(&Sockets);
FD_SET(m_sock,&Sockets);
// Print sock int for sainity
std::cout << "\nm_sock:" << m_sock << "\n";
tv.tv_sec = 1;
tv.tv_usec = 0;
retval = select(1, &Sockets, NULL, NULL, &tv);
std::cout << "\nretval is :[" << retval << "]\n\n";
// Check
if (FD_ISSET(m_sock,&Sockets))
std::cout << "\nFD_ISSET(m_sock,&Sockets) is true\n\n";
else
std::cout << "\nFD_ISSET(m_sock,&Sockets) is false\n\n";
// If error occurs
if (retval == -1)
{
perror("select()");
std::cout << "\nERROR IN SELECT()\n";
}
// If data present
else if (retval)
{
std::cout << "\nDATA IS READY TO BE READ\n";
std::cout << "recv ( m_sock, buf, MAXRECV, 0)... m_sock is " << m_sock << "\n";
int status = recv ( m_sock, buf, MAXRECV, 0 );
if ( status == -1 )
{
std::cout << "status == -1 errno == " << errno << " in Socket::recv\n";
return 0;
}
else if ( status == 0 )
{
return 0;
}
else
{
s = buf;
return status;
}
}
// If data not present
else
{
std::cout << "\nDATA WAS NOT READY, TIMEOUT\n";
return 0;
}
Your call to select is incorrect, as you have already discovered. Even though the first parameter is named nfds in many forms of documentation, it is actually one more than the largest file descriptor number held by any of the fd_sets passed to select. In this case, since you are only passing in one file descriptor, the call should be:
retval = select(m_sock + 1, &Sockets, NULL, NULL, &tv);
If you have an arbitrary number of sockets you are handling each in a different thread, you might find my answer to this question a better approach.
Whoops. Looks like I forgot to set select()'s int nfds:
working good now.
I begin to develop my tool, which works with net at the TCP level, which will present simple functions of web-server.
In testing my program I have got very bad mistakes:
Memory leaks
Creating thousands of threads immediately
In taskmgr.exe you may see about ~1,5 of threads and about ~50kb of allocated memory.
Also, I compiled program as 32 bit, but in vmmap utility you may see a lot of 64 bit stacks. My OS is 64 bit, but in taskmgr.exe you may see *32 , I don’t know how 32 bit program uses 64 bit stack, maybe it’s normal for launching 32 bit program in 64 bit OS, but I have no knowledge about this design of OS, so I shall be very pleased , if you give me a piece of advice on this question.
So, why did my program creates immediately a lot of threads? ( I guess , cause of while(true) block ).
But , I want the next:
Create each thread for each new request
When request has been handled, then terminate the thread and free the memory
How should I remake my code?
Thanks!
Here is my code ( MS VC ++ 9 ):
#include <iostream>
#include <Windows.h>
#pragma comment(lib, "Ws2_32.lib")
typedef struct Header
{
friend struct Net;
private:
WORD wsa_version;
WSAData wsa_data;
SOCKET sock;
SOCKADDR_IN service;
char *ip;
unsigned short port;
public:
Header(void)
{
wsa_version = 0x202;
ip = "0x7f.0.0.1";
port = 0x51;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr(ip);
service.sin_port = htons(port);
}
} Header;
typedef struct Net
{
private:
int result;
HANDLE thrd;
DWORD exit_code;
void WSAInit(WSAData *data, WORD *wsa_version)
{
result = WSAStartup(*wsa_version, &(*data));
if(result != NO_ERROR)
{
std::cout << "WSAStartup() failed with the error: " << result << std::endl;
}
else
{
std::cout << (*data).szDescription << " " << (*data).szSystemStatus << std::endl;
}
}
void SocketInit(SOCKET *my_socket)
{
(*my_socket) = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if((*my_socket) == INVALID_SOCKET)
{
std::cout << "Socket initialization failed with the error: " << WSAGetLastError() << std::endl;
WSACleanup();
}
else
{
std::cout << "Socket initialization successful!" << std::endl;
}
}
void SocketBind(SOCKET *my_socket, SOCKADDR_IN *service)
{
result = bind((*my_socket), (SOCKADDR*)&(*service), sizeof(*service));
if(result == SOCKET_ERROR)
{
std::cout << "Socket binding failed with the error: " << WSAGetLastError() << std::endl;
closesocket((*my_socket));
WSACleanup();
}
else
{
std::cout << "Socket binding successful!" << std::endl;
}
result = listen(*my_socket, SOMAXCONN);
if(result == SOCKET_ERROR)
{
std::cout << "Socket listening failed with the error: " << WSAGetLastError() << std::endl;
}
else
{
std::cout << "Listening to the socket..." << std::endl;
}
}
static void SocketAccept(SOCKET *my_socket)
{
SOCKET sock_accept = accept((*my_socket), 0, 0);
if(sock_accept == INVALID_SOCKET)
{
std::cout << "Accept failed with the error: " << WSAGetLastError() << std::endl;
closesocket(*my_socket);
WSACleanup();
}
else
{
std::cout << "Client socket connected!" << std::endl;
}
char data[0x400];
int result = recv(sock_accept, data, sizeof(data), 0);
HandleRequest(data, result);
char *response = "HTTP/1.1 200 OK\r\nServer: Amegas.sys-IS/1.0\r\nContent-type: text/html\r\nSet-Cookie: ASD643DUQE7423HFDG; path=/\r\nCache-control: private\r\n\r\n<h1>Hello World!</h1>\r\n\r\n";
result = send(sock_accept, response, (int)strlen(response), 0);
if(result == SOCKET_ERROR)
{
std::cout << "Sending data via socket failed with the error: " << WSAGetLastError() << std::endl;
closesocket(sock_accept);
WSACleanup();
}
else
{
result = shutdown(sock_accept, 2);
}
}
static void HandleRequest(char response[], int length)
{
std::cout << std::endl;
for(int i = 0; i < length; i++)
{
std::cout << response[i];
}
std::cout << std::endl;
}
static DWORD WINAPI Threading(LPVOID lpParam)
{
SOCKET *my_socket = (SOCKET*)lpParam;
SocketAccept(my_socket);
return 0;
}
public:
Net(void)
{
Header *obj_h = new Header();
WSAInit(&obj_h->wsa_data, &obj_h->wsa_version);
SocketInit(&obj_h->sock);
SocketBind(&obj_h->sock, &obj_h->service);
while(true)
{
thrd = CreateThread(NULL, 0, &Net::Threading, &obj_h->sock, 0, NULL);
//if(GetExitCodeThread(thrd, &exit_code) != 0)
//{
// ExitThread(exit_code);
//}
}
delete &obj_h;
}
} Net;
int main(void)
{
Net *obj_net = new Net();
delete &obj_net;
return 0;
}
You should create the thread AFTER you accept a connection, not before.
What you are doing is creating a ton of threads, and then having each of them wait for a connection. Many of them have nothing to do. I don't even know if Windows' accept call is thread-safe - you might end up with multiple threads handling the same connection.
What you need to do instead is, in your main loop (Net's constructor while(true)), you need to call accept(). Since accept() blocks until it has a connection, this will cause the main thread to wait until somebody tries to connect. Then, when they do, you create another thread (or process - more likely on UNIX) to handle that connection. So, your loop now looks like this:
SOCKET sock_accept = accept((*my_socket), 0, 0);
if(sock_accept == INVALID_SOCKET)
{
std::cout << "Accept failed with the error: " << WSAGetLastError() << std::endl;
closesocket(*my_socket);
WSACleanup();
}
else
{
std::cout << "Client socket connected!" << std::endl;
}
thrd = CreateThread(NULL, 0, &Net::Threading, &obj_h->sock, 0, NULL);
//push back thrd into a std::vector<HANDLE> or something like that
//if you want to keep track of it for later: there's more than one thread
Then, delete that code you moved from SocketAccept into this loop. And then, for cosmetic purposes, I would change the name of SocketAccept to SocketHandleConnection.
Now, when your thread starts, it already has a connection, and all you need to do is handle the data (e.g. what you do starting at char data[0x400]).
If you want to handle cleanup for connections, there are a few ways to do this. One, since you are threaded, you can have the thread do its own cleanup. It shares memory with the main process, so you can do this. But in this example, I don't see anything you need to clean up.
Lastly, I think you don't understand what ExitThread does. According to MSDN:
ExitThread is the preferred method of exiting a thread in C code. However, in C++ code,
the thread is exited before any destructors can be called or any other automatic cleanup
can be performed. Therefore, in C++ code, you should return from your thread function.
So it appears that you don't need to call ExitThread- you just return from your function and the thread exits automatically. You don't need to call it from the main thread.
Finally, you should really (if you can) use the new standard C++ threads in c++11, and then if you put in a little bit of effort to port your code over to boost::asio, you'll have a completely cross platform application, with no need for windows API C ugliness :D
DISCLAIMER: I only have a passing understanding of Windows as most of my experience is related to UNIX. I have attempted to be as accurate as I can but if I have any misconceptions about how this knowledge converts over to Windows, well, I warned you.
Why are you creating threads in an infinite loop? This will, of course, create tons of threads. I am referring to this piece of code:
while(true)
{
thrd = CreateThread(NULL, 0, &Net::Threading, &obj_h->sock, 0, NULL);
}