部分ARM开发板中QTCPServer不能接受Socket连接


来自QQ群 Linux && 技术分享 311078264 
此文档由elikang整理,如有疑问请进群讨论。

部分ARM开发板中QTCPServer不能接受Socket连接

问题描述:

当Tcp服务器端在PC上运行,客户端在开发板上运行的情况下,可以正常通信。
当反过来,Tcp的客户端运行在开发板上等待客户端连接的时候却出现了问题。

在连接过程中,客户端显示已经连接成功了,但是服务器端却没有检测,说明连接过程存在问题;
而且服务器和客户端之间也不能通信。

下面是netstat显示的连接信息:
1、
TCP服务器端监听状态
file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/1.png



file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/2.png

2、
TCP客户端连接服务器
file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/3.png

TCP客户端断开连接
file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/4.png


===============================
在网上看到有位前辈这么说的,个人感觉关联不大:

##############################################
针对TQ部分ARM开发板中QTCPServer不能接受数据的问题 2016-04-19

这种现象在TQ6410和TQIMX6上会有,其他开发板不清楚。

这种问题是交叉编译器的BUG!(好坑啊,还以为是编译qt时配置出问题了)

解决办法是:
用4.3.3的交叉编译器,编译qt源码,再将编译的qt源码放到ARM中替换原来的qt源码(/opt/PDA/);
##########################################################

我使用的编译器是:
arm-none-linux-gnueabi-gcc 4.4.3版本

更换了arm-linux-gnueabi-gcc 4.7.3版本

之后问题依然存在,下面是我找到与accept()相关的QT底层的部分代码。


file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/5.png

错误就是由于socketEngine->accept()返回了-1才产生的,接下来继续寻找accept的相关代码:


file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/6.png

file://C:\Users\ADMINI~1\AppData\Local\Temp\ct_tmp/7.png

 见 qglog.h文件定义:   
    #define Q_D(Class) Class##Private * const d = d_func()
    #define Q_Q(Class) Class * const q = q_func()
    d指针是在主类中使用的,来获取 私有子类成员指针
   q指针是在私有数据类中使用的,来获取 主类对象指针

上面accept函数中的d是QSocks5SocketEnginePrivate的实例,由于返回了sd=-1,才产生了错误。


===============================================
通过两天时间的探索,并没有找到最终原因,只是定位了问题所在之处;
接下来决定采用一个替代方案来继续后面的操作,替代方案即是使用C语言来实现tcp的bind()、listen()和accept(),然后再将Socket传给Qt使用。
这种做法实质就是取代QTcpServer的功能,测试的效果还是蛮好的。



1、在头文件MainWindow.h中加入下面的声明:
public:
void server_listen();
signals:
void recvConnection(QTcpSocket *socket);
private slots:
void getConnection(QTcpSocket *socket);
void slot_disconnected();

2、在.cpp文件中实现
在构造函数中加入下面代码:
connect(this, SIGNAL(recvConnection(QTcpSocket *)), this, SLOT(getConnection(QTcpSocket *)));
server_listen(); 

server_listen()实现:
void MainWindow::server_listen()
{
ui->pushBtn_start->setDisabled(true);

int newsd, sd;
struct sockaddr_in laddr,raddr;
socklen_t raddr_len;

sd = socket(AF_INET,SOCK_STREAM,0/*IPPROTO_TCP,IPPROTO_SCTP*/);
if(sd < 0)
{
perror("socket()");
exit(1);
}

laddr.sin_family = AF_INET;
laddr.sin_port = htons(atoi("6678"));
inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);
if(bind(sd, (const sockaddr *)&laddr,sizeof(laddr)) < 0)
{
perror("bind()");
return;
}

if(listen(sd,200) < 0)
{
perror("listen()");
return;
}

raddr_len = sizeof(raddr);

while(1)
{
newsd = accept(sd,(sockaddr *)&raddr,&raddr_len);
if(newsd < 0)
{
if(errno == EINTR || errno == EAGAIN)
continue;
perror("accept()");
exit(1);
}

break;
}

QTcpSocket *socket = new QTcpSocket(this);
socket->setSocketDescriptor(newsd);//socketDescriptor

// or get socket_server directly
// socket_server->setSocketDescriptor(socketDescriptor);

emit recvConnection(socket);
}


getConnection实现:
void MainWindow::getConnection(QTcpSocket *socket)
{
socket_server = socket;
connect(socket_server, SIGNAL(disconnected()), this, SLOT(slot_disconnected()));
connect(socket_server, SIGNAL(readyRead()), this, SLOT(readMessage()));

ui->label_status->setText("Server:client connection get");
}

slot_disconnection()实现: 
void MainWindow::slot_disconnected()
{
ui->pushBtn_start->setDisabled(false);
ui->label_status->setText("Socket: disconnected");



当服务端运行起来之后,可以通过telnet来测试是否可以连接:
telnet 192.168.122.60 6678

按下'Ctrl+Alt+]', 可以离开当前状态,然后输入disconnect即可断开连接(在XShell中的操作,其它终端类似) 。










评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值