基于C++和Qt封装一个简单的socket(TCP/IP)通信UI界面

这篇具有很好参考价值的文章主要介绍了基于C++和Qt封装一个简单的socket(TCP/IP)通信UI界面。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        最近在学习TCP/IP和socket套接字的有关知识,了解了三次握手四次挥手,TCP协议等等一大堆知识,但纸上得来终觉浅。网络上C++代码实现socket通信的资料很多,方便学习,于是想到自己用Qt实现一个基础的具有网络通信收发功能的服务端UI软件。进入正题:

一、UI界面及功能介绍

        此处我们在Windows系统下编程,使用Qt5框架,利用按钮(pushButton)来执行初始化socket和点击发送信息,接收信息和发送信息的窗口则使用文本编辑框(textEdit)来实现。整个界面只有两个按钮和两个文本框,实现的功能十分简单,即作为TCP/IP通信中的服务端,等待客户端连接,并与客户端进行通信。整个UI界面如下:

qt做的界面如何与c++联系起来,qt,c++,tcp/ip

软件流程:

        1.点击初始化按钮,调用bind和listen等函数初始化socket,并调用accept等待客户端连接;

        2. 调用accept同时,弹出对话框(messageBox)提醒正在等待客户端连接;

        3. 客户端连接到本服务端,accept完成,自动关闭对话框;

        4. 在发送窗口输入字符并点击发送进行传输,在接收窗口接收来自客户端的消息。

另外,服务端发送消息失败时考虑客户端已将socket连接断开,所以关闭连接用和当前通信用的socket,恢复初始态,可以进行下一次连接。

二、代码实现

        本部分注释写的比较多,此处不再对代码进行解释,需要注意的点有:

        首先,Qt的主线程为UI线程,所以如果将耗时较长的操作放在主线程,会影响UI界面的绘制和刷新,导致界面阻塞,软件无法正常使用。所以这里的等待客户端连接和接收消息均另外开了线程来运行(std::thread),当然大家也可以使用QThread进行多线程操作。

        其次,在accept阻塞之前发送自定义信号acceptStart(),令消息提示框弹出;连接完成后再次发送另一个自定义信号acceptFinish(),令消息提示框关闭。

        最后,若想实现socket重连功能,则必须先关闭(closesocket)已经失效(断连)的socket,然后再次初始化,否则无法连接。

Server.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_Server.h"
#include <errno.h>
#include <sys/types.h>
#include <thread>
#include <stdio.h>
#include <iostream>
#include<WinSock2.h>
#include<QMessageBox>

#pragma comment(lib,"ws2_32.lib")

class Server : public QMainWindow
{
    Q_OBJECT

public slots:
	bool init_server();
	void send_msg();

signals:
	void acceptStart();
	void acceptFinish();

public:
    Server(QWidget *parent = nullptr);
    ~Server();
	void recv_msg();
	//接收信息线程
	void recv_thread_function();
	//初始化socket线程
	void init_server_thread_function();

private:
    Ui::ServerClass ui;
	static const int BUF_SIZE = 0XFFFF;
	//接收线程和初始化线程
	std::thread *recv_thread, *init_thread;
	//用于连接和用于通信的socket
	int socket_fd, client_fd;
	//ip地址和端口
	std::string server_ip;
	unsigned short server_port;
	//服务端是否工作标志位
	bool isServerWork;
	//接收和发送缓冲区
	char recv_buf[BUF_SIZE];
	char send_buf[BUF_SIZE];
	//开始通信过程
	void start();
	//关闭socket
	void on_disconnected();
	//等待连接时弹出的对话框
	QMessageBox* dialogWait;
};

Server.cpp

#include "Server.h"

Server::Server(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
	//初始化用于连接的socket
	socket_fd = -1;
	server_ip = "127.0.0.1";
	server_port = 8888;
	isServerWork = true;
	dialogWait = new QMessageBox(this);
	dialogWait->setText(QStringLiteral("正在等待客户端连接..."));
	dialogWait->addButton(QMessageBox::Ok);
	connect(ui.pushButtonInit, &QPushButton::clicked, this, &Server::init_server);
	connect(ui.pushButtonSend, &QPushButton::clicked, this, &Server::send_msg);
	connect(this, &Server::acceptStart, this->dialogWait, &QMessageBox::show);
	connect(this, &Server::acceptFinish, this->dialogWait, &QMessageBox::accept);
}

Server::~Server()
{}

void Server::init_server_thread_function()
{
	struct sockaddr_in client;
	int len = sizeof(client);
	if (isServerWork)
	{
		emit acceptStart();//弹出等待对话框
		client_fd = accept(socket_fd, (struct sockaddr*)&client, &len);//此处阻塞直到客户端连接
		if (client_fd == -1)
		{
			perror("accept");
			exit(-1);
		}
		emit acceptFinish();//关闭等待对话框
		char *client_ip = inet_ntoa(client.sin_addr);
		ui.textEditRecv->append(QStringLiteral("连接成功,客户端IP为:"));
		ui.textEditRecv->append(client_ip);
		//服务端和客户端连接后可以开启接收线程
		recv_thread = new std::thread(std::bind(&Server::recv_thread_function, this));
	}
}

bool Server::init_server()
{
	//win系统下必须进行WSAStartup
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0)
	{
		return S_FALSE;
	}
	std::string ip = server_ip;
	unsigned short port = server_port;
	//不进行WSAStartup,socket_fd无法创建成功
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (socket_fd == -1)
	{
		perror("socket");
		exit(-1);
	}
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip.c_str());

	int ret = bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr));
	if (ret == -1)
	{
		perror("bind");
		exit(-1);
	}

	listen(socket_fd, 10);
	ui.textEditRecv->append(QStringLiteral("等待客户端连接..."));
	start();
	return true;
}

void Server::start()
{
	ui.pushButtonInit->setEnabled(false);
	//等待accept会阻塞UI,此处开线程进行处理
	init_thread = new std::thread(std::bind(&Server::init_server_thread_function, this));
}

void Server::send_msg()
{
	if (ui.textEditSend->document()->isEmpty())
		return;
	QString qstrToSend = ui.textEditSend->toPlainText();
	QByteArray ba = qstrToSend.toLatin1();
	char* buf = ba.data();
	memset(send_buf, 0, BUF_SIZE);
	memcpy(send_buf, buf, sizeof(buf));
	int ret = send(client_fd, send_buf, strlen(send_buf), 0);
	//若发送失败,考虑已经断线,可以关闭socket并进行下一步重连
	if (ret < 0)
	{
		on_disconnected();
		ui.textEditRecv->append(QStringLiteral("连接已断开,请重新连接!"));
		ui.pushButtonInit->setEnabled(true);
	}
		
}

void Server::recv_msg()
{
	int recv_size = recv(client_fd, recv_buf, sizeof(recv_buf), 0);
	if (recv_size <= 0)
		return;
	char recv_content[1024];
	memset(recv_content, 0, sizeof(recv_content));
	memcpy(&recv_content, recv_buf, sizeof(recv_content));
	ui.textEditRecv->append(recv_content);
}

void Server::on_disconnected()
{
	closesocket(socket_fd);
	closesocket(client_fd);
}

void Server::recv_thread_function()
{
	while (true)
	{
		recv_msg();
	}
}

三、软件效果

        qt做的界面如何与c++联系起来,qt,c++,tcp/ip

         此处使用的网络调试助手为野人家园的NetAssist软件,在此扮演客户端的角色。下载链接:http://www.cmsoft.cn/download/cmsoft/netassist.ziphttp://www.cmsoft.cn/download/cmsoft/netassist.zip

         该软件依然存在一些问题:如果服务端一直不发送消息给客户端,则无法自动实现关闭socket操作;无法发送中文等等,都是可以改进的方面。文章来源地址https://www.toymoban.com/news/detail-721419.html

到了这里,关于基于C++和Qt封装一个简单的socket(TCP/IP)通信UI界面的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# socket——简单的TCP 客户端 连接通信

    TCP编程的客户端一般步骤是: 1、创建一个socket,用函数socket()。 2、设置socket属性。 3、设置要连接的对方的IP地址和端口等属性。 4、连接服务器,用函数connect()。 5、收发数据,用函数send()和recv(),或者read()和write()。 6、关闭网络连接。 using System; using System.Net; using System.

    2024年02月11日
    浏览(48)
  • 【Unity】Socket网络通信(TCP) - 实现简单的多人聊天功能

    多客户端连接服务器其原理是在服务端保存客户端连入后与客户端通信的socket,由于等待客户端连接会阻塞主线程,所以结合多线程就能实现多客户端连入功能。多人聊天只需要将A客户端发来的消息,转发给除A客户端外的其他客户端,即可实现。如果你还不怎么熟悉服务端

    2024年02月03日
    浏览(62)
  • Socket网络编程(TCP/IP)实现服务器/客户端通信。

    一.前言 回顾之前进程间通信(无名管道,有名管道,消息队列,共享内存,信号,信号量),都是在同一主机由内核来完成的通信。 那不同主机间该怎么通信呢? 可以使用Socket编程来实现。 Socket编程可以通过网络来实现实现不同主机之间的通讯。 二.Socket编程的网络模型如

    2024年02月08日
    浏览(83)
  • socket套接字通信 TCP传输控制协议/IP网络协议 5.18

    B/S :浏览器和服务器 C/S :客户机和服务器 网络的层次结构和每层所使用协议的集合 网络采用分层管理的方法,将网络的功能划分为不同的模块 OSI模型: 共7种: 数据的封装与传递过程: 网络传输数据大小user data: 6~1460 网络传输中容易发生拆包和粘包,所以接收和发送的字节

    2024年02月05日
    浏览(76)
  • Qt6教程之三(13) TCP/IP通讯与socket编程

    目录 一 前言 二 TCP/IP协议架构和通信原理 三 TCP/IP的连接与断开过程 四 Qt中开发TCP/IP原理概述 五 完整实例代码示范 在软件开发中,常用的技术体系里面网络通信属于最重要的 “联通” 技术,是必须要掌握的技术。 那为什么网络通信如此重要呢,我想大概有以下几点: 不

    2024年02月12日
    浏览(40)
  • 【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

    橙色 所谓套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进程通

    2024年02月09日
    浏览(53)
  • 基于python socket实现TCP/UDP通信

    两个应用程序如果需要进行通讯最基本的一个前提就是能够唯一的标示一个进程,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。能够唯一标示网络中的进程后

    2024年02月16日
    浏览(48)
  • Qt TCP简单通信

    在.pro文件中添加网络模块 Qt += network 1. 创建QTcpServer 对象,用于监听,创建套接字等; 2.进行监听,通过QTcpServer对象 QTcpServer::listen(); 3.使用信号槽,connect(), 判断是否有客户端来连接,QTcpServer::newConnection(); 4.在步骤3的基础上,创建套接字,QTcpSocket socketServer = QTcpServer:: nex

    2024年02月11日
    浏览(34)
  • Qt 实现简单的TCP通信

    这段时间用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。 使用QT的网络套接字需要.pro文件中加入一句: 一、客户端 1、客户端的代码比服务器稍简单,总的来说,使用QT中的QTcpSocket类与服务器进行通信只需要以下5步: (1)创

    2024年02月08日
    浏览(45)
  • c/c++开发,c++无可避免的TCP/Socket通信开发实战案例

    目录 一、案例项目设计概括 二,案例整体设计 三、TCP/Socket 的服务端与客户端通信代码设计         3.1 tcp/socket通信        3.2 客户端信息管理         3.3 数据的读取与写入 四、tcp/socket通信扩展        4.1 线程类及消息队列类设计         4.2 读取及写入数据

    2024年02月16日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包