搜索
bottom↓
回复: 26

嵌入式Linux应用程序开发-(7)TCP-IP网络通信应用程序(TCP-...

[复制链接]

出0入0汤圆

发表于 2019-5-11 17:02:15 | 显示全部楼层 |阅读模式
基于TCP/IP的网络通信应用程序(TCP-Client)
        不管是嵌入式Linux应用程序,还是物联网IoT应用开发,网络通信一定是一个不可或缺的重要环节。
可以说,没有网络支持,整个物联网应用体系将产生不了社会价值,没有网络,很多应用程序都会受到限制。
作为全世界最优秀的开源操作系统,Linux内部已经集成了强大的网络协议栈,并向应用层提供丰富的系统调用,开发者可以基于通用的系统调用接口,使用Linux内核提供的网络功能。
如果要分析Linux内部的网络通信机制以及实现原理,相信不是一时半刻或片文只字能描述清楚,一般的应用开发者可以通过网上搜索资料去了解一下,但在初学阶段,不建议去深入研究。
因此,本章节只是站在应用开发的角度,描述如何开发嵌入式QT的网络应用程序。
        TCP/IP协议模型(Transmission Control Protocol/Internet Protocol),包含了一系列构成互联网基础的网络协议,是Internet的核心协议。
它是一种面向连接的、可靠的、基于字节流的传输协议。关于TCP/IP协议的具体实现原理,本文不进行描述(关于TCP/IP的实现原理描述,其复杂度已经可以用一本书来具体阐述了)。
本文着重描述在嵌入式QT环境下,如何使用TCP/IP进行数据通信。
对于TCP/IP的客户端(TCP-Client)角色,在进行数据通信之前,一般会经历以下过程:
(1)调用socket套接字函数,创建套接字的文件描述符。
(2)配置连接参数(需要连接的服务器IP,端口,连接协议,等等)。
(3)基于套接字的文件描述符,调用connect函数,连接指定的服务器。
(4)处理connect过程中可能出现的情况。(如连接成功,连接出错,找不到服务器等)
(5)connect成功后,调用数据发送接口,进行数据发送。
(6)调用数据接收接口,并处理接收到的网络数据。(Linux C语言开发,可以阻塞接收或使用select/poll机制接收。QT开发,可以使用信号槽机制进行接收。)
        使用嵌入式QT进行TCP/IP的网络通信应用程序开发,对于TCP客户端,只需要关注QT提供的QTcpSocket类,这个类继承于QAbstractSocket类,在QAbstractSocket类里面提供了一系列的网络操作接口函数,
如:连接服务器connectToHost()、断开与服务器的连接disconnectFromHost(),等等。提供各种信号(connected()、disconnected()、stateChanged())与槽函数,方便应用开发者调用。具体可以参阅 QtNetwork/qabstractsocket.h 文件的内容。

目标:使用QT提供的TCP/IP网络通信类,实现一个简单的TCP客户端(TCP-Client)
功能:
(1)开发板界面显示开发板的网络IP地址。
(2)可手动输入需要连接的服务器IP和端口。
(3)界面显示TCP客户端的连接状态。(连接成功,断开连接,连接出错)
(4)界面显示TCP客户端的收发数据,并提供清屏按钮。
(5)提供手动发送按钮和自动发送按钮。

实验现象初览:
服务器端的界面(在windows7运行的网络通信工具):

服务端界面描述:
(1)输入本机的服务端IP地址和端口,并开始侦听。笔者服务端是192.168.1.59:4418
(2)界面显示已经连接上的客户端IP地址,可以看出,跟imx6ul本机的IP一致。
(3)数据发送区1里面是服务端自动回复给客户端的内容,表示服务器端收到客户端的数据后,马上自动回复”reply_from_pc_to_imx6ul”。
(4)最底下显示接收到的客户端数据,从上图可以看出,客户端分别以自动方式和手动方式发送了数据

客户端的界面(在imx6ul上运行):

客户端界面描述:
(1)程序启动时,在界面右上角显示imx6ul本机的IP地址。
(2)填写客户端需要连接的服务器IP和端口。
(3)点击 [CONNECT] 按钮后,会在按钮后面显示连接的状态。
(4)点击 [START_AUTO_SEND] 后,客户端会自动以1秒的频率向服务器发送数据。
(5)每点击一次 [tcp_send_data] 按钮,客户端都会向服务器发送一次数据。
(6)在数据显示框显示客户端发送/接收到的数据内容。
(7)点击 [TX_CLEAR] 或 [RX_CLEAR] 进行清屏操作。

1、先用Qt Creator构建一个工程,命名为:007_tcp_client,关于如何构建工程,请参考“第一个嵌入式QT应用程序”的具体内容。

2、创建工程后,修改007_tcp_client.pro里面的内容,添加QT里面的网络通信模块network,使工程支持QT网络类的调用,如下图所示。


3、双击打开“widget.ui”文件,构建界面,构建后的界面如下图所示:

客户端界面描述如上面内容所示,这里不作重复。

4、创建一个tcp_client.h文件,编写一个TCP_Client类继承于QTcpSocket,TCP_Client类提供了一些客户端经常用的操作函数,如连接服务器,获取本机IP,处理连接状态,等等。类的具体实现如下图所示:
  1. #define TCP_CONNECTED        "CONNECTED"
  2. #define TCP_DISCONNECTED     "DISCONNECTED"
  3. #define TCP_CONNECT_ERROR    "CONNECT_ERROR"

  4. class TCP_Client : public QTcpSocket
  5. {
  6.     Q_OBJECT

  7. public:
  8.     TCP_Client(QObject* parent=0);
  9.     ~TCP_Client();

  10.     QString get_local_ipaddr(void);   //获取本机的IP地址
  11.     void connect_server(QString server_ip, int server_port);   //连接服务器函数
  12.     void disconnect_server(void);  //断开与服务器的连接

  13.     void tcp_client_send_data(QByteArray arr_data);    //客户端向服务器发送数据
  14.     void tcp_client_send_data(QString str_data);    //客户端向服务器发送数据

  15. public slots:
  16.     void slot_tcp_client_connected(void);  //客户端连接成功的槽函数
  17.     void slot_tcp_client_disconnected(void);  //客户端断开连接的槽函数
  18.     void slot_tcp_client_connect_error(QAbstractSocket::SocketError);   //客户端连接出错的槽函数
  19.     void slot_tcp_client_recv_data();   //客户端从服务器接收数据

  20. signals:
  21.     void signal_tcp_client_recv_data(QByteArray arr_data);  //发送此信号,通知widget类处理接收到的服务端数据
  22.     void signal_tcp_client_connect_state(QString state);   //发送此信号,通知widget类关于TCP-Client的连接状态

  23. private:

  24.     QTcpSocket *m_tcp_socket;  //QTcpSocket对象,用来进行网络操作
  25. };
复制代码


5、创建一个tcp_client.cpp文件,这个文件内包含了TCP_Client类里面的所有函数实现。有关tcp_client.cpp的具体内容,请参阅源码。

6、Qt应用程序启动时,跟C语言一样,都是以main函数作为入口。(当然了,真正的程序启动入口并不是main函数,这里忽略了main函数之前的一系列复杂过程,应用程序呈现给开发者的,一般都是以main函数作为入口)。
以下是Qt应用程序的main函数入口。
  1. int main(int argc, char *argv[])
  2. {
  3.     QApplication a(argc, argv);
  4.     Widget w;
  5.     w.show();

  6.     return a.exec();
  7. }
复制代码

这个main函数比较简单,里面定义了一个QApplication和Widget对象,通过Widget::show()函数显示窗体,然后执行QApplication::exec()函数把整个应用程序加入Qt的事件队列,不断循环。

7、在Qt的界面应用程序中,对于Widget类型的窗体,其ui都是通过QWidget类进行构建,在widget.cpp文件中,针对本工程,Widget类的构造函数如下图所示:
  1. Widget::Widget(QWidget *parent) :
  2.     QWidget(parent),
  3.     ui(new Ui::Widget)
  4. {
  5.     ui->setupUi(this);

  6.     ui->pushButton_connect->setCheckable(false);
  7.     ui->pushButton_auto_send_data->setCheckable(false);

  8.     ui->pushButton_send_data->setEnabled(false);         //手动发送数据按钮不可用
  9.     ui->pushButton_auto_send_data->setEnabled(false);    //自动发送数据按钮不可用

  10.     ui->lineEdit_server_ip->setEnabled(true);  //服务器IP可以被输入
  11.     ui->lineEdit_server_port->setEnabled(true); //服务器端口可以被输入

  12.     tcp_client = new TCP_Client();  //创建一个TCP_Client类对象

  13.     ui->label_local_ip_display->setText(tcp_client->get_local_ipaddr());   //显示本机的IP地址

  14.     //连接信号槽,用来处理TCP客户端的连接状态
  15.     connect(tcp_client,SIGNAL(signal_tcp_client_connect_state(QString)),this,SLOT(slot_tcp_client_connect_state(QString)));

  16.     //连接信号槽,用来处理TCP客户端接收到的数据
  17.     connect(tcp_client,SIGNAL(signal_tcp_client_recv_data(QByteArray)),this,SLOT(slot_tcp_client_recv_data(QByteArray)));

  18.     auto_send_timer = new QTimer();     //构建一个TCP自动发送数据的定时器
  19.     connect( auto_send_timer, SIGNAL(timeout()), this, SLOT(slot_auto_send_timer_handler()));  //关联定时器超时槽函数
  20. }
复制代码

在Widget类的构造函数里面,先对ui里面的某些控件进行配置,比如:在连接按钮点击之前,手动和自动发送数据的按钮不可用,服务器IP和端口可被编辑。
然后创建一个TCP_Client类对象,TCP-Client的一系列操作,如连接服务器,收发数据等等,都是基于这个类对象进行。
程序开始运行的时候,在界面上显示本机的IP地址,并连接tcp-client对象提供的信号槽。最后,构建一个定时器对象用于数据的自动发送,定时器对象在构建时,并没有启动计时。

8、先在windows7上运行服务器端的程序,设置好监听的IP和端口。imx6ul板卡上的客户端应用程序启动后,设置好需要连接的服务器参数,点击 [CONNECT] 按钮,程序就会调用该按钮的槽函数void Widget::on_pushButton_connect_clicked(),函数的实现内容如下图所示:
  1. //点击此按钮,连接服务器
  2. void Widget::on_pushButton_connect_clicked()
  3. {
  4.     QString server_ip;
  5.     int server_port;
  6.     bool ok;

  7.     if(ui->pushButton_connect->isCheckable())      //客户端处于连接状态
  8.     {
  9.         tcp_client->disconnect_server();
  10.     }
  11.     else     //客户端处于断开状态
  12.     {
  13.         //检查服务器IP和服务器端口是否参数有效
  14.         if(ui->lineEdit_server_ip->text().isEmpty() || ui->lineEdit_server_port->text().isEmpty())
  15.         {
  16.             ui->label_connect_status->setText(QString("params error!"));
  17.             QMessageBox::information(this,"Server Params","Server Params Error!");
  18.             return;
  19.         }
  20.         else
  21.         {
  22.             server_ip = ui->lineEdit_server_ip->text();
  23.             server_port = ui->lineEdit_server_port->text().toInt(&ok,10);

  24.             tcp_client->connect_server(server_ip,server_port);   //根据指定的ip和端口,连接服务器
  25.         }
  26.     }
  27. }
复制代码


9、点击按钮后,分两种情况,需要判断当前的客户端网络状态是连接还是断开。如果客户端处于连接状态,则点击按钮后,断开客户端与服务器的连接。
如果客户端处于断开状态,则点击按钮后,先检查输入的参数是否有效,如果参数有效,则启动客户端与服务器的连接。客户端与服务器的连接函数connect_server(),如下图所示:
  1. //连接服务器函数
  2. void TCP_Client::connect_server(QString server_ip,int server_port)
  3. {
  4.     if(m_tcp_socket)
  5.     {
  6.         m_tcp_socket->connectToHost(server_ip,server_port,QTcpSocket::ReadWrite); //尝试连接服务器

  7.         //建立信号槽,接收连接成功的信号
  8.         connect(m_tcp_socket,SIGNAL(connected()),this,SLOT(slot_tcp_client_connected()));
  9.         //建立信号槽,接收连接失败的信号
  10.         connect(m_tcp_socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slot_tcp_client_connect_error(QAbstractSocket::SocketError)));

  11.     }
  12. }

  13. //断开与服务器的连接
  14. void TCP_Client::disconnect_server(void)
  15. {
  16.     if(m_tcp_socket)
  17.         m_tcp_socket->disconnectFromHost();   //断开与服务器的连接
  18. }
复制代码


10、客户端与服务器连接过程中,由于在TCP-Client类里面绑定了连接状态的信号槽,因此,连接状态改变后,系统会发送相应的信号,然后调用对应的槽函数进行处理。
因为需要把连接状态显示在界面上,因此,需要在Widget类中,编写一个处理连接状态的槽函数,这个槽函数处理了CONNECTED,DISCONNECTED和CONNECT_ERROR这三种状态。如下图所示:
  1. //客户端连接状态的信号槽
  2. void Widget::slot_tcp_client_connect_state(QString state)
  3. {
  4.     if(state == TCP_CONNECTED)    //TCP客户端处于连接状态
  5.     {
  6.         ui->pushButton_connect->setCheckable(true);
  7.         ui->pushButton_connect->setText(trUtf8("DISCONNECT"));

  8.         //连接成功后,服务器的IP和端口不可以再被编辑
  9.         ui->lineEdit_server_ip->setEnabled(false);
  10.         ui->lineEdit_server_port->setEnabled(false);

  11.         //连接成功后,客户端的发送数据按钮和自动发送按钮可被使用
  12.         ui->pushButton_send_data->setEnabled(true);
  13.         ui->pushButton_auto_send_data->setEnabled(true);

  14.         ui->label_connect_status->setText("connect success");
  15.     }
  16.     else if(state == TCP_DISCONNECTED)   //TCP客户端处于断开状态
  17.     {
  18.         ui->pushButton_connect->setCheckable(false);
  19.         ui->pushButton_connect->setText(trUtf8("CONNECT"));

  20.         //连接断开后,服务器的IP和端口可以再被编辑
  21.         ui->lineEdit_server_ip->setEnabled(true);
  22.         ui->lineEdit_server_port->setEnabled(true);

  23.         //连接断开后,客户端的发送数据按钮和自动发送按钮不可被使用
  24.         ui->pushButton_send_data->setEnabled(false);
  25.         ui->pushButton_auto_send_data->setEnabled(false);

  26.         //自动发送定时器要关闭
  27.         ui->pushButton_auto_send_data->setCheckable(false);
  28.         ui->pushButton_auto_send_data->setText(trUtf8("START_AUTO_SEND"));

  29.         auto_send_timer->stop();

  30.         ui->label_connect_status->setText("disconnect success");

  31.     }
  32.     else if(state == TCP_CONNECT_ERROR)   //TCP客户端连接出错
  33.     {
  34.         ui->pushButton_connect->setCheckable(false);
  35.         ui->pushButton_connect->setText(trUtf8("CONNECT"));

  36.         ui->lineEdit_server_ip->setEnabled(true);
  37.         ui->lineEdit_server_port->setEnabled(true);

  38.         ui->pushButton_send_data->setEnabled(false);
  39.         ui->pushButton_auto_send_data->setEnabled(false);

  40.         ui->label_connect_status->setText("connect error");
  41.     }
  42. }
复制代码


11、每点击一次手动发送按钮 [tcp_send_data],客户端将会发送一包数据到服务端。点击自动发送按钮 [START_AUTO_SEND] 按钮,客户端将启动定时器,并以1秒的间隔向服务端发送数据。
手动发送函数和自动发送函数,如下图所示:
  1. //手动发送数据按钮
  2. void Widget::on_pushButton_send_data_clicked()
  3. {
  4.     tcp_client->tcp_client_send_data(QString("helloworld"));

  5.     display_tcp_client_tx_data(QString("helloworld"));
  6. }

  7. //自动发送数据按钮
  8. void Widget::on_pushButton_auto_send_data_clicked()
  9. {
  10.     if(ui->pushButton_auto_send_data->isCheckable())
  11.     {
  12.         ui->pushButton_auto_send_data->setCheckable(false);
  13.         ui->pushButton_auto_send_data->setText(trUtf8("START_AUTO_SEND"));

  14.         auto_send_timer->stop();   //关停定时器
  15.     }
  16.     else
  17.     {
  18.         ui->pushButton_auto_send_data->setCheckable(true);
  19.         ui->pushButton_auto_send_data->setText(trUtf8("STOP_AUTO_SEND"));

  20.         auto_send_timer->start(1000);   //启动定时器,以1秒的频率自动发送数据
  21.     }
  22. }
复制代码


12、客户端的发送数据函数tcp_client_send_data(QString),是直接调用了QIODevice::write()进行发送的。我们用面向对象多态的思维,编写两个发送函数,可以分别以QByteArry或QString类型的参数进行数据发送,如下图所示:
  1. //客户端向服务器发送数据,以QByteArray发送
  2. void TCP_Client::tcp_client_send_data(QByteArray arr_data)
  3. {
  4.     if(m_tcp_socket)
  5.         m_tcp_socket->write(arr_data);
  6. }

  7. //客户端向服务器发送数据,以QString格式发送
  8. void TCP_Client::tcp_client_send_data(QString str_data)
  9. {
  10.     if(m_tcp_socket)
  11.         m_tcp_socket->write(str_data.toLatin1().data(),str_data.length());
  12. }
复制代码


13、客户端的接收数据函数,是通过信号槽机制来实现的,当Widget类对象接收到TCP-Client类发送的信号signal_tcp_client_recv_data(QByteArray),就调用槽函数处理接收到的数据,如下图所示:

  1. //处理TCP客户端接收到的数据
  2. void Widget::slot_tcp_client_recv_data(QByteArray data_recv)
  3. {
  4.     QString str_display;

  5.     str_display.prepend(data_recv);

  6.     display_tcp_client_rx_data(str_display);   //显示TCP客户端接收到的数据
  7. }
复制代码


14、在TCP-Client类对象中,客户端是通过槽函数slot_tcp_client_recv_data()进行网络数据接收的,这个槽函数绑定了QIODevice::readyRead()信号,
一旦底层的IO有网络数据接收,则会调用该槽函数处理,然后这个槽函数会把数据从底层驱动的缓冲区中把数据全部读出,再发送signal_tcp_client_recv_data(QByteArray),通知Widget类进行处理。
在这里,可能大家会有一个疑惑,为什么不在这个槽函数直接处理数据呢?那是因为考虑到了软件的封装性。TCP-Client类只负责接收数据,然后再把接收到的数据通过信号槽传递出去,至于数据怎样处理,则应该在其他的数据handle类里面进行。
比如,这个客户端只进行数据显示,则可以在Widget类里面处理数据,只需要把Widget类里面的数据处理槽函数与TCP-Client类里面的信号绑定就行了。TCP-Client类里面的槽函数slot_tcp_client_recv_data()如下图所示:
  1. //客户端从服务器接收数据
  2. void TCP_Client::slot_tcp_client_recv_data()
  3. {
  4.     //qDebug() << ">>> void TCP_Client::slot_tcp_client_recv_data() >>>";
  5.     QByteArray arr_data_recv;

  6.     arr_data_recv.resize(m_tcp_socket->bytesAvailable());

  7.     arr_data_recv = m_tcp_socket->readAll();

  8.     emit signal_tcp_client_recv_data(arr_data_recv);
  9. }
复制代码


15、至此,整个TCP-Client连接服务器以及数据收发过程已经描述完成。这个工程只是简单地描述了TCP-Client建立通信和数据收发的简单过程。在真正的TCP-Client网络应用程序中,还需要处理很多突发的网络情况。
如:连接过程中的错误处理,心跳包机制,服务端强行断开连接后客户端的处理,数据粘包与断包,数据接收队列,等等。开发者应在工程开发中不断积累经验,才能开发出稳定可靠的网络应用程序。

题外知识:
      很多初学者可能会对服务器和客户端没有什么概念,不知道怎样理解服务端/客户端这两个角色,个人觉得,要记住关键的一点:客户端是请求服务的,服务器是提供服务的。
举一个简单而通俗的例子:汽车去加油站加油。
把汽车比喻为TCP-Client客户端,把加油站的加油机比喻为TCP-Server服务器。当汽车(TCP-Client)需要向加油机(TCP-Server)请求加油服务时,
则需要先知道加油站在哪(服务器的IP地址),在哪台加油机(服务器端口)上加油,当指定好加油站和具体的加油机后,就可以向加油机请求连接(向汽车插上加油枪)了。
But,总会有特殊情况的时候,比如,当该加油机没有油而导致加不了油(连接不上)了,那么,加油机(服务器)就会通知请求加油的汽车(客户端)进行处理,(这里就涉及到连接不上的情况了)。
当汽车加完油之后,就像是服务端已经提供完服务,那么,汽车(客户端)就可以主动端开与加油机(服务端)的连接了。

点击这里,联系客服获取源码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2019-5-11 22:14:44 | 显示全部楼层
lz有没有qt5 + 多点触摸的例程来一章?

出0入0汤圆

 楼主| 发表于 2019-5-13 12:03:38 | 显示全部楼层
041012js 发表于 2019-5-11 22:14
lz有没有qt5 + 多点触摸的例程来一章?

您好,感谢关注,暂时还没有进行到多点触摸的开发呢

出0入0汤圆

发表于 2019-5-13 12:52:28 | 显示全部楼层
广轻电气091 发表于 2019-5-13 12:03
您好,感谢关注,暂时还没有进行到多点触摸的开发呢

qt5 + 单点触摸的也行,qt5和qt4不太一样

出0入0汤圆

发表于 2019-5-14 10:18:06 | 显示全部楼层
这个应用开发和在pc机上的开发有什么不同?不要为了嵌入式而嵌入式吧

出0入0汤圆

 楼主| 发表于 2019-5-14 10:38:30 | 显示全部楼层
didadida 发表于 2019-5-14 10:18
这个应用开发和在pc机上的开发有什么不同?不要为了嵌入式而嵌入式吧

QT具有很好的跨平台特性,而在嵌入式平台上运行这类应用,可以很好地解决一些以前需要PC机才能做的事情。

出0入0汤圆

 楼主| 发表于 2019-5-14 10:43:32 | 显示全部楼层
didadida 发表于 2019-5-14 10:18
这个应用开发和在pc机上的开发有什么不同?不要为了嵌入式而嵌入式吧

我应该是忽略了一个问题,如果仅仅是描述这些纯理论知识,估计很多人不太感兴趣

出0入0汤圆

发表于 2019-5-30 11:46:29 | 显示全部楼层
厉害厉害

出0入0汤圆

 楼主| 发表于 2019-5-30 12:09:46 | 显示全部楼层

感谢关注,还在不断学习中

出0入0汤圆

发表于 2019-5-30 12:36:16 来自手机 | 显示全部楼层
这些基础没多少用啊,来一些 iocp, epoll,ngnix,websocket,

出0入0汤圆

 楼主| 发表于 2019-5-30 13:35:53 | 显示全部楼层
liangerfan 发表于 2019-5-30 12:36
这些基础没多少用啊,来一些 iocp, epoll,ngnix,websocket,

各花入各眼吧。您说的以上这些,是属于框架的介绍和应用。个人觉得这类框架不是三言两语可以描述清楚。大部分开发者都是使用这些框架,而不是深究其原理。

出0入0汤圆

发表于 2019-6-8 13:55:24 | 显示全部楼层
有没有多点触摸的呢?

出0入0汤圆

 楼主| 发表于 2019-6-8 18:32:20 | 显示全部楼层
tyustli 发表于 2019-6-8 13:55
有没有多点触摸的呢?

多点触摸这么受关注吗?

出0入0汤圆

 楼主| 发表于 2019-6-13 20:13:08 | 显示全部楼层
tyustli 发表于 2019-6-8 13:55
有没有多点触摸的呢?

嵌入式Linux应用程序开发-(10)i.MX6UL基于嵌入式QT实现电容屏多点触控

出0入0汤圆

 楼主| 发表于 2019-6-13 20:13:35 | 显示全部楼层
041012js 发表于 2019-5-13 12:52
qt5 + 单点触摸的也行,qt5和qt4不太一样

嵌入式Linux应用程序开发-(10)i.MX6UL基于嵌入式QT实现电容屏多点触控

出0入0汤圆

发表于 2019-6-15 08:59:15 | 显示全部楼层
广轻电气091 发表于 2019-6-8 18:32
多点触摸这么受关注吗?

看着高大上啊

出0入0汤圆

发表于 2019-8-1 21:38:30 | 显示全部楼层
广轻电气091 发表于 2019-5-14 10:43
我应该是忽略了一个问题,如果仅仅是描述这些纯理论知识,估计很多人不太感兴趣 ...

我就是为了嵌入式而嵌入式,高度关注楼主!顶你!

出0入0汤圆

 楼主| 发表于 2019-8-2 08:14:56 | 显示全部楼层
jiang887786 发表于 2019-8-1 21:38
我就是为了嵌入式而嵌入式,高度关注楼主!顶你!

感谢关注!

出0入4汤圆

发表于 2019-10-17 14:03:05 | 显示全部楼层
QT 基于TCP/IP的网络通信应用程序

出0入4汤圆

发表于 2019-10-18 09:11:19 | 显示全部楼层
我的SOCKET发送不出数据 大侠能否指点一下
https://www.amobbs.com/thread-5720361-1-1.html?_dsign=67914893

出0入4汤圆

发表于 2020-3-3 15:03:56 来自手机 | 显示全部楼层
先码后看。。

出0入4汤圆

发表于 2020-6-13 23:14:51 | 显示全部楼层
感谢楼主分享,改天可以弄着玩一下

出0入0汤圆

 楼主| 发表于 2020-6-29 14:45:17 | 显示全部楼层
batou 发表于 2020-6-13 23:14
感谢楼主分享,改天可以弄着玩一下

感谢支持!

出0入0汤圆

发表于 2020-7-7 16:09:39 | 显示全部楼层
先收藏再看!!!

出0入0汤圆

 楼主| 发表于 2020-7-7 16:46:31 | 显示全部楼层
lycmc1 发表于 2020-7-7 16:09
先收藏再看!!!

感谢关注

出0入0汤圆

发表于 2020-7-28 21:39:10 | 显示全部楼层
我想学习一下你的qt程序。

出0入0汤圆

 楼主| 发表于 2020-7-31 09:43:23 | 显示全部楼层
arris9 发表于 2020-7-28 21:39
我想学习一下你的qt程序。

行动起来吧
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 06:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表