I'm trying to make a server sample in c++ using <sys/socket.h>
and Qt Creator gui builder but two weird behaviors are going on at socket layer of the program. First of, I run the server but at the first attempt I make to connect to it using telnet
is imediately closed
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
When I attempt connection for the second time, it works and the terminal waits for my input. The second thing is when I close the connection. If I rerun right after, in a matter of minutes, the program halts on bind
exiting and returning:
ERROR on binding: Address already in use
So I suppose maybe a connection is being held after I break it using function call onCortarConexao()
or just stopping the debugger. Anyway, what am I missing?
My code:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
On MainWindow.cpp:
void MainWindow::on_pushButton_clicked()
{
socket1 = new MSocket();
socket1->start();
}
void MainWindow::on_pushButton_3_clicked()
{
socket1->onCortarConexao();
}
Socket class:
#ifndef MSOCKET_H
#define MSOCKET_H
#include <QString>
#include <QObject>
#include <QThread>
#include <QList>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define SERVER_BUFFER 4096
#define PORTRUN 15000
class MSocket : public QThread
{
public:
MSocket();
void error(char *msg);
void onCortarConexao();
private:
int sockfd;
int newsockfd;
int portno;
int clilen;
int n;
char buffer[SERVER_BUFFER];
struct sockaddr_in serv_addr, cli_addr;
u_short port;
void run();
};
#endif // MSOCKET_H
Socket implementation:
void MSocket::run()
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
error("ERROR opening socket");
exit(-1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = PORTRUN;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
serv_addr.sin_addr.s_addr = INADDR_ANY;
fprintf(stdout,"Iniciando servidor..");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
error("ERROR on binding");
exit(-1);
}
listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) sizeof(cli_addr));
if (newsockfd < 0){
error("ERROR on accept");
exit(-1);
}
bzero(buffer,SERVER_BUFFER);
n = read(newsockfd,buffer,SERVER_BUFFER-1);
if (n < 0)
error("ERROR reading from socket");
printf("Here is the message: %s",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0)
error("ERROR writing to socket");
}
void MSocket::onCortarConexao(){
printf("Encerrando socket");
close(newsockfd);
close(sockfd);
}
The complete code is at: https://github.com/FabioNevesRezende/BasicCppServer
Edit 1:
So, this is the list of packets of the communication between telnet and my Qt Server application it can be graphicaly seen in WireShark (.pcapng file). It contains 11 frames. The 6 first ones are from the first telnet, when it is imediately closed. As it seems on frame 4 and 5 where the application sends [FIN, ACK]
and the server responds to it by closing the connection. The frames 7,8,9 are the second attempt to connect and frames 10 and 11 is when I send the abc
to the server. As in the print screen:
The problem is I don't know why the application is sending this FIN
and where in the code it is.
Use SO_REUSEADDR
with setsockopt
:
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
This allows the port to be reused by other sockets and gets around the address already in use
issue you're facing.
The previous answers have indicate that how to handle the read correctly and how to use SO_RESUEADDR. I want to point out why your program can just receive one message. because your run function doesn't have a loop, so it can be only performed once, then the thread exits. after accept a client's request, then the connection is establish, then you should enter a loop to wait the client's input, and write them back once the read function returns.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With