|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
网络编程有 TCP 和 UDP,TCP 编程需要用到俩个类:QTcpServer 和 QTcpSocket。
: r' }" g. n0 m8 ]3 R* U& o
+ d' f2 N* O) ^6 k9 h
1 TCP 实现服务器和客户端9 n$ ^) D% M6 o! q
TCP 协议(Transmission Control Protocol)是一种面向连接的,可靠的,基于字节流的传输层通信协议,传输数据稳定可靠。
: D6 y% o- Z1 b3 n在 help 索引中搜索到如图 两个重要类:$ S% R# ?8 i/ ~6 h( s
; ^' h& b3 K1 C! S服务器编程中两个类都会用到,客户端编程中只会用到 QTcpSocket 对象。% W. L0 @& {% M+ b- F$ u) v
本实验中对 QTcpServer 类的基本使用:1 k, Y. I6 T- D' [7 `* b* y
(1)监听客户端连接。
3 }% _; Q; I6 F8 K" w(2)每当有新的客户端连接服务器的时候,会自动触发信号,
( ^$ u& G3 w* B( f7 g/ I(3)根据当前连接上的新的客户端创建一个 Socket 对象,将数据的收发动作交给 socket 套 接字去处理。7 f1 f4 i1 O: }! {( h) P
(4)关闭服务器 close();( b8 D8 w& \6 s# S
对 QTcpSocket 类的基本使用:
- j- n2 a/ B3 L; x(1)服务器端:有新连接时获取连接状态,绑定 socket 。2 V( `- ?, Z# Q, m
(2)客户端:通过 socket 连接服务器,连接成功触发信号。
2 {0 {* c# ~4 u6 m- S3 J3 b- `$ j8 a
0 o" p! J' f2 y2 s0 d(3)当有数据到来时会触发信号,用 readAll()读取。& D8 ^% ?# V8 r
(4)通过读写 socket 收发数据。+ e- y' _$ g- t; o0 I
具体步骤:, K. n% o9 O A
步骤一:创建工程,在工程文件.pro 中添加 network,如图:
# G# s% o+ P2 c
! \1 {% a0 U- C. F
步骤二:设计 ui 界面,% @% g. u& j7 t! i$ }
1. 在属性编辑栏设置主窗口大小:( {5 ?2 a6 }* v K4 ^, y
- y3 E" I( G) c W9 Q2. 添加组件
, G$ t' B3 r- v$ ], i* d接收窗口: Plain Text Edit
; m8 ~3 B. \" ?# I K发送窗口,IP 地址窗口,端口号窗口:Line Edit
' D, U5 Q# s; j' f$ z打开服务器,关闭服务器:Push Button+ h5 |' F( L9 R- h2 b6 T& O+ {0 I
拖拽完成后逐个布局,根据需要设置组件大小,这里端口号框设置成了最小 200) J+ t$ Z2 R& q9 a2 u
/ M3 c* E8 [! y+ Y' z& j# ?
按钮布局:拖拽按钮和弹簧,然后点击水平布局。, F* P1 ]9 z- d) l5 I; {* m" z/ y- x
9 v( l' c4 n( t0 o2 {1 K$ V8 f2 i然后选中全部组件,点击栅格布局:
! k, ]' v9 r h7 M3 k# D
; A$ Z6 l/ R$ x; u- U最后更改组件名称注释,完成后如图 :& _4 ^6 W3 u% M& N+ b
# \$ }5 Z* ^5 A' S) \# q- ~
步骤三:服务器端编程:
* J+ i/ W7 L9 H, S; @1.创建 QTcpServer 对象8 |$ K- |* v! w0 K
2.创建监听端口,使得客户端可以使用这个端口访问服务器,使用 listen 函数。 u3 ~3 s$ m; f- Q
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
; l. g) s$ @/ E第一个参数是绑定指定的地址(即本机服务器 IP),第二个参数是绑定的本服务器端口号。3 x" K& C z6 T0 \- R( g
监听某个端口时,如果有新连接进来就发出 newConnection()信号。8 Q5 ] a" m( T9 C$ l
3.当服务器对象被访问时,会发出 newConnection()信号,所以为该信号添加槽函数并用一个 QTcpSocket
9 Z5 T: i1 u; B# H+ Z对象接受客户端的访问。8 d$ z W3 x) m5 o/ h" F$ b
4.当socket接受缓冲区有新数据到来时,会发出readyRead()信号,为该信号添加槽函数,使用readyRead()+ s) F2 r6 m$ D6 {* X0 D* A$ L1 m, a
读取。6 t' R3 Y+ B$ v& k% \' ^) s& W0 a2 s5 K
5.socket 发送数据可直接调用 write()成员函数。
7 X* h0 ], l! H8 p. B5 e- y" J6.关闭端口号。- ]# v* [$ T/ R( n1 @
代码如下:0 c5 g( O: \; p
- Z* i5 j' d# C( }, [#include <QMainWindow>6 C/ t, h: ]' t2 K, I5 R
#include <QTcpServer>. Q% U( j' @0 q. D
#include <QTcpSocket> g- ?) E3 C, z9 d; P6 W
namespace Ui {: p' k* F3 D) _
class TcpServer;( C# S2 M j, f. q2 x% G5 C8 j7 j* F4 i
}
% }3 M; s+ {1 |5 @5 ~class TcpServer : public QMainWindow
8 K/ b' e" `: x _7 z. v6 N{2 T' j0 z( {+ Z9 q9 ?% j
Q_OBJECT! U3 e2 Z: Z: u8 f
public:4 @1 H- `- r! N3 E; C
4 U# n: }% T/ f( v: [explicit TcpServer(QWidget *parent = 0); ~TcpServer();4 K2 Y% d p4 N% f/ g3 e% |( W
QTcpServer * tcpServer;9 u+ ^8 N! e- T
QTcpSocket * tcpSocket;$ W' V4 G/ M, {: _" @( Z n
public slots:7 S4 R/ J @+ |6 {3 |! J
void newConnection_Slot(void);! d4 t0 k* W+ N/ f
void readyRead_Solt(void);0 L& b/ N' I$ d0 i
private slots:) r# N: {% O' d3 J3 v
void on_openBu_clicked();$ `8 G# E! |+ Y& x( I1 t
void on_sendBu_clicked();* X% w) ^/ n3 N( T, Z
void on_closeBu_clicked();6 ^6 Y; v4 \9 U) m# w3 C9 o z
private:
/ F+ h" v# {( |+ A8 j8 Y3 W JUi::TcpServer *ui;
! N$ K( n/ z6 J& ?9 _& d3 k};
* a, d* y5 ~% E: s#include "tcpserver.h" #include "ui_tcpserver.h" #include <QTcpServer>
0 Y# R+ b2 `$ S# n9 W! z#include <QTcpSocket>
; u' W$ ^: M7 U#include <QString>
4 J' Z" L* c; H4 `0 u; _TcpServer::TcpServer(QWidget *parent) :' o% V0 g5 ]4 V9 j* R. V7 b' U
QMainWindow(parent), ui(new Ui::TcpServer)
3 L: l& g0 \1 q1 j- j: O l{- m5 F$ Q9 x9 R5 E; _
ui->setupUi(this);
- N2 `8 @: r R$ A6 _2 q/ AtcpServer = new QTcpServer(this);: `) T3 F( m7 }9 q4 ^+ y5 s
tcpSocket = new QTcpSocket(this);
; m' P/ A5 [% V' P- n, T8 |//连接信号与槽函数进行绑定
& \, D& @1 ^% H+ C# sconnect(tcpServer,SIGNAL(newConnection()),SLOT(newConnection_Slot()));+ A1 k; V) u& x) E% e4 ^* P T
}
& y/ f- D( e" k8 H1 X9 C5 g//连接信号槽函数1 }. u N) N% V1 C
: |1 }4 j3 P' l* g
void TcpServer::newConnection_Slot(void)0 \0 r8 k5 b1 K, n; b$ ] h
{
" i6 d# B5 _9 _1 ]$ D//连接客户端后 socket. n* |7 S0 L4 A) j5 R
tcpSocket = tcpServer->nextPendingConnection();! o! A% o! _# c
//套接字的接收数据信号与都数据槽函数连接
( K7 O4 V7 a( f Xconnect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));
# v3 @5 c3 t1 @% v}; ]( N8 t6 z1 N
//读取数据
' v4 W& r# Z. o( A h1 Pvoid TcpServer::readyRead_Solt(void)
- N: ^# L9 k- s; F e{* W9 Q( d* a X2 L( ]8 c, t L, m
QString buf;
6 _/ D2 Z) X9 s+ ]8 P//读取
1 F/ k" B1 N9 Z) X2 q1 Sbuf = tcpSocket->readAll();" Z% ^/ G( H1 [6 K* o1 K: t
ui->recvEdit->appendPlainText(buf);; n( ~& Q F: l8 h, z4 D
}
" N$ d! x6 ^+ Z8 i+ r' t' l+ YTcpServer::~TcpServer()9 V' q+ @) F! q+ {# Y
{
- p8 v* }2 r9 }* `! F% B) f9 cdelete ui;
' ]8 y7 f- H5 Z}5 ]. g0 q5 M; M& N* e9 s
//打开4 _2 h( b7 a$ V! o7 L5 ^# A1 T
void TcpServer: n_openBu_clicked() t- x3 c! v5 S! } i9 t
{
. i! [$ {% X8 e5 W) ]) c) q//监听/ E2 X: ?) K# ~( m
tcpServer->listen(QHostAddress::Any,ui->portEdit->text().toUInt());
5 V6 M) K# K* m3 g* s/ @' M}
+ y6 S5 w- i* D//发送数据1 N) Y$ m- H( k0 ~8 k
void TcpServer: n_sendBu_clicked()
4 e* p! f! g. m6 N{0 M8 N) k. Z! v: i7 Z" |
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());: f% r; z5 X. s1 F) n1 ~2 v
}! C; g: l7 k( A- r
//关闭 J3 ~7 u! f8 q; v9 Y; o
void TcpServer: n_closeBu_clicked(). W# t) S+ L; T ]9 ]
4 ~0 B, [( w3 h7 }6 g, K- R4 o
{& j2 \- b- c5 I0 B
tcpSocket->close();4 a5 @+ |7 d" W2 Y( V* w3 s
}: ^8 i5 h0 X+ A; L Y% {
步骤四:客户端编程
3 Z1 p( C, \4 t# m3 {7 g
2 O+ @1 n( H9 X9 w- Z4 l
1.创建 QTcpSocket 套接字对象8 P, y# O( z" a& Z3 Y
2.使用套接字对象的成员函数去请求连接服务器。) O! v) u* S6 r( |
void connectToHost(const QHostAddress &address, quint16 port, openMode mode = ReadWrite);
' O+ w: R( h5 x- g$ h+ N/ X第一个参数为服务器 IP 地址,第二个参数为服务器端口号。第三个参数为打开方式,默认为可读可写6 o6 J3 r: B% \
函数功能:请求连接服务器连接成功后发出connected()信号,绑定槽函数connected_Solt()去操作socket。
7 I. Q+ f& z; {, {# C0 O, k: x3.使用 write 函数向服务器发送数据,当 socket 接收缓冲区有新数据到来时
! O. Z- m" B2 Q8 _) A会发出 readyRead()信号,为该信号添加槽函数以读取数据。
8 `" @9 p( G/ M' m; {4.断开与服务器的连接。4 w! k2 u0 G" K! O
. F' M8 C6 G# t7 f1 \! \; Rclass TcpClient : public QMainWindow7 l( Y2 ]0 Q* `* U& U% a
{5 i9 B0 J8 c5 l; i
....... private slots:
1 U8 z3 \ K" }5 jvoid on_openBt_clicked();
2 @! q3 W2 d+ E, n+ Vvoid connected_Solt(void);6 [& R2 j* q8 Y. A" ~
void readyRead_Solt(void);
) D5 c& g2 }) D5 g! r$ Kvoid on_sendEdit_2_clicked();0 R9 ]$ H4 ]& T5 |; j# S
void on_closeBt_clicked();* `' a2 ^# u3 Y# V& O6 u3 h& y
};, O$ X% f* _, @ }
$ z: i; i# Z% d q0 d7 N; f/ }TcpClient::TcpClient(QWidget *parent) :
0 d& e6 \% p$ o7 N6 a8 A# {: ?QMainWindow(parent), ui(new Ui::TcpClient)
7 f G6 E) {) T. D7 w; n{
. _; W; _: |! Z/ W3 zui->setupUi(this);
9 j2 s# M4 M; K1 G//创建 socket 对象. z. d x N7 [' T8 }
tcpSocket = new QTcpSocket(this);7 \4 j& x4 W1 q+ H* c' [
}
8 D9 m+ q. T# r8 `9 Z. _: ]- MTcpClient::~TcpClient()- F& Z& s* B5 [
{7 s7 b4 P5 h& y
delete ui;& a" X0 ~) p$ x, ?5 c
}' E" G7 e5 Y J# p/ ]; A7 _
//打开(连接服务器)
, O6 h* o/ d2 Q: T5 Y; Z5 zvoid TcpClient::on_openBt_clicked()
$ ~& L" X( ~1 q# P{ Y! ~# t& b% v, n
tcpSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toUInt());! I. d: o; W0 ]. n* o, e
connect(tcpSocket,SIGNAL(connected()),this,SLOT(connected_Solt()));5 ]% x! \( o2 h5 l
}9 y) G4 I5 L" d* T- B9 z" ^
//等待数据到来2 p" q9 F7 a5 p# z
void TcpClient::connected_Solt(void); a0 `8 i( t ]8 I0 E6 C
{
/ G5 h% c. H( k8 i( L6 V3 Nconnect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Solt()));# Z( C: V3 v4 Q: s* v$ u2 T) _6 s2 }
}$ _" t# b6 X+ _" n. k7 B
//读取数据1 k2 s# K6 D H( c. ^4 ]" P
void TcpClient::readyRead_Solt(void)2 w% s" n. x8 N9 m; s
{1 T! ^; W( @! X" L
ui->recvEdit->appendPlainText(tcpSocket->readAll());
7 p' f% E# D! \- e& c}6 q" ^% y. N6 ^5 c. x4 d' B
//发送
1 H7 o% f; z8 X R7 f/ m) Xvoid TcpClient::on_sendEdit_2_clicked()
! K; F" A1 x S{
( E7 Z4 |/ ?' {9 r8 H2 l. ttcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());2 t2 P% y' `# o" q& s0 p
}5 W9 C7 t3 O B! Z6 `: c2 s, A
//关闭
0 ^- f4 k* k1 q: Tvoid TcpClient::on_closeBt_clicked()
+ q/ P8 Y3 R4 @) }$ U
( A5 J0 X2 ?; ~2 T0 d) u{
( U W% ?- d& \% K- y" `tcpSocket->close();1 _) B7 q4 p" i6 R5 @
}
* f _. R$ q3 w编译运行成功,使用服务器和客户端通信如图:% @2 N/ d8 |: s3 j- @
2 Z* Z: R/ w. {
7 Y9 t+ [ f S& ?3 t5 `
7 O' o& P# k; k4 t" M, N' F3 d2 d( S
|
|