|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
网络编程有 TCP 和 UDP,TCP 编程需要用到俩个类:QTcpServer 和 QTcpSocket。1 O" M- Z5 u1 a3 ~* H. o2 Z
/ h8 m9 _; s, i" R; x
1 TCP 实现服务器和客户端
4 E* w7 ^2 c6 u6 a2 u: B2 DTCP 协议(Transmission Control Protocol)是一种面向连接的,可靠的,基于字节流的传输层通信协议,传输数据稳定可靠。
5 V2 ]# a0 O, Y在 help 索引中搜索到如图 两个重要类:
$ v+ l2 m1 [. p$ t
4 P" K; z. A; e( P
服务器编程中两个类都会用到,客户端编程中只会用到 QTcpSocket 对象。3 H* w" ]( R7 n" `5 ^5 H/ j, O4 u
本实验中对 QTcpServer 类的基本使用:+ I1 D! G/ U9 j% L
(1)监听客户端连接。, ^# }3 @3 N7 |, J
(2)每当有新的客户端连接服务器的时候,会自动触发信号,
$ j+ I6 w& k# j" p' h: I) \. x(3)根据当前连接上的新的客户端创建一个 Socket 对象,将数据的收发动作交给 socket 套 接字去处理。6 P B$ T0 x5 }6 \2 K! X! ]7 h
(4)关闭服务器 close();" h0 J: n u1 ]3 m1 U
对 QTcpSocket 类的基本使用:9 ?9 W- X2 f4 h8 r
(1)服务器端:有新连接时获取连接状态,绑定 socket 。
- a' ^' q* X+ o$ X* \: y" h. s! w5 A(2)客户端:通过 socket 连接服务器,连接成功触发信号。* c# d) o: G! ?+ [; K5 b
- h& A7 o: @! t% z" H5 ]0 F(3)当有数据到来时会触发信号,用 readAll()读取。8 P1 j. _5 S: ^% E& O: d
(4)通过读写 socket 收发数据。) a% A2 C$ x/ z& u3 I, ~
具体步骤:
- ~+ } d/ ?& u1 X2 |步骤一:创建工程,在工程文件.pro 中添加 network,如图:1 U. D9 x) H; m V2 {
+ F/ J9 y) V2 t2 N0 ~$ @步骤二:设计 ui 界面,: A) e, a4 |% K/ N$ d' J+ \5 R" n& U
1. 在属性编辑栏设置主窗口大小:
* `; m! M: p& o* z7 m+ k
; [6 ]3 a4 p s# i
2. 添加组件. `, W; ]$ {+ @* C
接收窗口: Plain Text Edit
. u- u5 M8 ]4 N4 F+ |) L% g发送窗口,IP 地址窗口,端口号窗口:Line Edit
$ `8 E# {. z4 C) O: U打开服务器,关闭服务器:Push Button3 g8 _( F( d+ [& ^5 g6 {
拖拽完成后逐个布局,根据需要设置组件大小,这里端口号框设置成了最小 2004 X6 e' V9 [" P6 b, }7 K3 O
9 A1 i- x, ^9 _. G0 B" v7 K按钮布局:拖拽按钮和弹簧,然后点击水平布局。
" a) q/ V- D9 E# b r% R
5 Q* M! d; x" G1 B) y* E
然后选中全部组件,点击栅格布局:
4 X8 e3 z& C8 E3 i! p5 ~
* a3 G: t+ [4 L: Q最后更改组件名称注释,完成后如图 :6 i) P* ?$ E5 v J. T, u7 f
4 w4 Z$ b' r1 Y& `
步骤三:服务器端编程:0 ?: Y8 |4 ~2 d" E
1.创建 QTcpServer 对象
9 H+ k: L/ e6 c6 _. r2.创建监听端口,使得客户端可以使用这个端口访问服务器,使用 listen 函数。' r0 O6 O* B3 M. [6 |8 B
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
- p. h9 K$ z+ K" f( n. s( I第一个参数是绑定指定的地址(即本机服务器 IP),第二个参数是绑定的本服务器端口号。
+ ]+ m, e: d4 @- e监听某个端口时,如果有新连接进来就发出 newConnection()信号。- ~+ o% p2 b! h( p. \! U
3.当服务器对象被访问时,会发出 newConnection()信号,所以为该信号添加槽函数并用一个 QTcpSocket$ e" ?! E$ z( h0 t O
对象接受客户端的访问。# a# ]! B* V0 p7 }' X7 z- r6 g
4.当socket接受缓冲区有新数据到来时,会发出readyRead()信号,为该信号添加槽函数,使用readyRead()
! J8 Q5 B8 Q+ h4 \/ X读取。& E! K; z: ]. Q R
5.socket 发送数据可直接调用 write()成员函数。
: Y& I, w! b3 K u0 W9 X6.关闭端口号。! ?5 x I# J: h/ v( j, K/ C
代码如下:
; d- z+ d/ s2 t+ u3 P0 g+ y% w
5 r/ ]; {" k- ]' W* v+ c#include <QMainWindow>
7 l4 o G: E/ i#include <QTcpServer>/ K' \7 E9 u4 a, E2 e
#include <QTcpSocket> u+ V' {8 w2 _( M( j
namespace Ui {
! d/ R: }: X7 |6 kclass TcpServer;2 E4 k+ S6 R: I, M% K, V
}% j2 H7 t5 H% h; a+ p
class TcpServer : public QMainWindow
0 E. ^# _% |% n, e# o% F/ Y4 c{
$ J/ A( G- o; v; w! K$ }Q_OBJECT
. N' L0 [2 n% m; F0 Upublic:6 H: A( D4 d z- `
; p7 }8 K* s! |1 e
explicit TcpServer(QWidget *parent = 0); ~TcpServer();
( [. ?, o# C! ^4 h# L7 y6 M( N' ?9 WQTcpServer * tcpServer;* i1 W* S! a! B. R# w. H
QTcpSocket * tcpSocket;+ {! U0 }. ^8 N1 R" `* F
public slots:
: a% S4 ~' D' |1 k. w2 ?void newConnection_Slot(void);6 i: S' E8 K, x5 }" z
void readyRead_Solt(void);$ l' v7 J3 v4 `4 e4 Z
private slots:
# _4 j: ]' @ x: o$ k" Cvoid on_openBu_clicked();! Q" m/ ?; Y3 w3 `( s+ n
void on_sendBu_clicked();0 W* ?& F* f6 t& y
void on_closeBu_clicked();
8 ^/ h6 {) g# l- c' I$ C t0 P# Q9 [private: r- |$ w. d; x
Ui::TcpServer *ui;, V* t# d9 b! G r! j' `
};
# A" Z O& K; l2 T9 y#include "tcpserver.h" #include "ui_tcpserver.h" #include <QTcpServer># i0 k) `: R2 J! r
#include <QTcpSocket>
2 t7 Y4 F8 T+ f) m) s- C#include <QString>( h% o& Q$ q# b; r% h' A1 h% j) Z: q
TcpServer::TcpServer(QWidget *parent) :
* O* Q/ {" s3 U! r+ K$ D" x, rQMainWindow(parent), ui(new Ui::TcpServer)7 ^% W w( s8 ~- w, i6 E. I
{
4 ^! z, x: S3 bui->setupUi(this);
q. J4 Y d% E7 OtcpServer = new QTcpServer(this);
( t! b8 B0 k, rtcpSocket = new QTcpSocket(this);
/ [2 Y( ]' ^) M2 ^* k6 f//连接信号与槽函数进行绑定# I3 m% n4 ~6 c$ p# C
connect(tcpServer,SIGNAL(newConnection()),SLOT(newConnection_Slot()));
- w6 ^! Y; O x. X- O}
0 Y+ r) C% t5 o, i( A//连接信号槽函数
# D o0 ~) L, `$ J
2 A9 L8 d( O; q$ z+ Yvoid TcpServer::newConnection_Slot(void)5 D& u( W4 J1 Z+ h4 ^
{
0 c+ A. I2 x' X8 a& U o//连接客户端后 socket: ?! ^ Q4 Y/ s- w( e4 @
tcpSocket = tcpServer->nextPendingConnection();) ?3 u# c- g2 K+ o% e2 c3 Y+ {
//套接字的接收数据信号与都数据槽函数连接: ~% j2 T. c3 F5 B3 g# e, w
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));
4 o9 S" P' \9 D+ ^4 e5 {; Q}( d8 N1 E, G) F
//读取数据4 g A0 l6 u- ~% l: W
void TcpServer::readyRead_Solt(void)
* U2 h/ e3 e2 a1 S{
2 Q7 E3 \+ s- }; _0 T$ k( kQString buf;
3 G1 e3 {* x3 Z( @' ?4 i0 d0 E//读取$ `& v% ?8 v( Y" T8 d5 J/ r4 m
buf = tcpSocket->readAll();
. U5 |4 r, k) X- L& S/ \ui->recvEdit->appendPlainText(buf);
" Z+ A" y/ H) Z3 a- v, m}+ E7 O8 v. r' D+ v I3 Z
TcpServer::~TcpServer()7 O5 B: R; x: k4 r# Z, q
{
1 [6 l% y( K* l0 i: V! Fdelete ui;. x+ B2 Q1 I5 a9 H$ Q% U
}
- q" o- u4 B- ^/ ? I( e/ N//打开$ r/ n' [! M% w1 {
void TcpServer: n_openBu_clicked()/ h5 ]& I2 {! U+ I/ X
{$ L. \- g5 b7 j L
//监听
1 `- \ ^' S% h. ItcpServer->listen(QHostAddress::Any,ui->portEdit->text().toUInt());! Y# r* }' F; b2 ^9 b
}! L2 I+ j, E/ ~+ j
//发送数据+ L1 J3 }7 J: @) l3 M
void TcpServer: n_sendBu_clicked()
, }3 s# a4 m; M3 [5 e{
* b9 u" A+ g+ ^5 PtcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
; P) \8 Q6 m1 }/ r# E}
2 r* e3 z, m4 s9 j0 k4 ]//关闭2 N. D& X' r7 J4 A& {& f B V
void TcpServer: n_closeBu_clicked()2 L, a5 v" t8 k2 }* }' S: x- ], v
; E0 N/ ]6 D% W3 k( ? U
{! D$ H; ^* N- l9 h
tcpSocket->close();
N4 z/ S8 D$ _8 g}. P; l B6 k7 [* O* n- i
步骤四:客户端编程4 e% c% B% |2 e) y2 L6 B
8 x, Z k: N8 f8 J3 F6 [1.创建 QTcpSocket 套接字对象4 ]& a, g1 g, A8 ^7 w5 m
2.使用套接字对象的成员函数去请求连接服务器。1 [! h9 z" l0 N1 P7 a5 e7 i
void connectToHost(const QHostAddress &address, quint16 port, openMode mode = ReadWrite);2 y1 S! E+ G( ?& i( b2 z2 A5 `
第一个参数为服务器 IP 地址,第二个参数为服务器端口号。第三个参数为打开方式,默认为可读可写% F) T9 i: d$ _0 x' @0 Y
函数功能:请求连接服务器连接成功后发出connected()信号,绑定槽函数connected_Solt()去操作socket。8 S/ `: s7 j/ I5 g
3.使用 write 函数向服务器发送数据,当 socket 接收缓冲区有新数据到来时
8 G! ^# h8 Y* d# a7 ?会发出 readyRead()信号,为该信号添加槽函数以读取数据。9 A6 P# A+ E l5 U$ g( Z; T+ x) x9 `
4.断开与服务器的连接。" R( D( G) W0 `( R- s
7 D8 S6 F3 a) P" P0 d6 |, w
class TcpClient : public QMainWindow
4 b. j: Z# M7 O% ^$ \% e7 s{) o6 I) B* Z3 B$ I1 @
....... private slots:7 B; z! q8 y3 B* G
void on_openBt_clicked();; H* S8 V! G7 N# n* J7 ~
void connected_Solt(void);7 x! `* c% p) i$ [# g2 C
void readyRead_Solt(void);
% n! s3 r* g9 p7 d1 P6 U2 wvoid on_sendEdit_2_clicked();
7 a$ ^* G0 U' ~' w, nvoid on_closeBt_clicked();
4 A! I- b8 ?0 q& A};
, _0 [% g2 J; u; N- U7 ~5 C# q' P2 z Y d8 T5 k
TcpClient::TcpClient(QWidget *parent) :
9 C- {3 L2 k0 G& dQMainWindow(parent), ui(new Ui::TcpClient)* s M; `2 V; Z2 v; F3 J: |
{% X2 r% o3 @4 Z; h
ui->setupUi(this);& V3 k2 |3 l! W# |, Z4 ?. D) A
//创建 socket 对象
& ^1 |+ U& [; vtcpSocket = new QTcpSocket(this);" ?: i# z j M' F
}
/ c( b4 n4 a9 S$ ?& K* x0 ~TcpClient::~TcpClient()( V% X8 P3 m4 g; Q! K
{
6 f) y& g# Q' l; |. m9 @/ j* Vdelete ui;
$ F. e! t( m* F% Q8 @}
# P: b8 K# h. a* @//打开(连接服务器)
" w3 a W' P0 N; d- |* xvoid TcpClient::on_openBt_clicked()8 l( W2 _- V4 w
{
M \' ?1 C7 ]4 qtcpSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toUInt());
2 @0 Q7 M! I# B, f# H7 O; U* r8 _connect(tcpSocket,SIGNAL(connected()),this,SLOT(connected_Solt()));
6 E$ K. ~) |- P1 s6 K}# h- R. x+ k- v) B' N& F( ]; ]0 C* V( `( m
//等待数据到来3 V/ ?! s6 X5 l5 N+ t
void TcpClient::connected_Solt(void)$ j, Z3 ?0 ~* E# t/ Q5 \( S7 R
{% p9 Z# `# T4 f, ~' G
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));. n4 d- P1 {# B4 G( \
}
6 Z* ]" t! h9 ]2 F//读取数据4 c- P# W0 r; d) S, W6 V
void TcpClient::readyRead_Solt(void)
. y. w+ V% L3 f c. ~; e# R{
, h: r0 a' g/ y% X0 q* O4 jui->recvEdit->appendPlainText(tcpSocket->readAll());" Q. q+ c7 D5 E4 l
}2 \2 ^4 ^; ~9 t* Z' s
//发送
0 g. M8 b8 z+ v( lvoid TcpClient::on_sendEdit_2_clicked(), @+ h( y% G( I. D7 C
{: ?" n' T2 O( w0 W; B' x+ u
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
7 G& x A1 s1 |9 U9 Y7 M2 ~}
' n" z2 F1 a$ [! y//关闭2 ~/ L' ]' @) I5 q
void TcpClient::on_closeBt_clicked()
3 \' e: Y$ v9 U0 O! ?1 r' I3 i$ \6 Q7 \8 w
{
( t7 I# s( M! ]1 @. g% q7 AtcpSocket->close();7 s' |8 O( r. X3 o& S
}
/ I$ R1 [% ?" {8 k编译运行成功,使用服务器和客户端通信如图:
% d1 I5 s: I# T; [
% l4 I) R9 J! D" Z4 @+ Z
! R4 i6 [! P# K2 [- ]6 _# \
# i9 r' t& W) k5 y% I+ P |
|