QT学习之旅 - Winsock入门

文章目录

      • 服务端
        • 初始化
        • 为服务器创建套接字
        • sockaddr和sockaddr_in
        • inet_addr
        • htonl()、htons()、ntohl()、ntohs()四个函数
          • htonl()函数
          • htons()函数
          • ntohs()函数
          • ntohl()函数
          • 这些函数存在的意义(就是为了字节存放)
      • 绑定
        • getsockopt
        • udp主函数处理
      • 客户端

客户端和服务器应用程序的前几个步骤相同。

  • 关于服务器和客户端
  • 创建一个基本的Winsock应用程序
  • 正在初始化Winsock

服务端

  • 初始化Winsock。
  • 创建一个套接字。
  • 绑定套接字。
  • 听取客户端的套接字。
  • 接受来自客户端的连接。
  • 接收和发送数据。
  • 断开链接。

初始化

  1. 添加头文件
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
  1. 初始化Winsock
WSADATA wsaData;
  1. 调用WSAStartup并将其值作为整数返回并检查错误。
/*
0: 失败
非0:成功
*/
//WSAStartup(MAKEWORD(2,2), &wsaData)
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {//成功qDebug("winsock initialization FAILED.");
}

调用WSAStartup函数以启动WS2_32.dll的使用。

#pro文件
#...
LIBS += -lWs2_32
#...

完整初始化

UdpThread::UdpThread()
{//注意可以写在别的程序中,所以可以不用管线程//sockVersion = MAKEWORD(2,2);//声明调用不同的Winsock版本if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {qDebug("winsock initialization FAILED.");}
}

为服务器创建套接字

初始化之后,必须实例化SOCKET对象以供服务器使用。

getaddrinfo函数用于确定sockaddr结构中的值:

  • AF_INET用于指定IPv4地址族。
  • SOCK_STREAM用于指定流套接字。
  • IPPROTO_TCP用于指定TCP协议。
  • AI_PASSIVE标志表示调用者打算在调用bind函数时使用返回的套接字地址结构。 当设置AI_PASSIVE标志并且getaddrinfo函数的nodename参数是NULL指针时,套接字地址结构的IP地址部分对于IPv4地址设置为INADDR_ANY,对于IPv6地址设置为IN6ADDR_ANY_INIT。

创建套接字

SOCKET sockWIN;
//udpThread->sockWIN: SOCKET sockWIN;
if(udpThread->sockWIN != INVALID_SOCKET){//INVALID_SOCKET:检查错误以确保套接字是有效的套接字closesocket(udpThread->sockWIN);//关闭套接字
}
/*
AF_INET:IPv4
SOCK_DGRAM:  是无保障的面向消息的socket,主要用于在网络上发广播信息(UDP)
SOCK_STREAM: 是有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料(如文件)传送。(TCP)
IPPROTO_UDP: 用于指定UDP协议
*/
udpThread->sockWIN = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(udpThread->sockWIN == INVALID_SOCKET){//INVALID_SOCKET:检查错误以确保套接字是有效的套接字QMessageBox::critical(this, tr("错误"), tr("无法创建 Socket!"));//显示提示return;
}

sockaddr和sockaddr_in

sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了,如下:

struct sockaddr {  sa_family_t sin_family;//地址族char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
}; 

sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下:

struct sockaddr_in {short	sin_family;				//地址组(Address Family)u_short	sin_port;				//16位TCP/UDP端口号struct in_addr	sin_addr;		//32位IP地址char	sin_zero[8];			//不使用
};

sin_portsin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序(HBO)。

inet_addr

ip地址转换函数

htonl()、htons()、ntohl()、ntohs()四个函数

htonl()函数

函数原型是:uint32_t htonl(uint32_t hostlong)
其中,hostlong是主机字节顺序表达的32位数,htonl中的h–host主机地址,to–to,n–net网络,l–unsigned long无符号的长整型(32位的系统是4字节)
函数返回值是一个32位的网络字节顺序;
函数的作用是将一个32位数从主机字节顺序转换成网络字节顺序。

htons()函数

函数原型是:uint16_t htons(uint16_t hostlong)
其中,hostlong是主机字节顺序表达的16位数,htons中的h–host主机地址,to–to,n–net网络,s–signed long无符号的短整型(32位的系统是2字节)
函数返回值是一个16位的网络字节顺序;
函数的作用是将一个16位数从主机字节顺序转换成网络字节顺序,简单的说就是把一个16位数高低位呼唤。

ntohs()函数

函数原型是:uint16_t ntohs(uint16_t hostlong)
其中,hostlong是网络字节顺序表达的16位数,ntohs中的,n–net网络,to–toh–host主机地址,s–signed long有符号的短整型(32位的系统是2字节)
函数返回值是一个16位的主机字节顺序;
函数的作用是将一个16位数由网络字节顺序转换为主机字节顺序,简单的说就是把一个16位数高低位互换。

ntohl()函数

函数原型是:uint32_t ntohs(uint32_t hostlong)
其中,hostlong是网络字节顺序表达的32位数,ntohs中的,n–net网络,to–toh–host主机地址,s–unsigned long无符号的短整型(32位的系统是4字节)
函数返回值是一个32位的主机字节顺序;
函数的作用是将一个32位数由网络字节顺序转换为主机字节顺序。

这些函数存在的意义(就是为了字节存放)

说到这部分需要引入字节存放的两个概念一个是“大端顺序”,一个是“小端顺序”。俗称“小尾顺序”、“大尾顺序”。
简单的说就是对应数据的高字节存放在低地址,低字节存放在高地址上就是大端顺序,对应数据的高字节存放在高地址,低字节存放在低地址上就是小端顺序。

绑定

if (bind(udpThread->sockWIN, (sockaddr *)&udpThread->locAddr,sizeof(udpThread->locAddr)) == SOCKET_ERROR){//绑定错误closesocket(udpThread->sockWIN);udpThread->sockWIN = INVALID_SOCKET;QMessageBox::critical(this, tr("错误"), tr("端口无法打开或被占用!"));return;}

getsockopt

//获取一个套接字
int getsockopt(int socket, int level, int option_name,void *restrict option_value, socklen_t *restrict option_len);

socket:文件描述符

  • level:协议层次
    • SOL_SOCKET 套接字层次
    • IPPROTO_IP ip层次
    • IPPROTO_TCP TCP层次
  • option_name:选项的名称(套接字层次)
    • SO_BROADCAST 是否允许发送广播信息
    • SO_REUSEADDR 是否允许重复使用本地地址
    • SO_SNDBUF 获取发送缓冲区长度
    • SO_RCVBUF 获取接收缓冲区长度
    • SO_RCVTIMEO 获取接收超时时间
    • SO_SNDTIMEO 获取发送超时时间
  • option_value:获取到的选项的值
  • option_len:value的长度

返回值:
成功:0
失败:-1

getsockopt(udpThread->sockWIN, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, &optLen);

udp主函数处理

//1. 来约束是否开启关闭线程
static bool isNetOpen = false;
NET_OPEN = false;
if(isNetOpen == false){
//ui界面样式,用来提醒可以不用管if(ui->pushButton_openNet->text() == "打开网络"){ui->pushButton_openNet->setText(tr("关闭网络"));ui->pushButton_openNet->setStyleSheet("QPushButton{background:yellow}");}else if(ui->pushButton_openNet->text() == "关闭网络"){ui->pushButton_openNet->setText(tr("打开网络"));ui->pushButton_openNet->setStyleSheet("QPushButton{background:none}");}//2.套接字赋值udpThread->sockWIN = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//udpThread->sockWIN: SOCKET sockWIN;//3.检查套接字是否正确if(udpThread->sockWIN != INVALID_SOCKET){//INVALID_SOCKET:检查错误以确保套接字是有效的套接字closesocket(udpThread->sockWIN);//关闭套接字}//4.创建socket是否成功if(udpThread->sockWIN == INVALID_SOCKET){//INVALID_SOCKET:检查错误以确保套接字是有效的套接字QMessageBox::critical(this, tr("错误"), tr("无法创建 Socket!"));//显示提示return;}ConfigDialog::Settings p = setting->settings(); //里面就只是本地和对方ip端口组播的值,可以修改成自己看的懂的//5.设置本地ip地址端口udpThread->locAddr.sin_family = AF_INET;udpThread->locAddr.sin_addr.S_un.S_addr = inet_addr(p.locIP.toStdString().data());udpThread->locAddr.sin_port = htons(p.locPort.toUInt());//6.设置对方ip地址端口udpThread->rmtAddr.sin_family = AF_INET;udpThread->rmtAddr.sin_addr.S_un.S_addr = inet_addr(p.DevIP.toStdString().data());udpThread->rmtAddr.sin_port = htons(p.DevPort.toUInt());//7. 绑定套接字,地址if (bind(udpThread->sockWIN, (sockaddr *)&udpThread->locAddr,sizeof(udpThread->locAddr)) == SOCKET_ERROR){//判断绑定是否出错closesocket(udpThread->sockWIN);udpThread->sockWIN = INVALID_SOCKET;QMessageBox::critical(this, tr("错误"), tr("端口无法打开或被占用!"));return;}//8.获取套接字,把套接字中的数据清0/* set socket buffer size */int optVal = 0;int optLen = sizeof(optVal);getsockopt(udpThread->sockWIN, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, &optLen); //获取套接字,并获取接收缓冲区长度//9.获取套接字,把套接字中的数据设置为8M大小optVal = 8*1024*1024;//8M大小#if USE_TEST//只是为了测试,可以定义#define USE_TEST 1打开int testRes = setsockopt(udpThread->sockWIN, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, optLen);//获取套接字,并获取接收缓冲区长度#elsesetsockopt(udpThread->sockWIN, SOL_SOCKET, SO_RCVBUF, (char*)&optVal, optLen);//获取套接字,并获取接收缓冲区长度#endifconnect(udpThread, SIGNAL(recvPingTop(quint32,quint32,quint32)), this, SLOT(plotPingTop(quint32,quint32,quint32)),Qt::QueuedConnection);connect(udpThread, SIGNAL(recvRmsTop()), this, SLOT(plotRmsTop()),Qt::QueuedConnection);#if USE_TEST	//只是为了测试,可以定义#define USE_TEST 1打开qDebug() << "testRes:" << testRes; //0:连接成功#endif//显示状态setWindowTitle(QString("XHCJTest 杭州矢志信息科技有限公司 -")+p.locIP);showStatus(tr("连接已建立,本地:%1:%2,组播:%3,存储路径:%4;").arg(p.locIP).arg(p.locPort));//显示本地组播存储地址,这里只有本地/*初始化*///自己自行添加可以是memset(x,0,sizeof(x));//10.开启线程udpThread->start();}else {//10.或者关闭线程udpThread->stop();}

客户端

  • 初始化Winsock。
  • 创建一个套接字。
  • 连接到服务器。
  • 发送和接收数据。
  • 断开链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/26953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webpack基础知识九:如何提高webpack的构建速度?

一、背景 随着我们的项目涉及到页面越来越多&#xff0c;功能和业务代码也会随着越多&#xff0c;相应的 webpack 的构建时间也会越来越久 构建时间与我们日常开发效率密切相关&#xff0c;当我们本地开发启动 devServer 或者 build 的时候&#xff0c;如果时间过长&#xff…

那些 MySQL 8.0 中的隐藏特性

在本文中&#xff0c;我想讨论 MySQL 8.0 中的几个相当新的特性&#xff0c;以及一个较老的特性。这些可能是您不知道的次要功能&#xff0c;但值得快速了解一下它们的工作方式以及在某些情况下可能的用途。 作者&#xff1a;Corrado Pandiani 本文来源&#xff1a;Percona 官网…

电源控制--品质因素Q值全解

什么是品质因素Q值&#xff1f; 在电源控制中&#xff0c;品质因素 Q 值通常用于描述电源滤波器的性能。电源滤波器用于减小电源中的噪声和干扰&#xff0c;以提供干净稳定的电源供应给电子设备。 品质因素 Q 值在电源滤波器中表示滤波器的带宽和中心频率之比&#xff0c;用于…

IP提取器对比器

需求&#xff1a; 一个html 页面 &#xff0c;有两个输入框 第一个输入框输入文本中包含多个ip&#xff0c;输入的ip是不规则的&#xff0c;需要使用正则表达式提取出 输入文本的ip地址 &#xff0c; 然后在第二个输入框中输入内容&#xff0c;并提取出内容的ip &#xff0c;如…

Spark 内存管理之 MemoryConsumer

MemoryConsumer 是内存的使用者&#xff0c;如 sort, shuffle。MemoryConsumer 的 spill 方法是抽象方法&#xff0c;由子类提供。 MemoryConsumer 的字段和构造方法如下&#xff1a; public abstract class MemoryConsumer {protected final TaskMemoryManager taskMemoryMan…

Linux进程间通信--msgsnd函数的作用

msgsnd函数用于将消息发送到消息队列中。它的原型如下&#xff1a; int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数解释&#xff1a; msqid&#xff1a;消息队列标识符&#xff0c;由msgget函数返回。msgp&#xff1a;指向要发送的消息的指针&…

改变vue循环生成的盒子样式,给点击的某一个盒子添加不同的样式

1.给盒子添加动态属性:class"[index isActive?active-box:choose-box]" <div v-for"(item,index) in zyList" :key"item.sid" :class"[index isActive?active-box:choose-box]" click"getKmList(item,index)"…

大数据开发的学习路线是什么样的

大数据技术的体系庞大且复杂&#xff0c;每年都会涌现出大量新的技术&#xff0c;目前大数据行业所涉及到的核心技术主要就是&#xff1a;数据采集、数据存储、数据清洗、数据查询分析和数据可视化。 学习大数据需要掌握什么语言基础&#xff1f; 1、Java基础 大数据框架90%以…

什么是OCR?OCR技术详解

光学字符识别(Optical Character Recognition)简称为“OCR”。ORC是指对包含文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的技术。 一般包括以下几个过程&#xff1a; 1.图像输入 针对不同格式的图像&#xff0c;有着不同的存储格式和压缩方式。目前&…

Elastic:linux设置elasticsearch、kibana开机自启

0. 引言 每次启动服务器都要手动启动es服务&#xff0c;相当之不方便&#xff0c;为此&#xff0c;书写一个脚本&#xff0c;实现es、kibana的开机自启 1. 原理 首先任何服务要实现开机自启&#xff0c;都可分为如下三步&#xff1a; 1、在/etc/init.d目录下创建启动、关闭服…

C#设计模式(15)命令模式(Command Pattern)

命令模式&#xff08;Command Pattern&#xff09; 命令模式是一种数据驱动的设计模式&#xff0c;属于行为型模式类别。请求被包装在一个对象中作为命令&#xff0c;并传递给调用对象。调用对象寻找可以处理该命令的合适对象&#xff0c;并将命令传递给相应的对象&#xff0c…

海康威视摄像头配置RTSP协议访问、onvif协议接入、二次开发SDK接入

一、准备工作 (1)拿到摄像头之后,将摄像头电源线插好,再将网线插入到路由器上。 (2)将自己的笔记本电脑也连接到路由器网络,与摄像头出在同一个局域网。 二、配置摄像头 2.1 激活方式选择 第一次使用设备需要激活,在进行配置。 最简单,最方便的方式是选择浏览器激…

uniapp创建项目入门【详细】

大家在学习vue和微信小程序之后&#xff0c;就可以开始来学习uniapp了&#xff0c;在uniapp中&#xff0c;一套代码可以跨越所有的平台&#xff0c;可以很方便的维护。接下来我们先来学习如何创建uinapp的项目 一、uniapp的创建需求 大家只要会vue和微信小程序的基础来学习unia…

在CentOS7安装部署GitLab服务

CentOS 7 安装 Gitlab 官方安装教程&#xff1a;https://about.gitlab.com/install/ 参考安装教程&#xff1a;https://developer.aliyun.com/article/74395 安装配置 Step1&#xff1a;配置yum源 vim /etc/yum.repos.d/gitlab-ce.repo存入以下内容&#xff1a; [gitlab-c…

目标分割后 opencv 轮廓骨架计算

opencv获取轮廓 contours, hierarchy = cv2.findContours(mask_i, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)获取分割图像的骨架 # 中轴变换 得到裂缝的骨架使用 skimage.morphology.skeletonize 函数对二值化图像进行骨架提取。skeleton = skeletonize(mask_i, method

浅析 String

浅析String 一、创建字符串二、字符串与常量池三、字符串的不可变性四、字符串的拼接五、StringBuilder和StringBuffer 一、创建字符串 //三种常用的构造字符串的方式public static void main(String[] args) {String str1 "hello";String str2 new String("w…

恢复swp文件

swp文件_.swp文件_luminous_you的博客-CSDN博客 三、恢复源文件 正常URL:xxx/m.php 则尝试URL:xxx/.m.php.swp下载.swp文件代码 假设你的swp文件叫’.m.php.swp’ 可用带-r参数编辑#vi -r m.php 然后wq保存即可

图论 <最短路问题>模板

图论 <最短路问题> 有向图 1.邻接矩阵&#xff0c;稠密图 2.邻接表 &#xff08;常用&#xff09;单链表&#xff0c;每一个点都有一个单链表 &#xff0c;插入一般在头的地方插&#xff0c; 图的邻接表的存储方式 树的深度优先遍历 特殊的深度优先搜索&#xff0c…

Python检查端口是否打开(七种方法)

sock.connect_ex 使用socket模块的connect_ex来判断端口是否打开&#xff0c;如果返回值是0表示连接成功&#xff0c;端口打开&#xff0c;否则端口关闭。 import socketdef check_port(ip, port): sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeo…

Python导出SqlServerl数据字典为excel

sql代码 SELECTtableName D.name ,tableIntroduce isnull(F.value, ),sort A.colorder,fieldName A.name,catogary B.name,bytes A.Length,lengths COLUMNPROPERTY(A.id, A.name, PRECISION),scales isnull(COLUMNPROPERTY(A.id, A.name, Scale), 0),isOrNotNull Cas…