Solved Read data from socket when pressed button widget
-
My problem is that at the moment I am able to read the socket data just once when pressed button widget and after pressing the button widget the socket connection goes down. I need to get the data receive to be continuous so that every time I press the button widget it will update the result to the LCD widget.
On the server side I am reading distance with ultra sonic sensor and calculate speed of the read distance values. Then I serialize the data to 8 bytes and send that 8 byte buffer through socket. This is inside a infinite while loop so that it continuously reads distance and calculates speed and then send those two values which are serialized to 8 bytes.
Here are my client side codes:
TCP_SocketClient.cpp:
#include "TCP_SocketClient.h" /*Global socket file descriptor*/ int m_sock_fd; TCP_SocketClient::TCP_SocketClient() { m_port = PORT_NUMBER; m_address = ADDRESS; } TCP_SocketClient::~TCP_SocketClient() { close(m_sock_fd); } bool TCP_SocketClient::CreateSocket() { /* Create socket */ if((m_sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Could not create socket \n"); return false; } memset(&m_server, '0', sizeof(m_server)); m_server.sin_family = AF_INET; m_server.sin_port = htons(m_port); /* Convert std::string to a const char* */ const char * c_address = m_address.c_str(); /*This function converts the character string src into a network address structure in the af address family, then copies the network address structure to dst.*/ if(inet_pton(AF_INET, c_address, &m_server.sin_addr)<=0) { perror("inet_pton error occured\n"); return false; } /* Connect */ if( connect(m_sock_fd, (struct sockaddr *)&m_server, sizeof(m_server)) < 0) { perror("Connect Failed \n"); return false; } return true; } bool TCP_SocketClient::SendAndReceiveSocketData(HRLVEZ0_Data_t *Data) { memset(this->m_recvBuf, '0',sizeof(this->m_recvBuf)); this->m_sendBuf[0] = 'S'; /* Send character "S" to the socket to receive data */ if(send(m_sock_fd, this->m_sendBuf, sizeof(this->m_sendBuf), 0) < 0) { perror("Send failed!\n"); return false; } /* Receive the socket data */ if(recv(m_sock_fd, this->m_recvBuf, sizeof(this->m_recvBuf), 0) < 0) { perror("Couldn't read data from the socket!\n"); return false; } /* Deserialize the recieved data */ Data->distance = DeserializeIntDistance(this->m_recvBuf); this->m_IntSpeed = DeserializeIntSpeed(this->m_recvBuf); Data->speed = Deserialize754_32(this->m_IntSpeed); std::cout << "Distance:" << Data->distance << std::endl; std::cout << "Speed:" << Data->speed << std::endl; return true; } float TCP_SocketClient::Deserialize754Float(unsigned int floatspeed, unsigned int bits, unsigned int expbits) { /* -1 for sign bit */ this->m_significantbits = bits - expbits -1; if(floatspeed == 0) return 0.0; /*pull the significant*/ this->m_result = (floatspeed&((1<<this->m_significantbits)-1)); //mask this->m_result /= (1<<this->m_significantbits); //convert back to float this->m_result += 1.0f; //add the one back on //deal with the exponent this->m_bias = (1<<(expbits-1)) -1; this->m_shift = ((floatspeed>>this->m_significantbits)&((1<<expbits)-1)) - this->m_bias; while(this->m_shift > 0) { this->m_result *= 2.0; this->m_shift--; } while(this->m_shift < 0) { this->m_result /= 2.0; this->m_shift++; } /*sign it*/ this->m_result *= (floatspeed>>(bits-1))&1? -1.0 : 1.0; return this->m_result; } unsigned int TCP_SocketClient::DeserializeIntSpeed(unsigned char *buf) { this->m_value = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]; return this->m_value; } unsigned int TCP_SocketClient::DeserializeIntDistance(unsigned char *buf) { this->m_value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; return this->m_value; }
TCP_SocketClient.h:
#ifndef TCP_SOCKETCLIENT_H #define TCP_SOCKETCLIENT_H #include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <unistd.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h> //Macro for deserializing float #define Deserialize754_32(i) (Deserialize754Float((i), 32, 8)) #define ADDRESS "10.42.0.2" #define PORT_NUMBER 51000 //Global socket file descriptor extern int m_sock_fd; //Structure of HRLVEZ0 data coming through TCP socket typedef struct HRLVEZ0_Data { float speed; int distance; }HRLVEZ0_Data_t; class TCP_SocketClient { public: TCP_SocketClient(); ~TCP_SocketClient(); bool CreateSocket(); bool RecieveSocketData(HRLVEZ0_Data_t *Data); float Deserialize754Float(unsigned int floatspeed, unsigned int bits, unsigned int expbits); unsigned int DeserializeIntSpeed(unsigned char *buf); unsigned int DeserializeIntDistance(unsigned char *buf); private: std::string m_address; int m_port; struct sockaddr_in m_server; unsigned char m_recvBuff[8]; unsigned int m_IntSpeed; float m_result; int m_shift; unsigned int m_bias; unsigned int m_significantbits; unsigned int m_value; }; #endif // TCP_SOCKETCLIENT_H
mainwindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" #include "TCP_SocketClient.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->DistanceButton, SIGNAL(clicked()), ui->lcdDistance, SLOT(setDecMode())); connect(ui->SpeedButton, SIGNAL(clicked()), ui->lcdSpeed, SLOT(setDecMode())); } MainWindow::~MainWindow() { delete ui; } int MainWindow::on_DistanceButton_clicked() { /*TCP Socket object*/ MainWindow TCP_Socket; /*HRLVEZ0 data structure*/ HRLVEZ0_Data_t Data; if(TCP_Socket.RecieveSocketData(&Data) == false) return 1; ui->lcdDistance->display(Data.distance); return 0; } int MainWindow::on_SpeedButton_clicked() { /*TCP Socket object*/ MainWindow TCP_Socket; /*HRLVEZ0 data structure*/ HRLVEZ0_Data_t Data; if(TCP_Socket.RecieveSocketData(&Data) == false) return 1; ui->lcdSpeed->display(Data.speed); return 0; } int MainWindow::on_QuitButton_clicked() { MainWindow TCP_Socket; if(TCP_Socket.SendQuitCommand() == false) { std::cout << "Couldn't sent the quit command!\n" << std::endl; return 1; } return 0; } int MainWindow::on_ConnectButton_clicked() { MainWindow TCP_Socket; if(TCP_Socket.CreateSocket() == false) { std::cout << "Couldn't connect to the socket!\n" << std::endl; return 1; } return 0; }
mainwindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "TCP_SocketClient.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow, public TCP_SocketClient { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: int on_DistanceButton_clicked(); int on_SpeedButton_clicked(); int on_QuitButton_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
main.cpp:
#include "mainwindow.h" #include <QApplication> #include "TCP_SocketClient.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; if(w.CreateSocket() == false) return 0; w.show(); return a.exec(); }
Firmware TCP_SocketServer:
int SendAndReceiveSocketData(void) { int on = 1; struct sockaddr_in server; struct pollfd fds[10]; int timeout, close_conn, rc; int end_server = FALSE, compress_array = FALSE; int socket_fd = -1, new_socket_fd = -1, len; unsigned char sendBuffer[BUFFERSIZE]; unsigned char recvBuffer[1]; int nfds = 1, current_size = 0, i, j; unsigned char *ptr; /*************************************************************/ /* Create IPV4 socket */ /*************************************************************/ socket_fd = socket(AF_INET , SOCK_STREAM , 0); if (socket_fd == -1) { perror("Could not create socket\n"); } /*************************************************************/ /* Allow socket descriptor to be reuseable */ /*************************************************************/ if(setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { perror("setsockopt error!\n"); close(socket_fd); exit(EXIT_FAILURE); } /*************************************************************/ /* Set socket to be nonblocking. All of the sockets for */ /* the incoming connections will also be nonblocking since */ /* they will inherit that state from the listening socket. */ /*************************************************************/ rc = ioctl(socket_fd, FIONBIO, (char *)&on); if(rc < 0) { perror("ioctl() error"); close(socket_fd); exit(EXIT_FAILURE); } /*************************************************************/ /* Bind the socket */ /*************************************************************/ memset(&server, '0', sizeof(server)); server.sin_addr.s_addr = inet_addr(CLIENT_ADDRESS); server.sin_family = AF_INET; server.sin_port = htons(PORT_NUMBER); if(bind(socket_fd, (struct sockaddr*)&server, sizeof(server)) < 0) { perror("Binding error!\n"); close(socket_fd); exit(EXIT_FAILURE); } /*************************************************************/ /* Set the listen back log */ /*************************************************************/ if(listen(socket_fd, 10) < 0) { perror("Listen error!\n"); close(socket_fd); exit(EXIT_FAILURE); } /*************************************************************/ /* Initialize the pollfd structure */ /*************************************************************/ memset(fds, 0 , sizeof(fds)); /*************************************************************/ /* Set up the initial listening socket */ /*************************************************************/ fds[0].fd = socket_fd; fds[0].events = POLLIN; /*************************************************************/ /* Initialize the timeout to 3 minutes. If no */ /* activity after 3 minutes this program will end. */ /* timeout value is based on milliseconds. */ /*************************************************************/ timeout = (2 * 60 * 1000); /*************************************************************/ /* Loop waiting for incoming connects or for incoming data */ /* on any of the connected sockets. */ /*************************************************************/ do { /***********************************************************/ /* Call poll() and wait 2 minutes for it to complete. */ /***********************************************************/ printf("Waiting on poll()...\n"); rc = poll(fds, nfds, timeout); /***********************************************************/ /* Check to see if the poll call failed. */ /***********************************************************/ if(rc < 0) { perror(" poll() failed"); break; } /***********************************************************/ /* Check to see if the 3 minute time out expired. */ /***********************************************************/ if(rc == 0) { printf("poll() timed out. End program.\n"); break; } /***********************************************************/ /* One or more descriptors are readable. Need to */ /* determine which ones they are. */ /***********************************************************/ current_size = nfds; for(i = 0; i < current_size; i++) { /*********************************************************/ /* Loop through to find the descriptors that returned */ /* POLLIN and determine whether it's the listening */ /* or the active connection. */ /*********************************************************/ if(fds[i].revents == 0) continue; /*********************************************************/ /* If revents is not POLLIN, it's an unexpected result, */ /* log and end the server. */ /*********************************************************/ if(fds[i].revents != POLLIN) { printf(" Error! revents = %d\n", fds[i].revents); end_server = TRUE; break; } if(fds[i].fd == socket_fd) { /*******************************************************/ /* Listening descriptor is readable. */ /*******************************************************/ printf(" Listening socket is readable\n"); /*******************************************************/ /* Accept all incoming connections that are */ /* queued up on the listening socket before we */ /* loop back and call poll again. */ /*******************************************************/ do { /*****************************************************/ /* Accept each incoming connection. If */ /* accept fails with EWOULDBLOCK, then we */ /* have accepted all of them. Any other */ /* failure on accept will cause us to end the */ /* server. */ /*****************************************************/ new_socket_fd = accept(socket_fd, NULL, NULL); if(new_socket_fd < 0) { if (errno != EWOULDBLOCK) { perror(" accept() failed"); end_server = TRUE; } break; } /*****************************************************/ /* Add the new incoming connection to the */ /* pollfd structure */ /*****************************************************/ printf(" New incoming connection - %d\n", new_socket_fd); fds[nfds].fd = new_socket_fd; fds[nfds].events = POLLIN; nfds++; /*****************************************************/ /* Loop back up and accept another incoming */ /* connection */ /*****************************************************/ }while (new_socket_fd != -1); } /*********************************************************/ /* This is not the listening socket, therefore an */ /* existing connection must be readable */ /*********************************************************/ else { printf(" Descriptor %d is readable\n", fds[i].fd); close_conn = FALSE; /*******************************************************/ /* Receive all incoming data on this socket */ /* before we loop back and call poll again. */ /*******************************************************/ do { /*****************************************************/ /* Receive data on this connection until the */ /* recv fails with EWOULDBLOCK. If any other */ /* failure occurs, we will close the */ /* connection. */ /*****************************************************/ rc = recv(fds[i].fd, recvBuffer, sizeof(recvBuffer), 0); if(rc < 0) { if (errno != EWOULDBLOCK) { perror(" recv() failed"); close_conn = TRUE; } break; } /*****************************************************/ /* Disconnect when received the quit command */ /* character "Q" from the UI */ /*****************************************************/ if(recvBuffer[0] == 'Q') { printf("Disconnecting the socket connection...!\n"); close_conn = TRUE; end_server = TRUE; break; } /*****************************************************/ /* Check to see if the connection has been */ /* closed by the client */ /*****************************************************/ if(rc == 0) { printf(" Connection closed\n"); close_conn = TRUE; break; } /*****************************************************/ /* Data was received */ /*****************************************************/ len = rc; printf("%d bytes received\n", len); /*****************************************************/ /* Read the HRLVEZ0 data and send the data */ /* to the client when received character "S" */ /*****************************************************/ if(recvBuffer[0] == 'S') { HRLVEZ0_Data_t HRLVEZ0_Data; measureHRLVEZ0_Data(&HRLVEZ0_Data); //Serialize data before sending it through socket ptr = Serialize_Struct(sendBuffer, &HRLVEZ0_Data); rc = send(fds[i].fd, sendBuffer, ptr - sendBuffer, 0); if(rc < 0) { perror("send() failed"); close_conn = TRUE; break; } else { printf("\nSent %d bytes data\n", rc); recvBuffer[0] = 0; } } } while(TRUE); /*******************************************************/ /* If the close_conn flag was turned on, we need */ /* to clean up this active connection. This */ /* clean up process includes removing the */ /* descriptor. */ /*******************************************************/ if(close_conn) { close(fds[i].fd); fds[i].fd = -1; compress_array = TRUE; } } /* End of existing connection is readable */ } /* End of loop through pollable descriptors */ /***********************************************************/ /* If the compress_array flag was turned on, we need */ /* to squeeze together the array and decrement the number */ /* of file descriptors. We do not need to move back the */ /* events and revents fields because the events will always*/ /* be POLLIN in this case, and revents is output. */ /***********************************************************/ if (compress_array) { compress_array = FALSE; for (i = 0; i < nfds; i++) { if (fds[i].fd == -1) { for(j = i; j < nfds; j++) { fds[j].fd = fds[j+1].fd; } i--; nfds--; } } } } while (end_server == FALSE); /* End of serving running. */ return 0; }
I am beginner in Qt programming. I appreciate if you can help me with this problem. Thank you in advance.
-
hi
You seems to use linux sockets ?
and not the ones provided with Qt
http://www.bogotobogo.com/Qt/Qt5_QTcpSocket_Signals_Slots.php
Not that linux sockets are bad but
qt offers signal and smoother integration to the rest of the GUI.
Anyway, using linux sockets, one would normally use select to wait for new data
http://stackoverflow.com/questions/4789377/using-select-to-waiting-for-data-on-a-client-socket -
Thank you for the quick reply!
Yes I am using Linux sockets. Ok, I will try with that select method. -
@lihakimpale
I found his samples to be good
http://www.tenouk.com/Module41.html
He also has one for the client that uses select.Note: if you call select from GUI thread, you might
hang/lag it. (never tried mixing linux sockets and qt) -
Thank you for the reply!
I made some research and I found out that poll() function is quite same as select() but would be slightly better choice. Do you have any thoughts or knowledge about that? -
@lihakimpale said:
poll()
Actually you are totally right. if you system has poll, it's better than select.
Im just a bit old school so select always comes first to mind :) -
I am having little problems at the moment. I am able to poll just one time and then it closes the socket because it doesn't poll the receive. Now it polls the connect and when I press the connect button in the UI it connects to the socket but after that it doesn't poll anymore the receive and because the recv function returns 0 it will close the connection.
At first I had the the connection to the socket just at the beginning of the main function and not under a widget button. With that way I could get the connection work and could send and receive the data once and after that it began not to poll the receive anymore and again because the recv function returns 0 it will close the connection.
I edited the main post codes also with the firmware TCP socket server code.
Hope you can help me because I don't have a clue.
-
This problem seems to be related to the Qt because it polls normally outside the Qt.
-
@lihakimpale
Hmm. I have really no idea what that could be.
Its pure linux sockets so Qt should not affect it.
When i works "out of Qt" do you also create socket, then try to read and then delete it as the button does`? -
The problem was that I created new object of the class beginning of the function so at the end of the function that object will go out of scope and destructor is called where I had the close function for the global socket file descriptor.
I am still little newbie with C++. So when class is derived from another class I can call the certain method in the parent class without creating any objects of the derived class like in this case I can call the method like this: TCP_SocketClient::SendAndReceiveSocketData();