精华内容
下载资源
问答
  • 客户端与服务器之间的网络通信基本原理如下所示,复杂一点的架构可能会添加消息中间件。 对于服务端,通信流程如下: 1、调用socket函数创建监听socket 2、调用bind函数将socket绑定到某个IP和端口号组成的二元组上 ...

    流程概述

    客户端与服务器之间的网络通信基本原理如下所示,复杂一点的架构可能会添加消息中间件。
    对于服务端,通信流程如下:

    1、调用socket函数创建监听socket
    2、调用bind函数将socket绑定到某个IP和端口号组成的二元组上
    3、调用listen函数开启监听
    4、当有客户端连接请求时,调用accept函数接受连接,产生一个新的socket(与客户端通信的socket)
    5、基于新产生的socket调用send或recv函数开始与客户端进行数据交流
    6、通信结束后,调用close函数关闭socket
    

    对于客户端,通信流程如下:

    1、调用socket函数创建客户端socket
    2、调用connect函数尝试连接服务器
    3、连接成功后调用send或recv函数与服务器进行数据交流
    4、通信结束后,调用close函数关闭监听socket
    

    在这里插入图片描述

    服务器端代码实现

    
    
    #include <iostream>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    
    using namespace std;
    int main() {
    
        // 创建一个监听socket
        int listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd == -1) {
            cout << " create listen socket error " << endl;
            return -1;
        }
        // 初始化服务器地址
        struct sockaddr_in bindaddr;
        bindaddr.sin_family = AF_INET;
        bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        bindaddr.sin_port = htons(3000);
        if (bind(listenfd, (struct sockaddr *)& bindaddr, sizeof(bindaddr)) == -1) {
            cout << "bind listen socket error" << endl;
            return -1;
        }
        // 启动监听
        if (listen(listenfd, SOMAXCONN) == -1) {
            cout << "listen error" << endl;
            return -1;
        }
    
        while (true) {
            // 创建一个临时的客户端socket
            struct sockaddr_in clientaddr;
            socklen_t clientaddrlen = sizeof(clientaddr);
            // 接受客户端连接
            int clientfd = accept(listenfd, (struct sockaddr *)& clientaddr, &clientaddrlen);
            if (clientfd != -1) {
                char recvBuf[32] = {0};
                // 从客户端接受数据
                int ret = recv(clientfd, recvBuf, 32, 0);
                if (ret > 0) {
                    cout << "recv data from cilent , data:" << recvBuf << endl;
                    // 将接收到的数据原封不动地发给客户端
                    ret = send(clientfd, recvBuf, strlen(recvBuf), 0);
                    if (ret != strlen(recvBuf)) {
                        cout << "send data error" << endl;
                    } else {
                        cout << "send data to client successfully, data " << recvBuf <<endl;
                    }
                } else {
                    cout << "recv data error" <<endl;
                }
                close(clientfd);
            }
        }
    
        // 关闭监听socket
        close(listenfd);
        return 0;
    }
    
    

    客户端代码实现

    #include <iostream>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    
    #define SERVER_ADDRESS "127.0.0.1"
    #define SERVER_PORT 3000
    #define SEND_DATA "helloworld"
    
    using namespace std;
    
    int main() {
        // 创建一个socket
        int clientfd = socket(AF_INET, SOCK_STREAM, 0);
        if (clientfd == -1) {
            cout << " create client socket error " << endl;
            return -1;
        }
        // 连接服务器
        struct sockaddr_in serveraddr;
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);
        serveraddr.sin_port = htons(SERVER_PORT);
        if (connect(clientfd, (struct sockaddr *)& serveraddr, sizeof(serveraddr)) == -1) {
            cout << "connect socket error" << endl;
            return -1;
        }
        // 向服务器发送数据
        int ret = send(clientfd, SEND_DATA, strlen(SEND_DATA), 0);
        if (ret != strlen(SEND_DATA)) {
            cout << "send data error" << endl;
            return -1;
        } else {
            cout << "send data to client successfully, data " << SEND_DATA <<endl;
        }
        // 从服务器拉取数据
        char recvBuf[32] = {0};
        ret = recv(clientfd, recvBuf, 32, 0);
        if (ret > 0) {
            cout << "recv data to client successfully, data " << recvBuf <<endl;
        } else {
            cout << "recv data to client error" << endl;
        }
        // 关闭socket
        close(clientfd);
        return 0;
    }
    

    函数和结构讲解

    sockaddr_in和sockaddr

    在讲解套接字编程函数之前,有必要对socket编程的两个不可或缺的结构体进行说明:sockaddrsockaddr_in
    结构如下:

    struct sockaddr
      {
        __SOCKADDR_COMMON (sa_);	/* Common data: address family and length.  */
        char sa_data[14];		/* Address data.  */
      };
      
    /* Structure describing an Internet socket address.  */
    struct sockaddr_in
      {
        __SOCKADDR_COMMON (sin_);
        in_port_t sin_port;			/* Port number.  */
        struct in_addr sin_addr;		/* Internet address.  */
    
        /* Pad to size of `struct sockaddr'.  */
        unsigned char sin_zero[sizeof (struct sockaddr)
    			   - __SOCKADDR_COMMON_SIZE
    			   - sizeof (in_port_t)
    			   - sizeof (struct in_addr)];
      };
    

    由于历史的原因,套接字函数中(如connect,bind等)使用的参数类型大多是sockaddr类型的。而如今进行套接字编程的时候大都使用sockaddr_in进行套接字地址填充.因此,这就要求对这些函数进行调用的时候都必须要讲套接字地址结构指针进行类型强制转换,例如:

    struct sockaddr_in serv;
     
    bind(sockfd,(struct sockaddr *)&serv,sizeof(serv));
    

    socket : 创建一个socket连接

    /* Create a new socket of type TYPE in domain DOMAIN, using
       protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
       Returns a file descriptor for the new socket, or -1 for errors.  */
    extern int socket (int __domain, int __type, int __protocol) __THROW; 
    

    向用户提供一个套接字,即套接口描述文件字,它是一个整数,如同文件描述符一样,是内核标识一个IO结构的索引。
    一般传入参数是这样的:

    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    

    __domain:这个参数指定一个协议簇,也往往被称为协议域。系统存在许多可以的协议簇,常见有AF_INET──指定为IPv4协议,AF_INET6──指定为IPv6,AF_LOCAL──指定为UNIX 协议域。这里指网络层的协议
    __type:这个参数指定一个套接口的类型,套接口可能的类型有:SOCK_STREAMSOCK_DGRAMSOCK_SEQPACKETSOCK_RAW等等,它们分别表明字节流、数据报、有序分组、原始套接口。
    __protocol:指定相应的传输协议,也就是诸如TCP或UDP协议等等,系统针对每一个协议簇与类型提供了一个默认的协议,我们通过把protocol设置为0来使用这个默认的值。这里指传输层的协议
    返回值:socket函数返回一个套接字,即套接口描述字。如果出现错误,它返回-1,并设置errno为相应的值,用户应该检测以判断出现什么错

    返回值:成功则返回0,失败返回非0

    bind :绑定地址以及端口号问题

    在服务器端我们有这样一段代码:

    // 初始化服务器地址
    struct sockaddr_in bindaddr;
    bindaddr.sin_family = AF_INET;
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(3000);
    if (bind(listenfd, (struct sockaddr *)& bindaddr, sizeof(bindaddr)) == -1) {
        cout << "bind listen socket error" << endl;
        return -1;
    }
    

    函数参数解释:

    /* Give the socket FD the local address ADDR (which is LEN bytes long).  */
    extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
    

    bind的地址我们使用了宏INADDR_ANY,这个宏定义如下:

    /* Address to accept any incoming messages.  */
    #define	INADDR_ANY		((in_addr_t) 0x00000000)
    

    如果应用程序不关心bind绑定的IP,则可以使用这个宏,底层的协议栈服务会自动选择一个合适的IP地址,这样在多个网卡机器上选择IP地址会变得简单
    如果只想在本机上进行访问,bind函数地址可以使用本地回环地址
    如果只想被局域网的内部机器访问,那么bind函数地址可以使用局域网地址
    如果希望被公网访问,那么bind函数地址可以使用INADDR_ANY or 0.0.0.0

    网络通信的基本逻辑是客户端连接服务器,即从客户端的地址:端口 连接到 服务器的地址:端口上。
    一般来说,服务器的端口号是固定的,而客户端的端口号是连接发起时操作系统随机分配的,并且不会分配被占用的端口。端口号是一个short类型的值,其范围为0~65535.
    如果将bind函数中的端口号设置为0,那么操作系统会随机为程序分配一个可用的监听端口。一般来说,服务程序不会这么做,因为服务程序是要对外服务的,必须让客户端知道确切的IP地址和端口号。
    在特殊的应用中,我们也可以在客户端程序以指定的端口号连接服务器,与普通的流程相比就是在创建socket与发起connect之间多了一次bind操作:

    图1 不绑定
    图2 绑定

    其他相关函数可以到往期文章中查看:
    socket编程常见函数使用方法

    展开全文
  • 第二节C++百万并发网络通信引擎演示 第三节C++百万并发网络通信引擎演示-阿里云服务器 第四节开发工具介绍 第五节本章内容介绍 第六节建立 Windows C++开发环境 第七节建立一个易于管理的Windows

    最近在网上买了个C++百万并发通信引擎的全套资料,感觉非常不错。

    原本资料的来源为:https://mp.csdn.net/console/home?spm=1000.2115.3001.4503

    想要资料可以加我微信dyh513418来购买

    第一章:搭建多平台下C++开发环境

    第一节课程内容介绍

    第二节C++百万并发网络通信引擎演示

    第三节C++百万并发网络通信引擎演示-阿里云服务器

    第四节开发工具介绍

    第五节本章内容介绍

    第六节建立 Windows C++开发环境

    第七节建立一个易于管理的Windows C++工程

    第八节VS2015 C++程序常用调试方法

    第九节常用虚拟机软件简介

    第一十节安装虚拟机软件VMware Workstation 12 Player

    第一十一节在虚拟机中安装MacOS 10.12系统

    第一十二节在MacOS 10.12系统中安装Xcode9开发工具

    第一十三节使用Xcode9.1编写一个MacOS C++程序

    第一十四节在虚拟机中安装Linux-ubuntu-16.04桌面系统

    第一十五节在Ubuntu 中编写一个Linux C++程序

    第一十六节安装配置SVN代码管理工具1

    第一十七节安装配置SVN代码管理工具2

    第二章:Socket网络通信基础

    第一节本章内容介绍

    第二节Socket 基础Api(TCP篇) 介绍

    第三节Hello Socket

    第四节用Socket API 6步建立TCP服务端

    第五节用Socket API 4步建立客户端

    第六节建立能持续处理请求的CS网络程序

    第七节用SVN来管理我们的教学项目

    第八节发送结构化的网络消息数据1

    第九节发送结构化的网络消息数据2

    第一十节网络报文的数据格式定义及使用1

    第一十一节网络报文的数据格式定义及使用2

    第一十二节网络报文的数据格式定义及使用3

    第一十三节网络报文的数据格式定义及使用4

    第一十四节将多次收发报文数据升级为一次收发1

    第一十五节将多次收发报文数据升级为一次收发2

    第一十六节答疑解惑:网络消息接收长度问题

    第一十七节服务端升级为select模型处理多客户端1

    第一十八节服务端升级为select模型处理多客户端2

    第一十九节服务端升级为select模型处理多客户端3

    第二十节服务端升级为select模型处理多客户端4

    第二十一节将服务端select模型设置为非阻塞,处理更多业务

    第二十二节客户端升级为select网络模型1

    第二十三节客户端升级为select网络模型2

    第二十四节客户端升级为select网络模型3

    第二十五节为客户端添加输入线程(Thread)

    第二十六节客户端升级1.4跨平台移植:Winows、Linux、MacOS系统1

    第二十七节客户端升级1.4跨平台移植:Winows、Linux、MacOS系统2

    第二十八节客户端升级1.4跨平台移植:Winows、Linux、MacOS系统3

    第二十九节客户端升级1.4跨平台移植:Winows、Linux、MacOS系统4

    第三十节客户端升级1.4跨平台移植:Winows、Linux、MacOS系统5

    第三十一节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统1

    第三十二节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统2

    第三十三节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统3

    第三十四节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统4

    第三十五节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统5

    第三十六节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统6

    第三十七节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统7

    第三十八节服务端升级1.4跨平台移植:Winows、Linux、MacOS系统8

    第三十九节客户端1.5,封装Client类,同时与多个服务端通信1

    第四十节客户端1.5,封装Client类,同时与多个服务端通信2

    第四十一节客户端1.5,封装Client类,同时与多个服务端通信3

    第四十二节客户端1.5,封装Client类,同时与多个服务端通信4

    第四十三节验证客户端1.5同时与多个不同平台下的服务端通信1

    第四十四节验证客户端1.5同时与多个不同平台下的服务端通信2

    第四十五节验证客户端1.5同时与多个不同平台下的服务端通信3

    第四十六节验证客户端1.5同时与多个不同平台下的服务端通信4

    第四十七节服务端1.5,封装Server类,创建多个Server服务1

    第四十八节服务端1.5,封装Server类,创建多个Server服务2

    第四十九节服务端1.5,封装Server类,创建多个Server服务3

    第五十节服务端1.5,封装Server类,创建多个Server服务4

    第五十一节在内外网中验证、测试粘包原因1

    第五十二节在内外网中验证、测试粘包原因2

    第五十三节在内外网中验证、测试粘包原因3

    第五十四节客户端1.6,解决客户端粘包1

    第五十五节客户端1.6,解决客户端粘包2

    第五十六节客户端1.6,解决客户端粘包3

    第五十七节服务端1.6,解决服务端粘包1

    第五十八节服务端1.6,解决服务端粘包2

    第五十九节服务端1.6,解决服务端粘包3

    第六十节服务端1.6,解决服务端粘包4

    第六十一节解决粘包测试-Win10专业版-每秒1Gb数据

    第六十二节解决粘包测试-Linux-ubuntu-16.04系统

    第六十三节解决粘包测试-外网云服务器-远程数据传输

    第六十四节突破Windows下select64限制1

    第六十五节突破Windows下select64限制2

    第六十六节添加高精度计时器测量处理能力1

    第六十七节添加高精度计时器测量处理能力2

    第六十八节单线程select模型10000连接测试

    第六十九节多线程与单线程网络程序架构简介

    第七十节多线程-基本概念简介

    第七十一节多线程-创建线程,两种启动线程方法的差异

    第七十二节多线程-传递参数给入口函数,创建线程数组

    第七十三节多线程-锁与临界区域

    第七十四节多线程-锁的消耗,通过简单并行计算示例测试

    第七十五节多线程-自解锁

    第七十六节多线程-原子操作

    第七十七节多线程-基本概念总结

    第七十八节定个小目标,1万连接每秒处理200万个数据包1

    第七十九节定个小目标,1万连接每秒处理200万个数据包2

    第八十节客户端1.7_1,多线程分组模拟高频并发数据1

    第八十一节客户端1.7_2,多线程分组模拟高频并发数据2

    第八十二节服务端单线程模式下性能瓶颈测试

    第八十三节经典设计模式-生产者与消费者模式

    第八十四节服务端1.7_1,分离新客户端连接与消息处理业务

    第八十五节服务端1.7_2,为消息处理线程添加新客户端缓冲队列

    第八十六节服务端1.7_3,建立消息处理线程

    第八十七节服务端1.7_4,将新客户端分配给客户数量最少的消息线程

    第八十八节服务端1.7_5,消息处理线程在无客户端时休眠1毫秒

    第八十九节服务端1.7_6,为消息处理线程添加每秒收包计数

    第九十节服务端1.7_7,事件通知,有客户端退出

    第九十一节服务端1.7_8,测试退出事件

    第九十二节服务端1.7_9,警告:内存不足

    第九十三节客户端1.7_3,提高发送频率,每次发送10个消息包

    第九十四节1.7版,小目标达成,1万连接每秒处理200万包验证测试

    第九十五节小目标达成,注解、补充、代码调整1

    第九十六节小目标达成,注解、补充、代码调整2

    第九十七节小目标达成,注解、补充、代码调整3

    第九十八节小目标达成,注解、补充、代码调整4

    第九十九节小目标达成,实现自定义Server

    第三章:多平台下的客户端网络通信

    第一节本章内容介绍

    第四章:一步一步建立高性能服务器

    第一节本章内容介绍

    第二节Server1.7_select模型接收数据性能瓶颈与优化1

    第三节Server1.7_select模型接收数据性能瓶颈与优化2

    第四节Server1.7_select模型接收数据性能瓶颈与优化3

    第五节Server1.7_select模型接收数据性能瓶颈与优化4

    第六节Socket API 极限测试,添加recv和send调用每秒调用计数

    第七节Socket API 极限测试之recv 1 单线程每秒100+万次接收

    第八节Socket API 极限测试之recv 2 多线程每秒400+万次接收

    第九节Socket API 极限测试之recv 3 阿里云服务器单线程每秒100万+次接收

    第一十节Socket API极限测试之send函数1

    第一十一节Socket API极限测试之send函数2

    第一十二节Socket API极限测试之send函数3

    第一十三节CellServer数据收发的性能瓶颈1

    第一十四节CellServer数据收发的性能瓶颈2

    第一十五节CellServer数据收发的性能瓶颈3

    第一十六节定时定量发送数据

    第一十七节添加发送缓冲区-定量发送1

    第一十八节添加发送缓冲区-定量发送2

    第一十九节Server消息接收与发送分离1

    第二十节Server消息接收与发送分离2

    第二十一节Server消息接收与发送分离3

    第二十二节Server消息接收与发送分离4

    第二十三节Server消息接收与发送分离5

    第二十四节Server消息接收与发送分离6

    第二十五节内存管理-内存池设计1

    第二十六节内存管理-内存池设计2

    第二十七节内存管理-内存池设计3

    第二十八节内存池实现1-重载new运算符

    第二十九节内存池实现2

    第三十节内存池实现3

    第三十一节内存池实现4-初始化内存池

    第三十二节内存池实现5-实现内存申请

    第三十三节内存池实现-6-

    相关链接:https://edu.csdn.net/course/detail/6252?utm_source=edu_bbs_autocreate

    我有全套代码,ppt,想要的可以加我微信dyh513418

    展开全文
  • 三:C++编程知识 任何脱离细节的C/C++工程师都是耍流氓,向上能运筹帷幄,向下能解决一线开发问题,C/C++工程师需要切实掌握好基础语法,s/linux编程、QT开发等企业项目开发能力并熟练运用。 能掌握以上知识这些人...

    一般来说技术团队的金字塔顶尖往往是技术最牛的人做底层架构师(或高级工程师)。所以底层架构师在广大码农中的占比大概平均不到 20%。

    然而80%码农干上许多年都是重复以下内容,所以做不了架构师,正在辛苦工作的程序员们,你有没有下面几种感觉?

    ①我的工作就是按时完成领导交给我的任务,至于代码写的怎样,知道有改进空间,但没时间去改进,关键是领导也不给时间啊。

    ②我发现我的水平总是跟不上技术的进步,有太多想学的东西要学,Swoft用的人最近比较多啊,听说最近Swoole比较火,还有微服务,听说PHP又更新了……

    ③我发现虽然我工作5年了,除了不停的Coding写业务代码,Ctrl+C和Ctrl+V更熟练了,但编码水平并没有提高,还是一个普通程序员,但有人已经做到架构师了。

    ④工作好几年了,想跳槽换个高薪工作,结果面试的考官都问了一些什么数据结构,什么垃圾回收,什么并发架构、协程编程之类的东西,虽然看过,但是平时用不着,看了也忘记了,回答不上来,结果面试官说我基础太差……

    如果有以上问题,那么你绝对进入学习误区走了弯路;如果我们要成为架构师,我们自己要面临的三大问题:找准定位:我是谁、我在哪里?怎样做好架构师:我要做什么?如何搭建架构师知识体系:我该怎么做?

    如果你想要往工程师或底层架构师的方向发展的话,那或许你可以看一下我分享给你的这份进阶路线图,主要针对1到5年及以上的C/C++开发人员,这些也是目前中大型互联网企业比较常用的技术,那么来详细看看

    一:切实掌握好C语言基础能力
    学习C/C++编程,首先应该掌握好的就是C语言,C语言不仅仅是编程的基础,在我们进阶的过程中也是有着相当大的作用,有些程序员开始学习的Java或者Python直接入门的,这样的学习过程在后期进阶的过程中会有一定的影响,影响程度视情况而定。

    二:算法与数据结构
    数据结构与算法的重要性相信大家也是非常清楚的,当你是码农的时候这个东西有需要有一定的掌握,那么你想要进阶的话,它们你是必须要更好的提升的一项!

    三:C++编程知识
    任何脱离细节的C/C++工程师都是耍流氓,向上能运筹帷幄,向下能解决一线开发问题,C/C++工程师需要切实掌握好基础语法,s/linux编程、QT开发等企业项目开发能力并熟练运用。

    能掌握以上知识这些人必然具备在技术上独当一面的能力并且清楚自己未来的发展方向,从一个Coder逐步走向CTO或是底层架构师,成为项目组中不可或缺的人物。

    链接:https://pan.baidu.com/s/1_4PIUb-Yl68aTW9Bw95iJA
    提取码:tnav

    展开全文
  • 4、初始设定:非安全模式通信,服务端监听所有地址。可修改监听端口。 5、源码下载链接在文章底部。 源码解析 界面 界面的主要操作:开启服务端/客户端线程、响应控件、通过自定义信号调用服务端/客户端的操作、接收...

    UI界面截图

    在这里插入图片描述

    说明

    1、如有bug,敬请谅解,欢迎在评论区留言。
    2、本程序使用多线程,即UI、服务端、客户端分别在不同的线程运行。
    3、线程之间使用信号-槽方式进行交互。
    4、初始设定:非安全模式通信,服务端监听所有地址。可修改监听端口。
    5、源码下载链接在文章底部。

    源码解析

    界面

    界面的主要操作:开启服务端/客户端线程、响应控件、通过自定义信号调用服务端/客户端的操作、接收服务端/客户端的消息信号、更新界面显示。代码参考源文件。

    服务端

    服务端的主要操作:开启监听、停止监听、客户端管理(接入/断开)、发送消息、接收消息、报错处理。

    
    WSServer::WSServer(QObject *parent)
        : QObject(parent)
    {
        WebSocketServer = new QWebSocketServer("LocalServer", QWebSocketServer::NonSecureMode, this);
        connect(WebSocketServer, &QWebSocketServer::newConnection, this, &WSServer::HasNewConnection);
    
        connect(WebSocketServer, SIGNAL(serverError(QWebSocketProtocol::CloseCode)),
                this             , SLOT(on_serverError(QWebSocketProtocol::CloseCode)));
    }
    
    void WSServer::Server_start(qint32 port)
    {
        Server_Port = port;
        WebSocketServer->listen(QHostAddress(QHostAddress::Any), Server_Port);  //开启监听,任意地址,指定端口
    }
     
    void WSServer::Server_stop()
    {
        foreach(QWebSocket* websocket, WSClients.values())
        {
            websocket->close(); //断开所有客户端连接
        }
        WebSocketServer->close();   //关闭服务
        WSClients.clear();  //清空哈希容器
    }
    
    void WSServer::remove_client(const QString ClientInfo)
    {
        if(WSClients.contains(ClientInfo))
        {
            WSClients.value(ClientInfo)->close();	//断开客户端链接,相当于强制下线
            WSClients.remove(ClientInfo);   //移除指定客户端
        }
    }
    //服务端错误处理
    void WSServer::on_serverError(QWebSocketProtocol::CloseCode error_code)
    {
        emit occur_error("error message:server error," + WebSocketServer->errorString()
                         + "\nerror code:" + QString::number(error_code));
    }
    //客户端连接错误处理
    void WSServer::on_clientError(QAbstractSocket::SocketError error_code)
    {
        QWebSocket* error_client = qobject_cast<QWebSocket*>(sender());
        emit occur_error("error message:client error," + error_client->errorString()
                         + "\nerror code:" + QString::number(error_code));
    }
     //有新的客户端接入,处理客户端的断开连接信号、错误信号、消息信号,将客户端加入哈希容器管理
    void WSServer::HasNewConnection()
    {
        QWebSocket* NewClient = WebSocketServer->nextPendingConnection();
        connect(NewClient, &QWebSocket::disconnected, this, &WSServer::on_ClientDisconnected);
        connect(NewClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_clientError(QAbstractSocket::SocketError)));
        // 客户端发来消息时,既会触发textFrame,也会触发textMessage,此处只写text
        connect(NewClient, &QWebSocket::textMessageReceived, this, &WSServer::on_textMessageReceived);
    
        QString NewClientInfo = QString("%1-%2").arg(NewClient->peerAddress().toString()).arg(NewClient->peerPort());
    
        WSClients.insert(NewClientInfo, NewClient);
    
        emit NewClient_conncted(NewClientInfo);
    }
     //客户端断开连接
    void WSServer::on_ClientDisconnected()
    {
        QWebSocket *client = qobject_cast<QWebSocket *>(sender());
        if(!client)
        {
            return;
        }
        QString ClientInfo = QString("%1-%2").arg(client->peerAddress().toString()).arg(client->peerPort());
        emit Client_disconncted(ClientInfo);    //发出信号给到UI线程
    
        WSClients.remove(ClientInfo);   //移除客户端
    }
     //接收客户端消息
    void WSServer::on_textMessageReceived(const QString &message)
    {
        QWebSocket* client = qobject_cast<QWebSocket *>(sender());
        if(!client)
        {
            return;
        }
        QString ClientInfo = QString("%1-%2").arg(client->peerAddress().toString()).arg(client->peerPort());
        emit NewTextMessage(ClientInfo, message);   //发出信号给到UI线程
    }
    
    //服务器发消息,UI界面可选择发至所有客户端或指定客户端
    void WSServer::Server_sendmsg(QString ClientInfo, QString message, bool isAllClients)
    {
       if(!isAllClients)
       {
           if(WSClients.contains(ClientInfo))
           {
               WSClients.value(ClientInfo)->sendTextMessage(message);
           }
       }
       else
       {
           foreach(QWebSocket* websocket, WSClients.values())
           {
               websocket->sendTextMessage(message);
           }
       }
    }
    
    

    客户端

    客户端的主要操作:连接服务端、断开连接、发送消息、接收消息、报错处理。

    
    WSClient::WSClient(QObject *parent)
        : QObject(parent)
    {
        WSClientObj = new QWebSocket;   //构造函数未设置参数和指定父对象
        WSClientObj->setParent(this);   //这里必须设置父对象,否则多线程运行报错
        //客户端需要处理的信号:连接成功、断开连接、发生错误、收到消息
        connect(WSClientObj, &QWebSocket::connected, this, &WSClient::on_connected);
        connect(WSClientObj, &QWebSocket::disconnected, this, &WSClient::on_disconnected);
        connect(WSClientObj, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_error(QAbstractSocket::SocketError)));
        connect(WSClientObj, &QWebSocket::textMessageReceived, this, &WSClient::on_textMessageReceived);
    }
    
    //连接服务端
    void WSClient::ConnectTo(const QString url)
    {
        WSClientObj->open(QUrl(url));
    }
    //断开连接
    void WSClient::Disconnect()
    {
        WSClientObj->close();
    }
     //发消息,字符串
    void WSClient::sendTextMessage(const QString message)
    {
        WSClientObj->sendTextMessage(message);
    }
     //发消息,二进制
    void WSClient::sendBinaryMessage(const QByteArray data)
    {
        WSClientObj->sendBinaryMessage(data);
    }
     //连接成功,通知UI
    void WSClient::on_connected()
    {
        emit connection_state("success connected", true);   //true/false用于UI判断更新控件可用状态
    }
     //断开连接,通知UI
    void WSClient::on_disconnected()
    {
        emit connection_state("success disconnected", false);
    }
     //报错,通知UI
    void WSClient::on_error(QAbstractSocket::SocketError error)
    {
        emit occur_error("error message:" + WSClientObj->errorString() + "\nerror code:" + QString::number(error));
    }
     //接收消息,通知UI
    void WSClient::on_textMessageReceived(const QString& message)
    {
        emit NewTextMessage(message);
    }
    
    

    源码地址

    WebSocketApplication-V1.0

    展开全文
  • C++实现RS485通信

    2021-07-21 13:23:35
    int main() { /* //RS485通信,串口接收数据 */ //查看所有串口信息 vector strCom; char strTemp[255]; HANDLE hCom; for (int i = 0; i ; i++) { //strTemp.Format("\\\\.\\COM%d", i + 1); sprintf(strTemp, "\\...
  • C++ TCP通信

    2021-03-23 15:10:22
    流程图 头文件和库 #include <...TCP 和UDP前面部分基本一致,只是在bind()函数之后,服务端有listen()和accept()过程,bind()之前的不详细的讲解,详细的API讲解可以参考我写的前一篇文章:DUP通信 初始
  • 网络socket编程中,常见的connect、accept、send、recv函数均具有阻塞与非阻塞两种调用方式。 阻塞与非阻塞socket具有各自适用的场景 非阻塞模式一般用于需要支持高并发QPS的场景,但是该模式会让程序执行流和控制...
  • C++实现进程通信(管道pipe)

    千次阅读 2021-12-03 16:54:44
    管道不仅可以用于本机进程间通信,还可实现跨网络进程间通信,如同Socket通信,管道同样封装计算机底层网络实现,提供一个良好的API接口。 管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道...
  • C++ UDP通信

    2021-03-21 22:44:41
    C++ UDP通信 流程图 头文件和库 #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib") 初始化套接字库 初始化函数: int WSAAPI WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData ); 返回值...
  • } Server端的c++代码: #include // for sockaddr_in #include // for socket #include // for socket #include #include // for printf #include // for exit #include // for bzero #include #include #include #...
  • UI界面截图 更新内容 1、增加发送和接收转16进制字符串,以空格符分割字节。 2、增加服务端与客户端的...4、初始设定:非安全模式通信,服务端监听所有地址,可修改监听端口。 5、代码我就不贴了,需要的请自行下载。
  • 2. C++ Socket 网络数据传输的几种方式 C++ Socket在进行网络数据的传送时,数据一般是char类型的字符数组,除此之外还有一些方法可以传送我们自己定义的数据类型 自定义结构体 Json序列化 定义Class对象 1. ...
  • C++ TCP通信 客户端多线程程序 #define HAVE_STRUCT_TIMESPEC #include <winsock.h> #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <iostream> #pragma ...
  • 1.服务器端代码:#include#include#pragma comment(lib, "ws2_32.lib")#define CONNECT_NUM_MAX 10using namespace std;int main(){//加载套接字库WSADATA wsaData;int iRet = 0;iRet = WSAStartup(MAKEWORD(2, 2), ...
  • c++多线程实现网络中的进程tcp/ip通信 进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道、FIFO、消息队列) 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量) 共享内存(匿名的和...
  • C++实现TCP服务器端同时和多个客户端通信(多线程)

    千次阅读 热门讨论 2021-05-12 15:25:26
    多线程网络通讯服务器端客户端运行实例 通讯建立后首先由服务器端发送消息,客户端接收消息;接着客户端发送消息,服务器端接收消息,实现交互发送消息。 服务器同时可以和多个客户端建立连接,进行交互; 在某次...
  • 目的是学习C++网络开发的基本概念,同时也可以熟悉下Linux下的C++程序编译和简单MakeFile编写 分享一个即时通讯的实战项目给大家:即时通讯实战项目 需要Linux服务器开发高阶学习资料的朋友可以后台私信【架构】...
  • Qt C++与unity之间TCP网络通信(多线程) 主要参考博客:https://blog.csdn.net/u012234115/article/details/46489537 考虑实现用Qt C++做服务器,unity做客户端实现TCP网络通信,来传递unity中模型的坐标。 Qt C++...
  • 网络通信中有客户端和服务端,它们之间是如何通信的呢? 各端的操作流程: 服务端操作流程: 创建套接字端口:在内核中创建socket结构体 为套接字绑定地址信息:网络通信中的数据都必须带有源端IP、源端端口、对...
  • Socket编程的目的是使网络的进程进行通信,基于TCP/IP协议簇,通过三元组(ip地址、协议、端口)标志进程,并通过该标志与其他进行进行交互。使用TCP/IP协议的应用程序通常采用应用编程接口,套接字Socket是当前的...
  • C++ TCP通信 服务器程序 /* 服务器编程思路: 初始化套接字库 1、创建套接字socket(socket) 地址处理以及端口处理 2、创建的套接字绑定(bind)到本地的地址和端口上 3、设置套接字的状态为监听(listen)...
  • TCP通信编程 tcp是面向连接、可靠传输、面向字节流的传输层协议 面向连接:必须建立了连接且保证双方都具有数据收发...为套接字绑定地址信息:网络通信中的数据都必须带有源端IP、源端端口、对端IP、对端端口、协议,这
  • C++实现简单Socket通信

    2021-03-31 11:25:43
    参考学习:C++:实现socket通信(TCP/IP)实例 1. 一对一 server.cpp // server.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 /* 服务端:建立socket,申明自身port和IP,并绑定到socket,使用listen...
  • 语言:C/C++ 通信方式:UDP 服务器端的步骤如下: socket: 建立一个socket bind: 将这个socket绑定在某个端口上(AF_INET) recvfrom: 如果没有客户端发起请求,则会阻塞在这个函数里 close: 通信完成后...
  • 通信特点 面向连接 可靠 端对端 报文格式 三次握手 四次挥手 流量控制 拥塞控制 资源分配 应用
  • PC端是用C++开发的,为了方便传输,在发送之前都将数据转化为字节数组。本以为可以万事大吉,可是过程还是会有一些问题。下面是我遇到的几个问题以及解决方案,这里做一个简单的记录,也希望大家遇到后能够快速解决...
  • 本书由浅入深、循序渐进地向读者介绍了visual c++网络编程的基础知识,并且在此基础上讲解了常见的visual c++网络编程技术及典型应用案例,最终使读者从根本上提高自身的编程水平,能够独立开发网络应用程序。...
  • 使用c/c++实现多线程TCP通信

    千次阅读 2021-11-11 11:28:03
    本文讲到的是c和c++的tcp通信的代码实现过程,具体原理不做描述,如三次握手四次挥手。 服务器: 1、定义文件描述符,套接字结构体sockaddr_in。 2、创建socket(AF_INET,SOCK_STREAM,0)和给文件描述符赋值; 3、套接...
  • 说明当前例子采用boost asio库发送HTTP数据报文,采用boost::asio::streambuf request流封装数据报文,在例子的后面通过string对响应数据包进行分析,获取其中的json格式数据包#include #include #include #include ...
  • 这里给出一个写的比较清晰的管道通信的文章: https://www.cnblogs.com/boyxiao/archive/2011/01/02/1924188.html 项目场景: 场景: Windows下,进程间使用FIFO通信,用于传输视频帧。 问题描述: 1. 客户端第一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 119,916
精华内容 47,966
关键字:

c+++网络通信

c++ 订阅