Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
The below code has a TCP client in C and TCP Server in Qt C++. My problem is that I am using TCP for reliability, but it has data losses (not packet). In my main code, if I run tcp client to send data, TCP server receives only one packet. if I add sleep(1); to the client between each packet transfer, then TCP server receives data. Both client and server runs on the same computer.
To simplify the question and can't put too huge code here, I have the below code that performs faster, but it losses last 10-15 bytes of the packet.
TCP C client
main.c
#include "socket_handler.h" //I didn't put the all includes here
#define PORT 22208
//tcp server
int main(void)
{
int sockfd;
uint32_t senderAddress = 2130706433; //127.0.0.1
if( connect_to_server_w_uint( &sockfd, senderAddress, PORT ) < 0 ){
printf("error at line 454\n");
exit(1);
}
char data[] = "124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22 03:01:00$0000-00-00 00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$2$0£";
char buffer[512];
int i=0;
for(i=0; i<1000; i++){
bzero(buffer, 512);
sprintf(buffer, "%d***%s -----",i,data);
send_data_to_server(&sockfd, buffer, strlen(data) +1 );
printf("[%d]: data is sent\n", i);
}
close_connection(&sockfd);
return 0;
}
socket_handler.c
int connect_to_server(int *sockfd , struct in_addr senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0)
//error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = senderAddress;
serv_addr.sin_port = htons(destPort);
if (connect( *sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
printf("connection error line 1413\n");
close( *sockfd );
return -1;
}
return 0;
}
int connect_to_server_w_uint(int *sockfd, uint32_t senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0){
printf("ERROR opening socket");
close(*sockfd);
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(senderAddress);
serv_addr.sin_port = htons(destPort);
if (connect(*sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
printf("ERROR connecting");
close(*sockfd);
return -1;
}
return 0;
}
int send_data_to_server(int *sockfd, char *message, uint16_t msgLength){
int n = write(*sockfd, message, msgLength);
if (n < 0){
printf("ERROR writing to socket");
return -1;
}
return 0;
}
int close_connection(int *sockfd){
close( *sockfd );
return 0;
}
Qt C++ TCP Server
MainWindow.cpp
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void ParseThePacket(QByteArray data);
private:
Ui::MainWindow *ui;
Server *server;
};
Client.h
class Client : public QObject
{
Q_OBJECT
public:
explicit Client(QObject *parent = 0);
public slots:
bool connectToHost(QString host);
bool writeData(QByteArray data);
private:
QTcpSocket *socket;
};
Server.cpp
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
if( server->listen(QHostAddress::Any, PORT) ){
qDebug() << "tcp server started!";
}else{
qDebug() << "tcp server couldn't start listening";
}
}
void Server::newConnection()
{
qDebug() << "new connection";
while (server->hasPendingConnections())
{
socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
}
}
void Server::disconnected()
{
qDebug() << "disconnected";
socket->deleteLater();
}
void Server::readyRead()
{
qDebug() << "readyRead";
QByteArray buffer = socket->readAll();
emit dataReceived(buffer);
}
Here is an example output from the TCP server(the end of qDebug() output):
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$996***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$997***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$998***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$999***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$"
disconnected
Question 1
Comparing to the original message, it misses "1$0$e6$d3$2$0£" part of the (14 byte) sent data. What is the reason of the missing message? How to fix the code that the TCP server receives the complete data.
Question 2
As I mentioned in the beginning that I am using the same code as a part of a large code and TCP server receives packets when I put sleep(1) between each packet transmission (otherwise it receives only the first packet). What is the reason of it and how to solve it?
I observed the packet transmission on Wireshark that all the TCP packets are sent successfully, but it seems like the receive part has an issue.
I am using Ubuntu 15.04, kernel 3.19.0-69-generic, gcc version 4.9.2
int n = write(*sockfd, message, msgLength);
if (n < 0){
You are only checking that write() did not return a negative value, indicating an error.
However, a write() to a socket does not guarantee that all requested bytes will be written. write() on a socket may return a positive value, fewer than msgLength here, indicating that fewer than the requested bytes have been written. This is documented, in detail, in write()'s manual page.
You are ignoring this possibility, and that's the likely reason you're missing your data. It's up to you to figure out what to do, in this case. The usual approach is to simply go back and attempt to write the remaining bytes (which, again, may not be written in their entirety).
Similarly, when reading from a socket, you are not guaranteed that everything that was written to the socket, by the sender, will be read in one gulp. It is up to you to verify that your reader has read everything that there is to read, and if the reader expects more data, continue reading from the socket until it is received.
readAll just reads all data available to the current moment.
Related
I'm working on a project in Qt Creator 6.3 and I'm programming it in C++. The program uses a GUI, threads and works like a client.
I need to make a TCP/IP connection using a socket to connect to the server. I have seen several tutorials and in all of them they use the connect function to connect to the server. In all tutorials, this function is used in the main.cpp.
The problem is that I need to make this conection in the GUI and not in the main.cpp. But, when I try to use the connect method the program confuses this method with the connect method that uses slots and signals as an argument. Is there a way to tell the program which connect I want to use?
I need to make the connection in the GUI because I have threads that need to receive data from the socket and save it in variables that are from the GUI.
I need something like this:
int main(int argc, char *argv[]){
QApplication a(argc, argv);
RadarGUI w; //this is the GUI
w.show();
return a.exec();
}
In radargui.cpp a function that makes the connections with the socket
void RadarGUI::conectar_servidor(){
std::string ip= "127.0.0.1";
int port=2020;
//winsock
WSAData data;
WORD version= MAKEWORD(2,2);
int wsResultado= WSAStartup(version, &data);
if (wsResultado != 0){
printf("fallo inicializacion de winsock del cliente");
}
//socket
SOCKET sock = socket(AF_INET,SOCK_STREAM,0);
if (sock== INVALID_SOCKET){
printf("fallo creacion del socket del cliente");
WSACleanup();
}
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ip.c_str(), &hint.sin_addr);
//connect to server, HERE IS THE PROBLEM
int conectarResultado = connect(sock, (sockaddr*)&hint, sizeof(hint)); //the program think
//that this function needs signal and slot
if (conectarResultado != SOCKET_ERROR){
printf("el cliente no pudo conectarse al servidor");
closesocket(sock);
WSACleanup();
}
}
The error related to the connect method:
No matching member function for call to 'connect'
candidate function not viable: no known conversion from 'SOCKET' (aka 'unsigned long long') to 'const QObject *' for 1st argument
I have copied the chat-example from the boost examples.
server code:
https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/chat/chat_server.cpp
chat_message.hpp: https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/chat/chat_message.hpp
client code: https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/chat/chat_client.cpp
In chat_server.cpp, I have added a cout in chat_room::leave to get notified when a client leaves. In chat_server, I tried to configure TCP keepalive according to this SO answer:
// additional includes that I have added
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ws2spi.h>
#include <mstcpip.h>
#include <windows.h>
// ----
class chat_server {
public:
chat_server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint)
: acceptor_(io_service, endpoint),
socket_(io_service) {
do_accept();
}
private:
void do_accept() {
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec) {
if(!ec) {
unsigned long val = 1;
int res = setsockopt(socket_.native_handle(), SOL_SOCKET, SO_KEEPALIVE, (char*) &val, sizeof val);
if(res) std::cout << "Can't set sockopt!" << std::endl;
tcp_keepalive alive;
alive.onoff = TRUE;
alive.keepalivetime = 1000;
alive.keepaliveinterval = 1000;
DWORD bytes_ret = 0;
res = WSAIoctl(socket_.native_handle(), SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0,
&bytes_ret, NULL, NULL);
if(res) std::cout << "Can't set TCP keepalive!" << std::endl;
std::make_shared<chat_session>(std::move(socket_), room_)->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
chat_room room_;
};
My test setup is to run the server on my local machine. The client runs on a "VMware Workstation 15 Player"-virtual machine, where NAT is used as network adapter. When I connect to the server and uncheck the "Connected"-checkbox in Virtual Machine Settings (should be the same as unplugging the network cable), I would expect to see the output of chat_room::leave in the console, but it seems, that the server even after a few minutes thinks that the client is still connected.
How can I configure the TCP keepalive appropriately? (I would prefer a cross-platform solution which works on Linux too, but if it works on windows, it's better than nothing)
Edit: I have monitored the sent data with Wireshark and found out that no keep-alive packets were sent. What could cause this?
I have a program that sends and receives broadcast messages. If I run two copies of these programs on the same PC, everything works just fine. If I run each copy on different PCs, then the broadcast messages are not received. I utilized Wireshark to verify whether the packets were sent (yes they were). In addition, on PC "A" Wireshark does not observe the sent packets, but on PC "B" everything is OK. Could the problem be in hardware?
Receiver code:
Receiver::Receiver(QObject *parent) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(45454, QUdpSocket::ShareAddress);
timer = new QTimer(this);
timer->start(500);
connect(timer, SIGNAL(timeout()), this, SLOT(processPendingDatagrams()));
}
void Receiver::processPendingDatagrams()
{
qDebug("first entrance");
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
qDebug() << datagram.data();
qDebug("Receive");
sendToQML(datagram.data());
}
}
Sender code:
Sender::Sender(QObject *parent) : QObject(parent)
{
messageNo = 0;
udpSocket = new QUdpSocket(this);
}
void Sender::broadcastDatagram(int message)
{
QByteArray datagram = QByteArray::number(message);
udpSocket->writeDatagram(datagram.data(), datagram.size(),
QHostAddress::Broadcast, 45454);
}
void Sender::sendBroadcast(int message)
{
qDebug() << message;
broadcastDatagram(message);
}
UPDATE
I managed to send and receive packets through an ethernet connection (via a cable).
I have problem with QUdpSocket. I want to create a simple program to send and receive data using the UDP protokol. I already read many similar topic but I do not found solved. Communication worked only for QHostAdress::LocalHost, then I give this same data as send, but if I want to send data to outside set concrete address, for example 194.181.161.134, that does not worked. That mean data is send but I can't receive. This is my code:
class Okno_GL : public QMainWindow
{
Q_OBJECT
public:
explicit Okno_GL(QWidget *parent = 0);
QWidget *wg;
QPushButton *pb;
QPushButton *pl;
QGridLayout *gr;
QUdpSocket *socket;
QHostAddress host;
QHostAddress bcast;
signals:
public slots:
void SLOT_Write();
void SLOT_load();
};
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver();
QUdpSocket *udpSocket;
public slots:
void SLOT_processPendingDatagrams();
void SLOT_StCh(QAbstractSocket::SocketState state);
};
Okno_GL::Okno_GL(QWidget *parent) :
QMainWindow(parent)
{
pb = new QPushButton("write" , this);
pl = new QPushButton("read" , this);
wg = new QWidget(this);
setCentralWidget(wg);
gr = new QGridLayout(wg);
gr->addWidget(pb);
gr->addWidget(pl);
socket = new QUdpSocket(this);
connect(pb , SIGNAL(clicked()) , SLOT(SLOT_Write()));
connect(pl , SIGNAL(clicked()) , SLOT(SLOT_load()));
}
void Okno_GL::SLOT_Write()
{
QByteArray datagram = "gS";
int send;
send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
}
void Okno_GL::SLOT_load()
{
}
Receiver::Receiver()
{
udpSocket = new QUdpSocket(this);
connect(udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this , SLOT(SLOT_StCh(QAbstractSocket::SocketState)));
if(udpSocket->bind(QHostAddress::Any , 1200))
{
qd "bind";
}
else
{
qd "not bind";
}
}
void Receiver::SLOT_processPendingDatagrams()
{
qd "receiver";
QByteArray datagram;
do {
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
} while (udpSocket->hasPendingDatagrams());
qd "datagram" << datagram;
}
void Receiver::SLOT_StCh(QAbstractSocket::SocketState state)
{
qd "slot" << state;
QByteArray datagram = "gS";
if ( state == QAbstractSocket::BoundState ) {
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(SLOT_processPendingDatagrams()) , Qt::QueuedConnection);
}
}
You should use write() instead of writeDatagram()
qint64 QUdpSocket::writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port)
Warning: Calling this function on a connected UDP socket may result in
an error and no packet being sent. If you are using a connected
socket, use write() to send datagrams.
So, I rebuild my code accordingly with your proposition. I add this line in construktor class Okno_GL.
socket = new QUdpSocket(this);
socket->connectToHost(QHostAddress("194.181.161.134") , 1200);
Here is slot to send
void Okno_GL::SLOT_Write()
{
QByteArray datagram = "gS";
int send;
// send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
send = socket->write(datagram);
qd " send" << send;
}
Receiver code is not change, so I still white for signal readRedy() ,and I do not get him after send data.
PS. I whant to add that I have other option to connetc, is very very simply file command *bat whitch connect this host without any problem . This is proof that my network or admin nothing blocks (port , ip);
Pss thanks for your interest
Problem solved ! It is very stupid mistake. I should be send 3 bajt instead 2. The 3 bajt it is 0x0D.
Following code is work
socket = new QUdpSocket(this);
socket->bind(QHostAddress::Any, 1200);
and send
QByteArray datagram = "gS";
datagram.append(0x0D);
int send;
send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
and receive after signal readyRead()
qd "receiver";
QByteArray datagram;
do {
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size());
} while (socket->hasPendingDatagrams());
qd "datagram" << datagram;
very help mi wireshark. Thanks for all
I am developing a GUI using Qt for a test UDP server application i wrote in C using the sockets interface available in unix. I aim of the GUI is to display all the messages (perror and fprintf) in either a "text edit box" or "text browser box". Here is my code,
//-----------------------------Main.Cpp------------------------------------------//
//-----------------------------QT specific headers-------------------------------//
#include "mainwindow.h"
#include <QApplication>
#include <QLabel>
//------------------------------------------------------------------------------------//
int main(int argc, char *argv[])
{
int sock_fd=0;
funct_class funct_class_obj;
QApplication a(argc, argv);
MainWindow w;
sock_fd=funct_class_obj.udp_config();
funct_class_obj.recv_fucnt(sock_fd);
return a.exec();
}
//--------------------------------End of main.cpp------------------------------//
//-----------------------------mainwindow.cpp----------------------------------//
//-----------------------------QT specific headers-----------------------------//
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QLabel>
//-----------------------------------------------------------------------------//
//--------------------------------C program specific headers------------------//
#include <stdio.h>
#include <stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
//---------------------------------------------------------------------------//
unsigned char message[50];
QString mystr;
int funct_class:: udp_config()
{
int sock_fd=0;
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
perror("\nError creating socket\n");
//mystr = "\nError creating socket\n";
else
{
fprintf(stdout, "\nSuccessfully created socket with descriptor:%d\n", sock_fd);
//mystr = "Successfully created socket";
struct sockaddr_in sock_addr = {0};
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(PORT);
if (inet_aton("127.0.0.1", &sock_addr.sin_addr) < 0)
perror("\nError converting destination IP address from dotted decimal to binary\n");
// mystr = "Error converting destination IP address from dotted decimal to binary";
else
{
if (bind(sock_fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) // Bind function call binds the properties assigned above to the socket created earlier
perror("\nError binding the port and IP address with the socket\n");
//mystr = "Error binding the port and IP address with the socket";
else
fprintf(stdout, "\nBinding port and IP address successful\n");
// mystr = "Binding port and IP address successful";
}
}
return sock_fd;
}
void funct_class:: recv_fucnt(int sock_fd)
{
struct sockaddr_in recv_sockaddr = {0};
socklen_t recv_sockaddr_len = sizeof(recv_sockaddr);
int recv_data=0;
if ((recv_data = recvfrom(sock_fd, message, sizeof(message), 0x00, (struct sockaddr*)&recv_sockaddr, &recv_sockaddr_len)) <= 0)
perror("\nError receiving data/no data received\n");
//mystr = "Error receiving data/no data received";
else
fprintf(stdout, "\nSuccessfully received %d bytes of data\n", recv_data);
fprintf(stdout, "\nData is :%s", message);
//mystr = "Successfully received data";
mystr = QString::fromStdString((const char*)message);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->testedit->setText(mystr);
//ui->mytextbrowser->setText((mystr));
}
MainWindow::~MainWindow()
{
delete ui;
}
//-----------------------------End of mainwindow.cpp---------------------------//
//------------------------------------mainwindow.h-----------------------------//
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#define PORT 5030
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
class funct_class{
public:
int udp_config();
void recv_fucnt(int sock_fd);
};
#endif // MAINWINDOW_H
//-------------------------------End of mainwindow.h-----------------------------//
The application is compiling fine, but i am facing problems when i execute it. It just freezes and even if i manage to get it out from freeze, i am not able to display the required string either in the "text edit box" or "text browser box". Please help.
P.S.: I am a newbie to GUI programming and Cpp.
The issue seems to be pretty clear:
ui->testedit->setText(mystr);
This is only called in the constructor and nowhere else. That means, when your mystr is updated, the widget will not be aware of it. It does not work like you seem to expect; it is not a one-time property binding so that the widget will be be notified automatically and transparently when the string changes. You have to do that work on your own.
Beside, you really ought to aim for using QtNetwork in a Qt based client rather than platform specific POSIX API with BSD sockets.