windows提供了 winsock2函数库,支持 tcp编程。本博客简单演示qt 结合 vs2017,实现tcp客户端。
代码分为两个文件:ClientTCP和ClientThread。clientTCP只提供一个Qwidget的窗体,用于显示从tcp服务器端发来的数据;clientThread继承自QThread,周而复始的接收从服务器发来的数据,然后交给ClientTCP显示。tcp socket的创建也由ClientThread完成。
代码:
main.cpp
#include "ClientTCP.h"
#include <QtWidgets/QApplication>
#include "ClientThread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ClientThread thrd;
ClientTCP w;
w.show();
return a.exec();
}
ClientTCP.H
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_ClientTCP.h"
class ClientTCP : public QMainWindow
{
Q_OBJECT
public:
ClientTCP(QWidget *parent = Q_NULLPTR);
~ClientTCP();
static ClientTCP * pGetInstance(void);
void setMsg(char *);
private:
Ui::ClientTCPClass ui;
private slots:
void OnClickConnect(void);
};
ClientCP.cpp
#include "ClientTCP.h"
#include "ClientThread.h"
ClientTCP * pInstance = NULL;
ClientTCP::ClientTCP(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
pInstance = this;
connect(ui.BtnConnect, SIGNAL(clicked()), this, SLOT(OnClickConnect()));
}
ClientTCP::~ClientTCP()
{
}
ClientTCP * ClientTCP::pGetInstance(void)
{
return pInstance;
}
void ClientTCP::setMsg(char * pMsg)
{
ui.label->setText(QString(pMsg));
}
void ClientTCP::OnClickConnect(void)
{
ClientThread * pThread = ClientThread::pGetInstance();
pThread->start();
}
clientThread.h
#pragma once
#include <winsock.h>
#include <QThread>
#pragma comment(lib, "Ws2_32.lib")
class ClientThread : public QThread
{
public:
ClientThread();
~ClientThread();
static ClientThread * pGetInstance();
SOCKET m_socket;
protected:
void run();
};
clientThread.cpp
#include "ClientThread.h"
#include "ClientTCP.h"
int MFCconnect(SOCKET skt, const sockaddr * pAddr, int iLen)
{
return connect(skt, pAddr, iLen);
}
ClientThread * pInstance = NULL;
ClientThread::ClientThread() : QThread()
{
pInstance = this;
}
ClientThread::~ClientThread()
{
terminate();
}
void ClientThread::run()
{
WSAData wsaData;
int iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (0 == iRet)
{
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET != m_socket)
{
sockaddr_in saServer;
saServer.sin_family = AF_INET; //地址家族
saServer.sin_port = htons(5050); //注意转化为网络节序
saServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (SOCKET_ERROR != MFCconnect(m_socket, (const sockaddr *)&saServer, (int)sizeof(saServer)))
{
ClientTCP * pDlg = ClientTCP::pGetInstance();
while (true)
{
char szBuf[256] = { 0 };
short sRet = recv(m_socket, szBuf, 250, 0);
if (SOCKET_ERROR == sRet)
{
int nError = WSAGetLastError();
break;
}
else if (0 == sRet)//链接断开
{
int nError = WSAGetLastError();
break;
}
else
{
pDlg->setMsg(szBuf);
}
}
WSACleanup();
}
}
}
}
ClientThread * ClientThread::pGetInstance()
{
return pInstance;
}
假如tcp服务器与客户端断开,clienthread将自动跳出while循环。用户再次点击"connect"按钮,会重新建立链接。
效果:
1)启动网络助手,设置为服务器模式,且端口设为5050,IP为127.0.0.1
2)启动自己的客户端程序,点击connect按钮
3)点击后,你会发现网络助手的界面浮现出客户端的信息
4)点击发送按钮,网络助手输入框中的字符就显示再客户端的界面上