找回密码
 注册
关于网站域名变更的通知
查看: 611|回复: 1
打印 上一主题 下一主题

4412开发板Qt网络编程-TCP实现服务器和客户端

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-4-28 15:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

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

x
网络编程有 TCP 和 UDP,TCP 编程需要用到俩个类:QTcpServer 和 QTcpSocket。
: I6 T$ T( @1 T4 B* S- g 0 T# s. \7 L8 u; |) l, p" s) |$ W, P8 G8 w
1 TCP 实现服务器和客户端. ~7 {/ \; Q% B3 n) D0 ~, V$ @7 A
TCP 协议(Transmission Control Protocol)是一种面向连接的,可靠的,基于字节流的传输层通信协议,传输数据稳定可靠。
0 Z8 l+ r" S6 p' ^8 x在 help 索引中搜索到如图 两个重要类:+ w, I- V9 E0 w  l& X- ^
  |& N! o: h( o! D) O9 c9 q+ w3 G
服务器编程中两个类都会用到,客户端编程中只会用到 QTcpSocket 对象。
3 I6 z0 w& Y4 F3 D$ u+ {本实验中对 QTcpServer 类的基本使用:
3 N0 b& q2 J" P( ?, Z. b  x/ M5 W(1)监听客户端连接。
3 c3 q+ ~# `- a* H' I5 X* Y(2)每当有新的客户端连接服务器的时候,会自动触发信号,
2 l! m& B/ _  E$ Y% @' L(3)根据当前连接上的新的客户端创建一个 Socket 对象,将数据的收发动作交给 socket 套 接字去处理。
3 I1 `. r4 h$ a3 b$ L  G(4)关闭服务器 close();/ I# m, r1 Y. S
对 QTcpSocket 类的基本使用:
( L* I" g4 i* o6 _" w(1)服务器端:有新连接时获取连接状态,绑定 socket 。8 O! i5 b) }* @
(2)客户端:通过 socket 连接服务器,连接成功触发信号。
  T& h8 W/ G" U& L1 A6 y0 l: N
1 x8 V1 V9 }0 m! y% n(3)当有数据到来时会触发信号,用 readAll()读取。" q, ?1 I1 d7 Y
(4)通过读写 socket 收发数据。. i! X/ ?, g4 L! x# P
具体步骤:' U7 Y. f8 w6 e1 b- Q: |
步骤一:创建工程,在工程文件.pro 中添加 network,如图:- T3 i7 X* ]: D- [

' o# V, O# T! Z& k3 H0 `步骤二:设计 ui 界面,
1 Q' m5 Z0 I2 g- Q; Z) s) k3 m1. 在属性编辑栏设置主窗口大小:
0 Y" \4 S* W& t3 n& o
, L+ z; e0 B  r7 X% w2. 添加组件
4 @$ v+ D. \" |9 [7 O- _接收窗口: Plain Text Edit  T/ t/ l4 q5 }- i3 f1 v
发送窗口,IP 地址窗口,端口号窗口:Line Edit7 }3 `. ]) g" o: [7 J7 e8 C6 K
打开服务器,关闭服务器:Push Button- p7 T  U; a+ ]' \' b
拖拽完成后逐个布局,根据需要设置组件大小,这里端口号框设置成了最小 200; P% j8 e* m7 {- q7 S$ }* o# R

3 Q+ q- U/ u- [4 j1 Z7 g9 s按钮布局:拖拽按钮和弹簧,然后点击水平布局。
2 `+ Z' \( f: F* Q' m8 ` 5 D$ U, w1 U1 L4 |" p  p5 b
然后选中全部组件,点击栅格布局:
4 t& e/ w' h5 o7 y
) N3 P$ n. v: U( U& x& I最后更改组件名称注释,完成后如图 :( v2 b; @$ y4 M0 o! W

7 l& i$ l" q, \步骤三:服务器端编程:4 ?' f8 P, _! u+ d+ u% k/ |
1.创建 QTcpServer 对象
# I7 Z4 j' e" O9 {/ {7 V2.创建监听端口,使得客户端可以使用这个端口访问服务器,使用 listen 函数。3 H/ f. i, Q. Z  k' n
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);- N, h; z7 l8 O) w' |- d
第一个参数是绑定指定的地址(即本机服务器 IP),第二个参数是绑定的本服务器端口号。! I0 K' _8 X5 c% g& |* Z
监听某个端口时,如果有新连接进来就发出 newConnection()信号。
6 K5 A) b4 A1 w' f3.当服务器对象被访问时,会发出 newConnection()信号,所以为该信号添加槽函数并用一个 QTcpSocket6 g7 e7 `( x  Z; S4 e3 J7 O- D/ E  X
对象接受客户端的访问。
/ O4 T9 r2 D+ _6 D( ]' h/ T4.当socket接受缓冲区有新数据到来时,会发出readyRead()信号,为该信号添加槽函数,使用readyRead()
  I3 e$ Z9 U; f# x; o读取。
+ Q8 x4 [2 K; _3 w5.socket 发送数据可直接调用 write()成员函数。: U; q2 i  T9 t1 X- L6 U
6.关闭端口号。
: z; C- x, Z( G6 _代码如下:
, h2 G+ s* l/ P. `  w2 S
! g- B& {) g& S; z1 n#include <QMainWindow>
* m; K0 O  |  ^3 R# \( _6 _5 L#include <QTcpServer># o; ^/ R$ S1 E& y
#include <QTcpSocket>) A! l2 i1 f' W& a
namespace Ui {
! S% i% q" l1 T; \1 H5 h0 j* Qclass TcpServer;
# x* r$ D4 n, o8 X/ i}0 I$ ^1 Y3 y" i& `
class TcpServer : public QMainWindow! r. `! _& o" [5 P
{
( e# v3 p2 o! a7 m6 Q  qQ_OBJECT
$ @9 D: O+ H3 S5 O" r1 z7 X! w& bpublic:
+ w/ d1 b  q# F" ^$ S0 ^7 f$ G3 C1 n: v2 R  T: R
explicit TcpServer(QWidget *parent = 0); ~TcpServer();
3 A4 V7 R  p+ z' `( bQTcpServer * tcpServer;2 M8 S$ i0 ~, ^+ Q
QTcpSocket * tcpSocket;
: e, G  h( v. s& O# u% Spublic slots:* U4 \' K! r3 x  }. D$ r7 U& |
void newConnection_Slot(void);
& c% I0 ~* J& k6 yvoid readyRead_Solt(void);
; h. s- w) Y% T3 Uprivate slots:
3 `% |" H: q5 `5 {7 M# m' M' W3 zvoid on_openBu_clicked();( l$ M0 x* K8 u) r3 M; T
void on_sendBu_clicked();
' g$ A- v) ?* i( [: G  U2 hvoid on_closeBu_clicked();2 W! D5 E+ p; Q) I( M
private:
7 s7 ]7 Q( t$ S  mUi::TcpServer *ui;, p. Y# }" Z) I4 O: h# w# D8 @: }
};
! P9 A) A8 M  k3 _' O" _2 {#include "tcpserver.h" #include "ui_tcpserver.h" #include <QTcpServer>; C$ Z4 e4 [" i0 i5 t, @( K. X
#include <QTcpSocket>
* ?! S6 k% x) M7 W#include <QString>, x( |0 g/ u; S5 `( k
TcpServer::TcpServer(QWidget *parent) :' l  ^5 }# j5 q! C7 }
QMainWindow(parent), ui(new Ui::TcpServer)
0 b( n# T  d/ p% d{% B% q2 f+ {6 b& h! c+ y
ui->setupUi(this);
  d# k/ }) c! j' N+ N3 h  a; ZtcpServer = new QTcpServer(this);) a% P  r3 C1 t5 m( j
tcpSocket = new QTcpSocket(this);
! ^' f5 y; x: X' R//连接信号与槽函数进行绑定: W+ t3 A& t/ }
connect(tcpServer,SIGNAL(newConnection()),SLOT(newConnection_Slot()));  G& s( H& ?0 B' C* }1 N
}4 \# L( v; F, \5 B
//连接信号槽函数- }  X) W! @+ _3 `! h
2 T  W8 _4 q9 k# A% E- X
void TcpServer::newConnection_Slot(void)' k& d6 S/ C7 V: j& b5 y4 S8 x
{0 F% \( B8 a( ^5 D0 m+ W2 h
//连接客户端后 socket
# Z* i9 u' f" CtcpSocket = tcpServer->nextPendingConnection();
+ w* X( p. z) Q) k7 [5 V# E& m//套接字的接收数据信号与都数据槽函数连接
) ~( i0 u9 N. Q$ ]5 ~; kconnect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));
- k+ }5 x! Q1 Z}" g+ q" k4 t4 u' S% C
//读取数据
  f: n9 m3 T: Q( K. l9 m. l2 ~void TcpServer::readyRead_Solt(void)
6 f1 z0 z) s: e# @" n) T0 d{! k# `0 d, \) C* S, P0 Z8 j
QString buf;
1 E$ E* Z: Q  ]. ^! s* b6 S9 B2 R//读取
! n8 ^' X( u( x7 I: O2 M( _buf = tcpSocket->readAll();
* r$ y7 @( Y# H! @" Qui->recvEdit->appendPlainText(buf);# |3 a$ r" ], @: X# J
}% U5 z9 o+ z7 e8 Z2 V" P9 |0 E
TcpServer::~TcpServer()
6 \8 n+ K) d9 [9 c# F  T, Z2 ~{
7 D! ^8 A5 _* I7 K5 r/ Sdelete ui;! i5 r9 }7 m5 H8 p7 O% O: n: C
}
, b, y9 c& s7 u0 O  z1 Q2 R! x  C! L//打开0 l0 C$ ?4 k+ Z& w: }! R
void TcpServer:n_openBu_clicked()' _8 Q9 v: R3 ?$ R' Q* K
{
% b( c/ i# T* e% o$ e//监听) e9 h; [4 ]8 ?$ _0 S* P4 t
tcpServer->listen(QHostAddress::Any,ui->portEdit->text().toUInt());7 h" P" g6 O3 J( X; i
}
3 c! }' o; `6 I6 d5 q% z; `//发送数据! @0 ~& K; H0 I6 B- h% e2 _2 a
void TcpServer:n_sendBu_clicked()! W: g8 ~7 C& r- s: V* _
{0 c2 X" @8 ~5 C" i: {
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());; y' G4 w) ~% E; J) q/ M/ U
}& e; b- ], f( @5 f
//关闭) t( r. g1 Q7 V# ^% x( L
void TcpServer:n_closeBu_clicked()* P  e- U) V) d& P7 Q
3 k* R9 V  Y9 v6 @( \  O1 K0 l7 w
{
2 j% `( i6 n# N$ Y' f! I- ytcpSocket->close();! F9 |9 U7 h7 f& v! m$ K% B
}: p8 F& ]& R% ?" s& ^: ?, h6 y
步骤四:客户端编程
9 g. K) `( L4 x% b: k2 U- O5 \
$ H( X; S% k3 ?# f& T/ |/ P6 v1.创建 QTcpSocket 套接字对象/ t1 O( Z0 K2 W, ~9 a; A& Q
2.使用套接字对象的成员函数去请求连接服务器。; r$ t7 V0 w( _) f; I
void connectToHost(const QHostAddress &address, quint16 port, openMode mode = ReadWrite);
( Z7 k0 N9 X4 c8 i3 e' c; W8 m% g第一个参数为服务器 IP 地址,第二个参数为服务器端口号。第三个参数为打开方式,默认为可读可写
0 L/ W  Q- d% z! r! V; s+ z函数功能:请求连接服务器连接成功后发出connected()信号,绑定槽函数connected_Solt()去操作socket。
, T. b% j- L7 L0 l3.使用 write 函数向服务器发送数据,当 socket 接收缓冲区有新数据到来时  S3 Q1 g! L! S8 m3 X
会发出 readyRead()信号,为该信号添加槽函数以读取数据。+ p, ?' b5 J+ R5 g. Q3 g, L5 R
4.断开与服务器的连接。/ D$ q# `; A0 a( B2 p' n. w4 L
* z' d/ z! y* N9 _: W2 n
class TcpClient : public QMainWindow
1 F2 n  j( d" p$ y* t5 i) M0 B{
: v) b, x1 ]% B) x9 u7 o% L( ~3 F9 a....... private slots:2 G  u" D- v5 z' E7 C. g
void on_openBt_clicked();. j, d% J& g. b3 s. i0 |
void connected_Solt(void);
6 H7 B& y" N: n5 R/ x( Evoid readyRead_Solt(void);/ \/ n5 `3 y. I$ ~9 X! J2 w* p
void on_sendEdit_2_clicked();
* s) D7 H" {$ bvoid on_closeBt_clicked();% {2 V2 M% D6 j, m9 n* `0 c" B
};
" U# T# f1 g! j& {' k  M/ _, j! l6 {' t+ A
TcpClient::TcpClient(QWidget *parent) :
& {% Q- R0 X) ]QMainWindow(parent), ui(new Ui::TcpClient); @( ^( r! Q  u4 G3 L* x
{
8 b6 p1 @* f4 {/ H2 A) Cui->setupUi(this);  |4 h) Q8 ^3 w* h
//创建 socket 对象% B8 a; _9 M1 ?6 X* ~" n8 C) D
tcpSocket = new QTcpSocket(this);
0 U% m3 I0 h  W: h) Y}
" @! w# c: R$ |TcpClient::~TcpClient()
# u4 Q! _; C  S+ F{
, Q! m+ i" N2 n) @/ O5 _& hdelete ui;4 b3 F7 v( X( K, ?
}
7 {7 W$ T; c& j. V+ a, p' Y: Y//打开(连接服务器). t/ {1 v' [: ~9 C% A
void TcpClient::on_openBt_clicked()3 ?+ I$ e6 U: S
{
' |: a' r0 j* w2 w% w2 xtcpSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toUInt());
/ g% E) k$ U. r& D  r% \connect(tcpSocket,SIGNAL(connected()),this,SLOT(connected_Solt()));
, [2 z4 Z& X# k7 r7 Y}1 C$ g" c" ~+ O$ U5 v, G) m
//等待数据到来: `. }* w8 m) Z- M- {# J
void TcpClient::connected_Solt(void)
) @9 W! H6 H! _4 ?{
) n0 ?' y4 W+ p5 Sconnect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));& J3 R& ?% d7 _5 G
}
9 W" f+ k8 I0 X+ E0 m" s0 R  A; f. T//读取数据
# I/ ]; G: B8 ~- K' \void TcpClient::readyRead_Solt(void)
! M$ `8 G  x$ D0 }, V{
6 ?! s* @' P5 aui->recvEdit->appendPlainText(tcpSocket->readAll());; r$ a+ k7 l0 ~+ {
}( h2 ~! @' s6 R2 `* U- W% E
//发送4 n! i* ^8 m" l: ]' Q, }" p
void TcpClient::on_sendEdit_2_clicked()
8 q. X1 n2 I" _. g! B: v9 U8 u{0 T# U$ B" ]* @' u8 N. n4 M! k
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
( O/ j% E7 b! w. z- ^}
! J4 {4 E6 m. E! y4 l//关闭
7 Z: A/ Y3 A2 qvoid TcpClient::on_closeBt_clicked()& N2 b) |  Q! v) C  c1 F. Y4 G
3 ?: _8 l& _5 v" i1 @8 `* s5 U
{) X$ @1 g& K- k( t8 w4 |8 A
tcpSocket->close();1 o6 U+ Q8 J) ?2 C% X
}+ R# p# m3 R% e
编译运行成功,使用服务器和客户端通信如图:
6 x9 s1 t9 c6 E+ @6 g& ?
) y$ n5 T5 t! l( [- Q5 }& K' f
5 l4 x0 E7 z& B8 `: r5 s9 B9 {- x. Z* L5 p- X* _4 A
  • TA的每日心情
    开心
    2022-12-5 15:27
  • 签到天数: 1 天

    [LV.1]初来乍到

    2#
    发表于 2021-4-28 16:16 | 只看该作者
    很详细,学习了
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-11-24 08:19 , Processed in 0.171875 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

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