I apologize, I was not sure how to deliver a concise title for this issue.
Background: I am using QTcpSocket to connect to a PLC Simulator application. Previously I was using PLCQTLIB to connect to the simulator and everything was working fine. The library did not offer enough functionality for my project so I have created my own library for interfacing Qt with the libnodave library.
The simulator runs on IP Address 192.168.32.1 and Port 102
Current Issue: I enter the IP (192.168.32.1) and Port (102) and press connect. I receive:
TCP Error = QAbstractSocket::ConnectionRefusedError
TCP Error = QAbstractSocket::SocketTimeoutError
If I change the port to 80 and press connect, the connection is successful. However the connection to the PLC Simulator will fail because it is not listening on Port 80.
Now that a successful connection has been established to 192.168.32.1 and the current state of the connection is disconnected, I can enter the correct port 102 and connect successfully.
Question: Why does the TCP Socket not establish a connection to Port 102 until after a connection has been previously opened on Port 80? No firewalls exist and all communication is occurring on the local machine.
Declared in Header:
QTcpSocket *tcp;
Source File:
PLCLibNoDave::PLCLibNoDave()
{
tcp = new QTcpSocket();
connect(tcp, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(tcpStateChanged(QAbstractSocket::SocketState)));
connect(tcp, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(tcpErrorHandler(QAbstractSocket::SocketError)));
connect(tcp, SIGNAL(hostFound()), this, SLOT(tcpHostFound()));
connect(tcp, SIGNAL(connected()), this, SLOT(tcpConnected()));
connect(tcp, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
}
void PLCLibNoDave::connectTCP(int port, QString ip)
{
tcp->connectToHost(ip,port);
if(!tcp->waitForConnected(3000)){
tcp->disconnectFromHost();
return;
}
tcpHandle = tcp->socketDescriptor();
if(tcpHandle == -1){
tcp->disconnectFromHost();
qDebug() << "Invalid Socket Descriptor on Connect";
return;
}
return;
}
void PLCLibNoDave::disconnectTCP()
{
tcp->disconnectFromHost();
if(tcp->state() == QAbstractSocket::UnconnectedState ||
tcp->waitForDisconnected(1000)){
tcpError = tcp->error();
}
else{
tcpError = tcp->error();
qDebug() << "Disconnect Failed: " << tcp->errorString();
}
return;
}
Related
I search an example to open multiple serial ports in qt.
My open port function settings forward from other class
void MainWindow::openSerialPort(){
SettingsDialog::Settings p = settings->settings();
serial->setPortName(p.name);
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
if (serial->open(QIODevice::ReadWrite)) {
ui->connectAction->setEnabled(false);
ui->disconnectAction->setEnabled(true);
ui->settingsAction->setEnabled(false);
showStatusMessage(tr("Connected to %1 : OK")
.arg(p.name));
} else { //gdy sie nie udalo error
QMessageBox::critical(this, tr("Error"), serial->errorString());
showStatusMessage(tr("Open error"));
}
}
As far as I remember single instance of QSerialPort if opened does it exclusively so no other instance has access to this port. I guess creating other QSP and opening other port would do the thing.
actually i have Qt code. so i need to send data of packets from serial port to terminal and display the data in terminal and also from terminal i need to read data and display it in Qt window page. main problem is, for serial communication to terminal, does we really require serial port should connect to some hardware devices and also.. can we write and read data to terminal without connecting any serial port to hardware devices.
the code from Transceiver layer to serial port
Transceiver::Transceiver(QObject *parent)
:
QObject(parent),
mSerial(new QSerialPort(this))
{
mSerial->setPortName(QString("COM1"));
qint32 baudRate = 9600;
mSerial->setBaudRate(baudRate);
mSerial->setDataBits(QSerialPort::Data8);
mSerial->setParity(QSerialPort::NoParity);
mSerial->setStopBits(QSerialPort::OneStop);
connect
(
mSerial,
&QSerialPort::readyRead,
[ this ]()
{
QByteArray data = mSerial->readAll();
OnDataReceived( data );
qDebug()<<data;
}
);
}
Transceiver::~Transceiver()
{
mSerial->close();
}
void
Transceiver::Send_Data(const QByteArray & inDataStream )
{
qDebug()<<"Data_in_Transceiver_layer :"<<inDataStream;
mSerial->write(inDataStream);
}
bool
Transceiver::OpenConnection()
{
mSerial->open(QIODevice::ReadWrite);
QSerialPort::SerialPortError error = m`enter code here`Serial->error();
return error == QSerialPort::NoError;
// connect(mSerial, SIGNAL(readyRead()), this, SLOT(read_data()));
}
when i run this it shows
QIODevice::write (QSerialPort): device not open
I have a simple sketch on my Seeeduino Mega 1.22 which just displays the serial input on a LCD Display. Using lynx term and the arduino serial monitor works fine: sent input is being displayed. The trouble starts when I want to start serial communication between my Java programm, running in Eclipse on a Win7 x64 machine, and the Seeeduino. I'm using the RXTX x64 build. The programm is intended to send and receive some string.getBytes() via the open port. Receiving on the Java side works, but receiving on the Arduino side fails.
It seems that the problem is the proper Flow Control setting. I saw that some people had the same issue like here Issues receving in RXTX
But this solution does not work for me. If I set the FlowControl to None, than I get only a block icon on the display, indicating, that the serial connection has been established, but nothing else. If I set the FlowControl to RCTS_IN | RCTS_OUT, then I get the string bytes only on the display when I close the established connection.
Why is the data only send when I close the connection (Flushing the out stream did not help as well) ? What am I doing wrong with the Flow Controll settings?
This is the modified connect() method I'm using.
void connect(String portName) throws Exception {
CommPortIdentifier portIdentifier = CommPortIdentifier
.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Error: Port is currently in use");
} else {
CommPort commPort = portIdentifier.open(this.getClass().getName(),
2000);
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
try {
serialPort.setFlowControlMode(
// SerialPort.FLOWCONTROL_NONE);
// OR
// If CTS/RTS is needed
//serialPort.setFlowControlMode(
SerialPort.FLOWCONTROL_RTSCTS_IN |
SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException ex) {
System.err.println(ex.getMessage());
}
serialPort.setRTS(true);
in = serialPort.getInputStream();
out = serialPort.getOutputStream();
(new Thread(new SerialWriter(out))).start();
serialPort.addEventListener(new SerialReader(in, this));
serialPort.notifyOnDataAvailable(true);
} else {
System.out.println("Error: Only serial ports are to use!");
}
}
}
Thanks in advance for your time
Solved it. It was not the buffer, as many suggested it. The problem was, that the Seeeduinos RST Switch on the board was set to automatic. Setting it to manual, solved the problem.
No Flow-Controll needed.
I have a project that uses TCP sockets to communicate between a server and one client. As of now I have been doing this on one computer so I have just used local address of "127.0.0.1" for the address to bind and connect to on both sides and its worked fine. Now I have a second computer to act as a client, but I don't know how to change the addresses accordingly. They are connected through a network that is not connected to the Internet. Before the code looked like this -
Server -
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET; //local address
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
return false;
}
//make socket
fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (fd < 0) {
printf("\nserver socket failure %m", errno);
return false;
}
//allow reuse of port
int yes=1;
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*) &yes,sizeof(int)) == -1) {
perror("setsockopt");
return false;
}
//unlink and bind
unlink("127.0.0.1");
if(bind (fd, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
return false;
}
Client -
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET; //local address
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
return false;
}
//make socket
fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (fd < 0) {
printf("\nserver socket failure %m", errno);
return false;
}
//connect
if(connect(fd, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
return false;
}
I know it should be simple, but I can't figure out how to change the IPs to get them to work. I tried setting the server computer's IP address in the quotes in these lines -
if ((status = getaddrinfo("127.0.0.1", port, &hints, &servinfo)) != 0)
and
unlink("127.0.0.1");
and then change the address in the client code to the client computer's IP address in this line -
if ((status = getaddrinfo("127.0.0.1", port, &hints, &servinfo)) != 0)
Whenever I do that, it tells me connection refused. I have also tried doing the opposite way of putting the server's address in the client's line and client's address in the server's lines along with a few other attempts. At this point I feel like I am just guessing though. So can someone please help me understand how to change this from using the local address with one computer to connecting two computers? Any help is appreciated.
First, unlink("127.0.0.1"); is totally wrong here, don't do that.
Then, you have two computers connected by some network. Both should have IP addresses. Replace 127.0.0.1 with the server's IP address in both client and the server. The server does not to have to know client's address beforehand - it'll get that information from the accept(2) call. The client needs server's address to know where to connect. The server needs its own address for the bind(2) call.
The main problem is that your putting AI_PASSIVE in your client code. AI_PASSIVE is meant for servers only (that's what it signals).
Also on the server side you should first of all not call unlink. That's for AF_UNIX sockets only, not AF_INET. Secondly you don't need to put "127.0.0.1" in the getaddrinfo line on the server side. It's better to use NULL to bind to all available addresses.
If you change those things, I believe your code should work. However you're actually supposed to loop on the getaddrinfo result using the ai_next pointer and try to connect to each result, using the first that succeeds.
Connection Refused usually means your client received a RST to his SYN. This is most often caused by the lack of a listening socket on the server, on the port you're trying to connect to.
Run your server
On the CLI, type netstat -ant. Do you see an entry that's in LISTEN state on your port?
Something like:
tcp4 0 0 *.3689 *.* LISTEN
I bet you do not, and therefore have a problem with your server listening socket. I also bet the changes you made this this line:
if ((status = getaddrinfo("127.0.0.1", port, &hints, &servinfo)) != 0) {
Weren't quite right. Try changing that IP to 0.0.0.0 on the server to tell it to to bind to any IP on the system. On the client, that line should have the IP address of the server. You should also remove the unlink() call in the server; unnecessary.
If you do have a listening socket, then there's probably a firewall or something in between your boxes that's blocking the SYN. Try typing service iptables stop on the CLI of both systems.
I am working on Ubuntu 9.04. I am running this on VMware workstation. Here is my C code:
int sockfd,cnt,addrlen;
const int on = 1;
struct sockaddr_in servaddr,cliaddr;
char reply[512];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR, &on,sizeof(on));
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliaddr.sin_port = htons(68);
addrlen = sizeof(servaddr);
if (bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0) {
perror("bind");
exit(1);
}
while(1)
{
cnt = recvfrom(sockfd, reply, sizeof(reply), 0,(struct sockaddr *) &servaddr, &addrlen);
if (cnt < 0) {
perror("recvfrom");
exit(1);
}
printf("\nReply Received\n");
}
I run this program in one terminal and run 'dhclient' on another. I receive no datagrams. What am I doing wrong?
Looks like you're listening on UDP port 68 for a broadcasted message from the client? If I'm reading DHCP correctly, the client will send its broadcase 'discover' request FROM UDP port 68, but TO UDP port 67 on the server, so you would need to be listening on port 67 to receive it.
An easy 'first' test to test you're code before trying it with dhclient would be to try talking to your server with netcat. a command line like
echo "Foo" | netcat -u localhost 68
Should cause a packet to be received by your current code.
Another good debugging tool is wireshark which will let you see exactly what UDP packets are being sent by dhclient and what they contain.
I'm not sure what you're doing wrong but if I were you I'd write my own client which is very simple and see if it can talk to your server code above (who knows what dhclient might do outside of contact your code). I'd also temporarily change the port number to something not well-known. This way I wouldn't be interfering with any other programs and interfaces.
I recommend this tutorial. Also, are you running as root? You can't get that low-numbered port otherwise.