Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ socket closing the first connection attempt

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:

sequence of commands

The problem is I don't know why the application is sending this FIN and where in the code it is.

like image 886
Fnr Avatar asked Aug 14 '16 21:08

Fnr


2 Answers

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.

like image 113
aviraldg Avatar answered Sep 28 '22 16:09

aviraldg


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.

like image 38
Jian Zhang Avatar answered Sep 28 '22 15:09

Jian Zhang