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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
网络编程有 TCP 和 UDP,TCP 编程需要用到俩个类:QTcpServer 和 QTcpSocket。
% K7 ^" c: O( \0 V' q% x, f; G + ^0 S/ Q7 t. ^3 A3 Y  K! A1 U2 ^% ]
1 TCP 实现服务器和客户端* W# [0 i4 b7 G& C( t
TCP 协议(Transmission Control Protocol)是一种面向连接的,可靠的,基于字节流的传输层通信协议,传输数据稳定可靠。' M8 |2 _& M  |; ?% L/ Y' h
在 help 索引中搜索到如图 两个重要类:
4 n- o% l1 z' p2 S4 m
* H1 ^  Y. w% z5 A, \服务器编程中两个类都会用到,客户端编程中只会用到 QTcpSocket 对象。
' K1 A3 G. _# E" T本实验中对 QTcpServer 类的基本使用:* q/ Z  C1 a; j9 W
(1)监听客户端连接。
6 Y& R+ Y( O% E% C7 e9 Y: k(2)每当有新的客户端连接服务器的时候,会自动触发信号,8 a% ~. i( |2 y9 D
(3)根据当前连接上的新的客户端创建一个 Socket 对象,将数据的收发动作交给 socket 套 接字去处理。
% W9 U/ ~+ T* Y; j  I- c(4)关闭服务器 close();0 R* s' W! I$ h; g1 ]3 w
对 QTcpSocket 类的基本使用:
" B1 U' N6 T$ b2 C1 z(1)服务器端:有新连接时获取连接状态,绑定 socket 。
, b$ J% c. h0 ?- c& }, f(2)客户端:通过 socket 连接服务器,连接成功触发信号。
2 T4 ?8 S) @( s9 H8 j
0 @& L9 q" a: V4 ]0 u6 B% y9 J, U(3)当有数据到来时会触发信号,用 readAll()读取。
7 c% D2 s: c- ?6 C' J(4)通过读写 socket 收发数据。; S5 k& Y# T& P
具体步骤:- @$ W# z3 w. J" p
步骤一:创建工程,在工程文件.pro 中添加 network,如图:
( D6 v- N' Z- l+ l: a
# B* B) y6 g4 W1 |6 \6 [步骤二:设计 ui 界面,, p* {7 r, ~/ S" F
1. 在属性编辑栏设置主窗口大小:
1 x, C. J% X/ o! M( X. \5 Z
/ q2 ]: P: K& p" M% t# l" V' V# O2. 添加组件
# e* e+ v8 \# H接收窗口: Plain Text Edit4 V; ^" d+ d( v9 I: ?# u
发送窗口,IP 地址窗口,端口号窗口:Line Edit
" o: _$ Y( M5 o1 u9 d( \) s3 d打开服务器,关闭服务器:Push Button
8 P3 n! c) K$ I拖拽完成后逐个布局,根据需要设置组件大小,这里端口号框设置成了最小 200
, o7 `7 S* [7 @" Z/ J; W7 u 6 p) ^4 |0 c' B* v- p" D
按钮布局:拖拽按钮和弹簧,然后点击水平布局。5 N4 Q/ S0 Z9 ^! z. n
. v8 r, B! P* }2 d+ {% d/ _! V
然后选中全部组件,点击栅格布局:
3 {8 W2 o& Z: y9 i2 h 4 M- B' [3 n' ^% W! w8 S  b' \6 K; z6 {& X
最后更改组件名称注释,完成后如图 :( W- z6 c% c) J- D

; _" {9 U& @. O) a. V8 f) Z; `- j步骤三:服务器端编程:; W3 w3 d/ l& `, a' f
1.创建 QTcpServer 对象. n9 s% j# v9 Q! c0 i% z: w
2.创建监听端口,使得客户端可以使用这个端口访问服务器,使用 listen 函数。: {5 m- y) K) M3 u: O' I
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
9 ^6 q% i* i0 a  J- f# k3 t第一个参数是绑定指定的地址(即本机服务器 IP),第二个参数是绑定的本服务器端口号。7 a4 e+ W+ w/ _- U
监听某个端口时,如果有新连接进来就发出 newConnection()信号。/ R$ z0 N+ U3 M4 @- u" H2 S& F. k6 D
3.当服务器对象被访问时,会发出 newConnection()信号,所以为该信号添加槽函数并用一个 QTcpSocket8 ?& x4 Y; Y0 V1 P2 c$ L6 o8 P' x" _
对象接受客户端的访问。
8 h/ _' S9 t: l+ r  c4.当socket接受缓冲区有新数据到来时,会发出readyRead()信号,为该信号添加槽函数,使用readyRead()$ p( Z$ V; q3 a
读取。
$ |$ F3 t2 h* g  M5.socket 发送数据可直接调用 write()成员函数。
1 k; _2 d9 |5 w6.关闭端口号。1 l0 c3 D2 i* w. e
代码如下:$ t$ h1 Y5 H# ^4 ~$ k1 t
9 W" E7 ?2 P4 ?
#include <QMainWindow>
0 u/ n: g9 p0 H: l* J) X6 r. J% `#include <QTcpServer>, u4 M! _' ^7 `, H$ E& s
#include <QTcpSocket>; o6 Q+ u* {4 V; L7 k2 c
namespace Ui {
0 c* k2 i! ]$ aclass TcpServer;
( ^+ \; ]) F' `/ X}
, N( z  m  L! I7 V& P, rclass TcpServer : public QMainWindow
0 J+ w# {/ Q# s) E{
: @! h" E* ]. s) E/ _: I: CQ_OBJECT
7 ~6 F! O. d+ t3 jpublic:  k# t$ l7 p! m' h3 @" t" A
) l1 a& c$ Y; w: ~/ ^' X
explicit TcpServer(QWidget *parent = 0); ~TcpServer();1 C& r: [# }4 z& O+ P  w- M/ u" j
QTcpServer * tcpServer;* m0 C7 \- o, k6 |
QTcpSocket * tcpSocket;9 A9 a5 M2 c+ p. b0 O2 E
public slots:
4 ?* O+ [. D5 G+ @6 Lvoid newConnection_Slot(void);' F4 j+ ^6 Z) W7 v, I2 e
void readyRead_Solt(void);
* f( m7 W* H$ a: l1 E# V. Rprivate slots:! h5 c$ ?, H) |+ T' r8 W$ f
void on_openBu_clicked();' y' S2 f1 ?, p* \2 ]3 b4 x9 i
void on_sendBu_clicked();
, h) s! }' e% C: J( k  b8 [" B+ `void on_closeBu_clicked();
) H/ {+ o% J7 m$ Tprivate:
8 _2 ?6 |; k% a! n* n, zUi::TcpServer *ui;! E- z3 |. z2 |2 N1 A
};
* W0 H2 L8 F  _- g) A. G# p#include "tcpserver.h" #include "ui_tcpserver.h" #include <QTcpServer>
0 S) H3 Z1 ~$ [! Y+ v2 r$ l* M0 ?#include <QTcpSocket>
1 a8 Z' t; h# A+ _7 J#include <QString>$ q2 G. w/ y- c* g' C1 e
TcpServer::TcpServer(QWidget *parent) :0 X1 L) w# W: r' V! K0 o0 v* r
QMainWindow(parent), ui(new Ui::TcpServer)3 R% {3 c4 R. l. Y
{
/ K! N/ \' I( H, ]& `( _2 L6 Lui->setupUi(this);' n7 @, {+ [4 R% d) o6 ?
tcpServer = new QTcpServer(this);
2 L& K/ F% V% P' V( htcpSocket = new QTcpSocket(this);
& I* X& X0 [) o2 s//连接信号与槽函数进行绑定4 M6 k/ z( `% J- g. }4 f
connect(tcpServer,SIGNAL(newConnection()),SLOT(newConnection_Slot()));
  S" u7 M5 g4 z) ~0 |$ |/ R3 L  H- b}1 D7 x! |' y0 o
//连接信号槽函数
  n$ j; Y" g# @) ]1 x: W/ e; L+ h0 k3 @) z3 ^! Y# b
void TcpServer::newConnection_Slot(void)& ]& w1 i/ k& n8 \
{' C! C4 Z5 ^2 O$ O/ G& G6 M
//连接客户端后 socket* t& R+ c& u: h* D% D
tcpSocket = tcpServer->nextPendingConnection();% h5 k3 d7 q) P, c1 }5 f9 Y+ H
//套接字的接收数据信号与都数据槽函数连接
6 p$ c& V. t1 ]/ G( y. }connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));
7 V2 h7 K3 N, \8 \+ h' T. ^- h}: n- |( A1 {% {, J3 G& D
//读取数据4 \5 j# M& \3 K+ q% R$ z- Q
void TcpServer::readyRead_Solt(void)5 O9 B+ I" W0 r6 b( q7 c6 p
{% X; @. Y3 t% Q, U
QString buf;
% r  I" Q' K+ K  e: M. c  q, R//读取
5 A, y, U- R% E# G) `buf = tcpSocket->readAll();
* J( _% m1 q5 q4 o' |: _ui->recvEdit->appendPlainText(buf);9 q, K* O! Y4 U% v; ]" s7 x- I" e+ |
}) B* o# }0 O" N3 {& @
TcpServer::~TcpServer()
1 R7 A/ c. l7 ^  ~7 U. g+ C{
' [2 T. ]& W& R, m  {- mdelete ui;
' b7 x# C3 k/ O}# |) k# K% U! i7 z! D; j
//打开
# X6 M$ Z- |' e* h- L# \void TcpServer:n_openBu_clicked()
; l# \0 X' C8 n4 E{3 `( q* x1 u6 B6 d- S
//监听
, i9 k6 `  T6 }9 V: l" btcpServer->listen(QHostAddress::Any,ui->portEdit->text().toUInt());% |2 K1 s% ~* L2 [" S- _+ w
}
8 D9 ~$ t# b" H//发送数据5 {3 r7 L4 X: R& Z3 p
void TcpServer:n_sendBu_clicked()
) Y: G7 H( u$ t* v3 m* e  m{: G& j; e/ g) d" \; r5 x1 x; X
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());9 V0 D: }! f8 [/ n
}
7 r7 V7 L. i+ z% \# P1 t( ~, w//关闭' B  ]" a& L6 V$ I( D: Z+ h* ~9 K
void TcpServer:n_closeBu_clicked()
. _8 b; }# @5 |) z" ^+ G% E# D( Z! ]$ ?/ a5 D7 ^' _
{
5 |2 l6 u) F* W* ?- R; ltcpSocket->close();
' ~( ]7 {- x: [# a" W3 ^9 m) m}/ k5 u5 M9 T( Y) ~& [+ U
步骤四:客户端编程; Z  [$ K# f) g) u7 J& a/ |

9 P/ q. u1 v9 z) K, M1.创建 QTcpSocket 套接字对象
! R: U/ t& C* \2.使用套接字对象的成员函数去请求连接服务器。
9 B. [; O5 A; C: Mvoid connectToHost(const QHostAddress &address, quint16 port, openMode mode = ReadWrite);" X; t" A1 ]$ A/ q, Z' |! d
第一个参数为服务器 IP 地址,第二个参数为服务器端口号。第三个参数为打开方式,默认为可读可写2 ?' o1 r* w' I. R2 P! L) d
函数功能:请求连接服务器连接成功后发出connected()信号,绑定槽函数connected_Solt()去操作socket。
8 u0 z* M$ k3 P& w7 Z3.使用 write 函数向服务器发送数据,当 socket 接收缓冲区有新数据到来时# P9 S, [( @$ f+ v$ _5 W
会发出 readyRead()信号,为该信号添加槽函数以读取数据。& z& Q) ?& D, l* v$ U3 A; p6 k
4.断开与服务器的连接。5 |& ?2 a4 W  C9 ~1 i8 L* K
1 T4 N$ Z" ]% i9 r+ G% K  J3 W
class TcpClient : public QMainWindow
- K  z3 g% n1 n{. V9 ?- O0 f8 Q) n/ V
....... private slots:
5 o6 s# d5 s1 M7 mvoid on_openBt_clicked();& X. ^. C/ N% g! ~% F4 G' x+ F
void connected_Solt(void);/ [# ^# Q7 m$ q4 ^" s
void readyRead_Solt(void);5 i# z  p  f2 g' m2 M* ^0 ]2 i: H" ~7 M
void on_sendEdit_2_clicked();6 Y# h: r# T; I7 c: @1 F1 ]
void on_closeBt_clicked();
; D  U; C) k; w/ m& r4 l) \};8 f5 w( j9 _( z
6 F- d) n6 T6 W9 d) _
TcpClient::TcpClient(QWidget *parent) :
# _5 }# [, A# P0 l$ q4 g( Y& uQMainWindow(parent), ui(new Ui::TcpClient)$ \9 I6 j0 K1 |5 \% G  ?3 ?2 F
{$ Q- o1 h( j& D( v& w4 y
ui->setupUi(this);4 A( r$ Z# N! ~! g
//创建 socket 对象
1 F: H4 `0 m$ q! b0 ~  btcpSocket = new QTcpSocket(this);
0 I7 U. |# R1 c5 ?1 p$ T; t8 o}
1 G3 G) f7 z1 h8 P; |2 o9 j6 J- ~TcpClient::~TcpClient()+ W2 g7 @; y) h6 _- H- [9 |
{
# s7 p6 d1 c. ~' {" W% X8 e) Kdelete ui;
: o4 j. ?8 W$ T8 G6 X' }" \( N}
! Y. F. O8 t* s2 R& K//打开(连接服务器): b$ s' L( r) ~" Y. |& X
void TcpClient::on_openBt_clicked()
1 R& d6 a0 z4 q2 Y$ _. N{0 e& S3 H0 u) q( a% z
tcpSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toUInt());! w; D- x" Q- C
connect(tcpSocket,SIGNAL(connected()),this,SLOT(connected_Solt()));: V4 ~+ c1 u( ?( W# n4 u
}
3 `; W* _0 H: z* X9 h# x' m  a: q0 h//等待数据到来
% p7 K- P+ I7 S5 \5 ]6 Jvoid TcpClient::connected_Solt(void)
! W$ W8 L$ [0 R{
/ Y0 Q# a1 U3 ?4 oconnect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));; \# v+ v1 x* d
}
6 Q1 H5 f' ?* X& H8 g//读取数据
% D- o7 x; X4 w, A) L4 L- {4 A% ovoid TcpClient::readyRead_Solt(void)9 n" s5 x0 X/ q' n8 [
{
: R0 j# G8 q+ M! R+ v7 Zui->recvEdit->appendPlainText(tcpSocket->readAll());
2 ^2 K) ?  d# \/ X4 Y. f}1 I/ S6 T' o, p% {: R% d
//发送2 F( z3 Z/ E- D4 x  `6 L2 S
void TcpClient::on_sendEdit_2_clicked()
4 n2 U/ b# q7 M- E' ?3 Z{( O& d# H3 x8 ?
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());0 \7 L. |# x/ y  `0 r& Q  k1 n0 }
}  A+ A' x6 U$ T- y/ A2 S& x' w/ [6 ^
//关闭* I+ M& ]7 P* w' q! a& Z
void TcpClient::on_closeBt_clicked()1 U. Z, `4 _, w& b; z9 D
3 p/ r! q; M: |$ r
{
2 L0 I3 H% h- \  U" k" M9 LtcpSocket->close();
! J+ [( j& f6 T  ~% p}' F9 W/ q  Q9 Y& q9 I
编译运行成功,使用服务器和客户端通信如图:4 Y0 b; W+ e- i, n- [8 b

% {( d. \+ D, J# H7 |/ a . u9 Z4 l3 |; P' P* e8 `3 E

% v* C! M& \, `: ]; Q/ v% Y3 p
  • 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 11:34 , Processed in 0.171875 second(s), 26 queries , Gzip On.

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

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

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