I have a problem with my C++ networking code(a test server that receives strings and displays it). Occasionally, when I turn off my server(Ctrl C) and then restart it, clients fail to connect to it. If I wait for around a minute and try connecting with a client again, it works perfect. Doing a ps -A | grep my_server I don't find the process running. However, if I'd try to connect in about 2 minutes it would work just fine.
I find this rather strange.
I'm used to a slightly similar problem in Python, where I have trouble connecting to a port after pressing Ctrl+C. In that case, the process might still be running and I'd have to manually kill the process and try connecting again(and it would work just fine then).
Is there any code that you'd like me to paste in particular? I'm accepting the connections as follows :-
NetworkManager* start_listening(char* host, int port) {
keep_running = true;
signal(SIGINT, signal_handler);
int listenfd, connfd, n;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
pid_t pid;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
#ifdef DEBUG
std::cout << "[+] Starting to listen at port " << port << std::endl;
#endif
#ifdef DEBUG
std::cout << "[+] Binding to port" << std::endl;
#endif
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
#ifdef DEBUG
std::cout << "[+] Starting to listen" << std::endl;
#endif
listen(listenfd, 1024);
clilen = sizeof(cliaddr);
while ( keep_running ) {
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
#ifdef DEBUG
if ( connfd == -1 ) {
std::cout << "Yikes got an error with errno = " << errno << std::endl;
}
sockaddr_in* pV4Addr = (struct sockaddr_in*)&cliaddr;
int ipAddr = pV4Addr->sin_addr.s_addr;
char str[20];
inet_ntop(AF_INET, &ipAddr, str, 20);
std::cout << "[+] Incoming connection from " << str << std::endl;
std::cout << "[+] Using socket " << connfd << std::endl;
#endif
if ( (pid=fork()) == 0 ) {
close(listenfd);
NetworkManager *nm = new NetworkManager(connfd);
return nm;
} else {
close(connfd);
}
}
if (!keep_running) {
// #TODO kill all children
#ifdef DEBUG
std::cout << "[+] Killing server" << std::endl;
#endif
exit(0);
}
return 0;
}
The problem is that you're not checking your return values. For example, to bind. Which could be failing. For example, because you aren't using REUSEADDR to allow binding to a port which was recently in use. There's a timeout on these things, and that was a dead giveaway when you mentioned that it works again after two minutes. But really, check your return values--this is C after all!
Related
I have a strange problem: I have written a c++ programm which is supposed to connect to ip enabled scales. It is using standard c++ sockets.
When I run the programm against real device (address 192.168.30.200 port 23) i am getting errno=ECONNREFUSED (connection refused).
When I run the same program against my dummy server created in python - it is working like a charm (I am using "server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)" etc.
When I connect to the scale from bash with a command "echo "FB_INFO" | netcat -w 3 192.168.30.200 23" (the same address and port) - the scale replies with correct answer. So it is NOT refusing connections.
I have no clue even how to try to debug where is the problem.
Here is my code:
#define PORT 60000
#define ADDRESS "10.0.10.100"
int scale_port=PORT; // scale port number
string scale_ip = ADDRESS; // scale IP address
// connect to scale, and process commands in a loop.
// upon succesfull processing of every complete set of commands
// execute given OS script/shell/command [NOT IMPLEMENTED]
int daemon_connection(int sock, struct sockaddr_in serv_addr)
{
int valread=0;
int connectstatus=connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (connectstatus<0)
//if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
cout << "DAEMON:Error - socket connection failed status "<< connectstatus;
cout << " errno=" << errno << endl;
socketErrPrint(errno);
return -1;
}
cout << "DAEMON: connected to socket" << sock << endl;
struct timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
(...)
}
// the main loop: create socket, parse address and call connect to scale
// and retry forever if connection broken or unsuccesfull
int daemon(string addr, int port)
{
int sock = 0;
struct sockaddr_in serv_addr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "DAEMON: Socket creation error" << endl;
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, addr.c_str(), &serv_addr.sin_addr) <= 0)
{
cout << "DAEMON: error - invalid address "<< addr << " or address not supported" << endl;
return -1;
}
int result=daemon_connection(sock,serv_addr);
}
(...)
This question already has answers here:
What are the use cases of SO_REUSEADDR?
(2 answers)
Closed 7 years ago.
discovering TCP socket, I made a very simple test based on my understanding of the subject and some tuto found on the net
Server :
void Server(void)
{
int localSocket;
int distantSocket;
sockaddr_in serverInfo;
sockaddr_in clientInfo;
int sizeOfSocketInfo = sizeof(struct sockaddr_in);
/* Open Socket */
std::cout << "open socket" << std::endl;
localSocket = socket(AF_INET, SOCK_STREAM, 0);
if (localSocket == -1)
{
std::cout << "open failed, error - " << (int)errno << std::endl;
exit(errno);
}
/* Configure server */
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_family = AF_INET;
serverInfo.sin_port = htons(61001);
/* Bind Socket */
std::cout << "bind socket" << std::endl;
if (bind (localSocket, (sockaddr *) &serverInfo, sizeof(serverInfo)) == -1)
{
std::cout << "bind failed, error - " << (int)errno << std::endl;
exit(errno);
}
/* Wait for client */
std::cout << "Wait for client ..." << std::endl;
listen(localSocket, 1);
distantSocket = accept(localSocket, (sockaddr *)&clientInfo, (socklen_t*)&sizeOfSocketInfo);
std::cout << "client connected - " << inet_ntoa(clientInfo.sin_addr) << std::endl;
/* Close Socket */
close (localSocket);
close (distantSocket);
std::cout << "socket closed" << std::endl;
}
and client :
void Client(void)
{
int localSocket;
sockaddr_in clientInfo;
/* Open Socket */
std::cout << "open socket" << std::endl;
localSocket = socket(AF_INET, SOCK_STREAM, 0);
if (localSocket == -1)
{
std::cout << "open failed, error - " << (int)errno << std::endl;
exit(errno);
}
clientInfo.sin_family = AF_INET;
clientInfo.sin_port = htons(61001);
clientInfo.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Open Socket */
std::cout << "connect to server" << std::endl;
if (connect(localSocket, (sockaddr*)&clientInfo, sizeof(clientInfo)) < (int)0)
{
std::cout << "connect failed, error - " << (int)errno << std::endl;
exit(errno);
}
std::cout << "connected !" << std::endl;
close(localSocket);
}
When I launch the server in one terminal and the client in another one, it seems to be ok :
server side :
> ./tcpTest -s
open socket
bind socket
Wait for client ...
client connected - 127.0.0.1
socket closed
>
and client side :
> ./tcpTest -c
open socket
connect to server
connected !
>
But, if, just after this first try, I launch the server again ...
> ./tcpTest -s
open socket
bind socket
bind failed, error - 98
>
And I have to wait a "certain time", I don't know exactly how long, one minute maybe, to have the server working again.
I can't figure out what's happening, looking to open socket with sockstat does not show anything strange (I only see mozilla socket).
I found this guy having the same problem but in Ruby
basic Ruby TCP server demo fails on startup: `bind': Address already in use, Errno::EADDRINUSE
If this is really the same problem, how can I apply the same solution in C++ ? Or do you have any idea ?
Thank you
You may need to use both SO_REUSEADDR and SO_REUSEPORT. You can further go through the documentation of Socket: Socket Docs
const int trueFlag = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &trueFlag, sizeof(int)) < 0)
error("Failure");
You can use reuse Port in similar way. Hope this helps
Try setsockopt(SO_REUSEADDR), this should help.
I am trying to implement a small c++ server. i want to receive connections from clients, and handle all of these connections in own threads. So far so good. As long as i introduce no threads, it works fine, but as soon as i try to create a thread for a client, accept returns with -1/error.
Here is my code:
void Server::run()
{
cout << "starting server on port " << this->port << "..." << endl;
this->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (this->socket_fd < 0) {
perror("creating socket");
exit(1);
}
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(this->port);
inet_aton("192.168.201.58", &myaddr.sin_addr);
if ( bind(this->socket_fd, (struct sockaddr*)&myaddr, sizeof(myaddr))) {
perror("bind");
exit(1);
}
if (listen(this->socket_fd, 5)) {
perror("listen");
exit(1);
}
/* waiting for clients */
cout << "waiting for connection..." << endl;
int client_fd;
struct sockaddr_in remote_addr;
socklen_t remote_addr_len;
while (this->running) {
client_fd = accept(this->socket_fd, (struct sockaddr*)&remote_addr, &remote_addr_len);
if (client_fd <= 0) {
perror("accept");
this->running = false;
continue;
}
cout << "got new client with address " << inet_ntoa(remote_addr.sin_addr) << endl;
Client new_client(client_fd, remote_addr.sin_addr);
//new_client.run();
std::thread t ( &Client::run, &new_client );
//t.detach();
}
}
when I am trying to connect via telnet, I get "accept: Invalid argument". As soon as I comment out the line where I create the thread
std::thread t ( &Client::run, &new_client );
everything works fine.
I would appreciate any hints.
Try:
std::thread t ( &Client::run, std::move(new_client) );
According to the documentation, that's how you should call it.
Firstly, the code I will share is the basis of my code(found it in another site, open source), I added functions and threads later to improve.
In the office, we have local network and another 3 computer cannot connect to my server. Especially have a look at that line. 26010 is random port number that I want to listen. According to data I found in the other topics, NULL and 127.0.0.1 are the localhost ip.I tried my own ip number instead of NULL, but it didn't work. I can send data from my client code to other computers, but can't get any connections.
Code is listening connections properly, and can get info if I open another 3 terminal and try to connect it from my computer through my client code. How to fix that?
Thanks in advance.
status = getaddrinfo(NULL, "26010", &host_info, &host_info_list);
int main()
{
int status;
struct addrinfo host_info; // The struct that getaddrinfo() fills up with data.
struct addrinfo *host_info_list; // Pointer to the to the linked list of host_info's.
memset(&host_info, 0, sizeof host_info);
std::cout << "Setting up the structs..." << std::endl;
host_info.ai_family = AF_UNSPEC; // IP version not specified. Can be both.
host_info.ai_socktype = SOCK_STREAM; // Use SOCK_STREAM for TCP or SOCK_DGRAM for UDP.
host_info.ai_flags = AI_PASSIVE;
**status = getaddrinfo(NULL, "26010", &host_info, &host_info_list);**
// getaddrinfo returns 0 on succes, or some other value when an error occured.
// (translated into human readable text by the gai_gai_strerror function).
if (status != 0) std::cout << "getaddrinfo error" << gai_strerror(status) ;
std::cout << "Creating a socket..." << std::endl;
int socketfd ; // The socket descripter
socketfd = socket(host_info_list->ai_family, host_info_list->ai_socktype,
host_info_list->ai_protocol);
if (socketfd == -1) std::cout << "socket error " ;
std::cout << "Binding socket..." << std::endl;
int yes = 1;
status = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
status = bind(socketfd, host_info_list->ai_addr, host_info_list->ai_addrlen);
if (status == -1) std::cout << "bind error" << std::endl ;
std::cout << "Listen()ing for connections..." << std::endl;
status = listen(socketfd, 5);
if (status == -1) std::cout << "listen error" << std::endl ;
int new_sd;
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
new_sd = accept(socketfd, (struct sockaddr *)&their_addr, &addr_size);
if (new_sd == -1)
{
std::cout << "listen error" << std::endl ;
}
else
{
std::cout << "Connection accepted. Using new socketfd : " << new_sd << std::endl;
}
std::cout << "Waiting to recieve data..." << std::endl;
ssize_t bytes_recieved;
char incomming_data_buffer[1000];
bytes_recieved = recv(new_sd, incomming_data_buffer,1000, 0);
// If no data arrives, the program will just wait here until some data arrives.
...
std::cout << "send()ing back a message..." << std::endl;
return 0 ;
}
Your problem is your call to getaddrinfo(). This function returns information in the host_info_list member. What you're reading is the hint (host_info) which is not changed by getaddrinfo(). You would need to use host_info_list to read the what's returned by getaddrinfo. You never use it and you never free it (by calling freeaddrinfo).
I am not sure why you'd want to use getaddrinfo() to listen for connection. You can just build the sockaddr yourself. It's easy:
struct sockaddr_in listenAddr;
memset(&listenAddr, 0, sizeof(listenAddr));
/* IPv4 address */
listenAddr.sin_family = AF_INET;
/* your port number */
listenAddr.sin_port = htons(26010);
/* listen on all interfaces */
listenAddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* TCP socket */
socketfd = socket(PF_INET, SOCK_STREAM, 0);
/* your error code, omitted here */
status = bind(SocketFD,(struct sockaddr *) &listenAddr, sizeof(listenAddr))
I am currently programming a C++ module that creates a socket server thread, which polls the accept() function every 1ms. I have a test module that spoofs a client connection that is also running. The test module initiates the creation of the server thread. After the thread is created and verified to be running, the client runs the connect() command as a test. My code states that a connection was established, returning a 0 on the connect command. However, the accept() running in my server thread never receives the connection.
The server is bound to accepting any IP:50000, and the client is not bound, but has 127.0.0.1:50000 set as its destination. Is my Linux environment automatically accepting this connection?
Here is the code for my server's socket:
int nSocket;
int nOn = 1;
int nControl;
struct sockaddr_in sServerAddress;
nSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(nSocket < 0)
{
std::cout << "Failed to create socket\n";
}
if(setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, &nOn, sizeof(int)) < 0)
{
std::cout << "failed to set socket option\n";
}
nControl = fcntl(nSocket, F_GETFL);
if(fcntl(nSocket, F_SETFL, O_NONBLOCK | nControl) < 0)
{
std::cout << "set not blocking failed\n";
}
memset(&sServerAddress, 0x00, sizeof(struct sockaddr_in));
sServerAddress.sin_family = AF_INET;
sServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
sServerAddress.sin_port = htons(mtListenPort);
if(bind(nSocket, (struct sockaddr*)&sServerAddress, sizeof(struct sockaddr_in)) < 0)
{
std::cout << errno << "bind failed\n";
}
if(listen(nSocket, MAXPENDING) < 0)
{
std::cout << "listen failed\n";
}
Here is the code for my test client's socket:
int nSocket;
nSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(nSocket < 0)
{
std::cout << "Failed to create socket\n";
}
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
inet_aton(LOCAL_HOST, &serverAddress.sin_addr);
serverAddress.sin_port = htons(LISTEN_PORT00);
char msg[] = "Hello World.";
usleep(10000);
if (connect(nSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
{
std::cout << errno << "Could not connect to the server.\n";
}
usleep(10000);
if (sendto(nSocket, msg, strlen(msg), 0, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
{
std::cout << errno << "Could not send data to the server.\n";
}
Here is a small part of the thread that runs the accept code.
while(mbListening)
{
nMessengerSocket = accept(mnSocket, (struct sockaddr*)&sClientAddr, &tClientAddrLength);
if(nMessengerSocket >= 0)
{
std::cout << "Accepted connection from " << inet_ntoa(sClientAddr.sin_addr) << std::endl;
mnConnections++;
mbListening = false;
}
mThreadRunningTime++;
usleep(1000);
}
Make sure tClientAddrLength is initialized to sizeof sClientAddr before calling accept(). That is a common error.
Don't silently ignore errors. Examine the error code in errno because it tells you what went wrong.
Are you using sendto? That's for UDP... Use send.
Also, check if the port is free:
telnet localhost 50000
netstat -a