TCP-消息队列模型

#include "main.h"
fd_win_set setSockets;VOID Server_write_error()
{}int cteateserver(HWND hwnd)
{WORD wVersionRequested;WSADATA wsaData;int err;/* 使用Windef.h中声明的MAKEWORD(低字节、高字节)宏 */wVersionRequested = MAKEWORD(2, 2);/*启用网络链接库,调用的封装库命令*/err = WSAStartup(wVersionRequested, &wsaData);if (err != 0) {/* Tell the user that we could not find a usable *//* Winsock DLL.                                  */printf("WSAStartup failed with error: %d\n", err);return -1;}/*确认WinSock DLL支持2.2*/if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {/* Tell the user that we could not find a usable *//* WinSock DLL.                                  */printf("Could not find a usable version of Winsock.dll\n");//清理网络库WSACleanup();return -1;}//创建套接字。 创建网络类型 tcp或者updSOCKET socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == socketServer){string ret = to_string(WSAGetLastError());MessageBoxA(0, "error_socket",ret.c_str(),  0);//清理网络库WSACleanup();return -1;}//设置sockaddr结构sockaddr_in saServer;saServer.sin_family = AF_INET;saServer.sin_addr.s_addr = INADDR_ANY;saServer.sin_port = htons(9999);// 绑定本机(服务器)IP和端口//sockaddr结构中的信息if (SOCKET_ERROR == bind(socketServer, (SOCKADDR*)&saServer, sizeof(saServer))){string ret = to_string(WSAGetLastError());MessageBoxA(0, "error_bind", ret.c_str(),  0);//释放stocketclosesocket(socketServer);//清理网络库WSACleanup();return -1;}/*监听本机(服务器)的套接字*/if (SOCKET_ERROR == listen(socketServer, SOMAXCONN)){string ret = to_string(WSAGetLastError());MessageBoxA(0, "error_listen", ret.c_str(),  0);//释放stocketclosesocket(socketServer);//清理网络库WSACleanup();return -1;}//将socket和消息绑定 并投递给消息队列管理,和事件类似WSAAsyncSelect(socketServer, hwnd, WSAAsyncSelectMsg, FD_ACCEPT);/*将服务器socket句柄写进结构体*/setSockets.sockall[setSockets.count] = socketServer;setSockets.count++;
}int AsyncSelectMsg(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{HDC DC = GetDC(hWnd);//参数三存放的是响应的socket句柄SOCKET socket = (SOCKET)wParam;//参数四可以获取句柄信息//if (0 != HIWORD(lParam))//高位保存错误码 ,退出也属于错误码//   return -1;switch (LOWORD(lParam)){case FD_ACCEPT:{sockaddr_in clientMsg = { 0 };int clientMsg_size = sizeof(clientMsg);/*得到客户端信息并返回客户端socket*/SOCKET socketClient = accept(socket, (sockaddr*)&clientMsg, &clientMsg_size);printf("%d.%d.%d.%d.%d \n", clientMsg.sin_addr.S_un.S_un_b.s_b1,clientMsg.sin_addr.S_un.S_un_b.s_b2,clientMsg.sin_addr.S_un.S_un_b.s_b3,clientMsg.sin_addr.S_un.S_un_b.s_b4,clientMsg.sin_port);TextOutA(DC,0,0,"ACCEPT",strlen("ACCEPT"));MessageBox(0,"ACCEPT","",0);if (INVALID_SOCKET == socketClient)break;//将socket和消息绑定 并投递给消息队列管理,和事件类似if (SOCKET_ERROR == WSAAsyncSelect(socketClient, hWnd, WSAAsyncSelectMsg, FD_WRITE | FD_READ | FD_CLOSE)){//释放stocketclosesocket(socketClient);break;}/*将客户端socket句柄写进结构体*/setSockets.sockall[setSockets.count] = socketClient;setSockets.count++;}break;case FD_WRITE:{//accept会触发一次,一般用于链接服务器后初始化char sendmsg[] = "connect_success";if (SOCKET_ERROR == send(socket, sendmsg, strlen(sendmsg), 0)){break;}}break;case FD_READ:{char recvmsg[1024] = { 0 };if (SOCKET_ERROR == recv(socket, recvmsg, sizeof(recvmsg), 0)){break;}printf("read:%s\n", recvmsg);char sendmsg[] = "recv_success";if (SOCKET_ERROR == send(socket, sendmsg, strlen(sendmsg), 0)){break;}}break;case FD_CLOSE:{MessageBox(0, "FD_CLOSE", "", 0);//释放stocketclosesocket(socket);//关闭事件对象WSAAsyncSelect(socket, hWnd, 0, 0);/*将这个事件和socket移除数组,取巧方法:由于事件是无序的,把数组最后一个数据放进移除的数据的位置,并将数组大小-1*/for (UINT i = 0; i < setSockets.count; i++){if (socket == setSockets.sockall[i]){setSockets.sockall[i] = setSockets.sockall[setSockets.count - 1];//数组从0开始,-1才是正确位置setSockets.count--;break;}}}break;}return 1;
}/*窗口消息回调,每次只处理一个消息*/
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WSAAsyncSelectMsg:AsyncSelectMsg(hWnd, message, wParam, lParam);break;case WM_CREATE://窗口初始化,只执行一次break;case WM_DESTROY://关闭释放窗口PostQuitMessage(0);//退出break;}//处理我们没有处理的消息return DefWindowProc(hWnd, message, wParam, lParam);
}int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{// 注册窗口结构体WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_VREDRAW| CS_HREDRAW, WindowProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, TEXT("server"), NULL };::RegisterClassEx(&wc);//创建窗口HWND windowshWnd = CreateWindowEx(WS_EX_TOPMOST  , wc.lpszClassName, TEXT("server"), WS_OVERLAPPEDWINDOW,0,0, 500,500, NULL, NULL, wc.hInstance, NULL);//显示窗口ShowWindow(windowshWnd, SW_SHOWNORMAL);//SW_SHOWNORMAL  或者 SW_SHOW//更新窗口UpdateWindow(windowshWnd);//创建服务器cteateserver(windowshWnd);// 主消息循环:MSG msg;while (GetMessage(&msg, NULL, 0, 0)){//将虚拟密钥消息转换为字符消息,字符消息将发布到调用线程的消息队列TranslateMessage(&msg);//将消息发送到窗口回调处理DispatchMessage(&msg);}//    /*释放整个结构体,可能有些事件和socket已经被释放过了,不影响*/for (UINT i = 0; i < setSockets.count; i++){//取消窗口消息和socket的绑定WSAAsyncSelect(setSockets.sockall[i], windowshWnd, 0, 0);//释放stocketclosesocket(setSockets.sockall[i]);}//清理网络库WSACleanup();return (int)msg.wParam;}
#pragma once
#define _WINSOCK_DEPRECATED_NO_WARNINGS
//#define FD_SETSIZE 1024
#include <winsock2.h>
#include <windows.h>
#include <string>#include <iostream>#pragma comment(lib,"ws2_32.lib")using namespace std;//自定义的消息值不能和系统消息冲突
#define WSAAsyncSelectMsg    WM_USER +1struct fd_es_set
{UINT count;SOCKET sockall[1024];HANDLE eventall[1024];
};struct fd_win_set
{UINT count;SOCKET sockall[1024];
};

利用windows的消息队列函数,对比事件消息,好处是消息接收更合理,按客户端发送消息的顺序会依次处理,但是由于send accept recv这些函数天生存在缺陷,是同步处理的,这些函数必须处理完一个消息才能往下处理另一个消息,会造成堵塞,故windows设计了了新的套接字函数WSAsocket  AccpetEx WSAaccept  WSAsend,这些函数采用异步方式,解决了堵塞

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

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

相关文章

AMBA总线协议(6)——AHB(四):传输细节

一、前言 在之前的文章中&#xff0c;我们已经讲述了AHB传输中的两种情况&#xff0c;基本传输和猝发传输。我们进行一个简单的回顾&#xff0c;首先&#xff0c;开始一次传输之前主机需要向仲裁器申请获得总线的使用权限&#xff0c;然后主机给出地址和控制信号&#xff0c;根…

非计算机科班如何丝滑转码

近年来&#xff0c;很多人想要从其他行业跳槽转入计算机领域。非计算机科班如何丝滑转码&#xff1f; 方向一&#xff1a;如何规划才能实现转码&#xff1f; 对于非计算机科班的人来说&#xff0c;想要在计算机领域实现顺利的转码并不是一件容易的事情&#xff0c;但也并非不…

【JavaEE进阶】SpringMVC

文章目录 一. 简单认识SpringMVC1. 什么是SpringMVC?2. SpringMVC与MVC的关系 二. SpringMVC1. SpringMVC创建和连接2. SpringMVC的简单使用2.1 RequestMapping 注解介绍2.2 RequestMapping支持的请求类型2.3 GetMapping 和 PostMapping 3. 获取参数3.1 传递单个参数3.2 传递对…

【linux】2 Linux编译器-gcc/g++和Linux调试器-gdb

文章目录 一、Linux编译器-gcc/g使用1.1 背景知识1.2 gcc如何完成1.3 函数库1.4 gcc选项 二、linux调试器-gdb使用2.1 背景2.2 开始使用 总结 ヾ(๑╹◡╹)&#xff89;" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)&#xff89;" 一、Linux编译器-gcc/g使用 1.1 背景…

/root/.ssh/config line 2: Bad protocol 2 host key algorithms ‘+ssh-rsa‘.

文章目录 1、问题2、查看openssh版本3、解决问题4、重新生成密钥5、查看是否可连接工蜂 1、问题 ssh访问工蜂报错&#xff1a; [rootlocalhost .ssh]# ssh -T gitgit.code.tencent.com /root/.ssh/config line 2: Bad protocol 2 host key algorithms ‘ssh-rsa’. 2、查看o…

升级Qt后VS项目不能使用

错误场景&#xff1a; 如果你的QT卸载了装了新版,那么VS你原来设置的项目就不能跑了. 问题 升级Qt后&#xff36;&#xff33;项目不能使用 跟我一起开始挽救自己的项目 升级Qt后&#xff36;&#xff33;项目不能使用 假如你从5.14.6 升级到 Qt6.2并删除了原来的QT 你在VS里…

Unity 3d角色展示脚本(旋转 平移 缩放)展示界面

不考虑性能 很简陋的一个功能&#xff0c;主要是用于角色渲染的观察用&#xff0c;比simplecontroller要好用一点 using System; using UnityEngine;public class CharacterViewer : MonoBehaviour {public Transform target; // 人物模型的Transformpublic float rotationSpee…

Java网络编程(一)网络基础

概述 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递 网络分类 局域网(LAN) 局域网是一种在小区域内使用的,由多台计算机组成的网络,覆盖范围…

hive-sql

hive-常用SQL汇总 查看数据库 -- 查看所有的数据库 show databases; 使用默认的库 -- 下面的语句可以查看默认的库 use default ;查看某个库下的表 -- 查看所有的表 show tables ; -- 查看包含 stu的表 &#xff0c;这种是通配的方法来查看 show tables like *stu*; 查…

【深入理解jvm读书笔记】jvm如何进行内存分配

jvm如何进行内存分配 内存分配方式内存分配方式的选择并发场景下的内存分配内存空间的初始化构造函数 内存分配方式 指针碰撞空闲列表 指针碰撞法&#xff1a; 假设Java堆中内存是绝对规整的&#xff0c;所有被使用过的内存都被放在一边&#xff0c;空闲的内存被放在另一边&a…

春秋云镜 CVE-2019-16692

春秋云镜 CVE-2019-16692 phpIPAM 1.4 - SQL Injection 靶标介绍 phpIPAM 1.4后台存在SQL Injection。 启动场景 漏洞利用 后台SQL注入&#xff0c;admin/admin888登陆成功。 exp POST /app/admin/routing/edit-bgp-mapping-search.php HTTP/1.1 Host: xxx.com Content-Le…

mysql从传统模式切到GTID模式后启动主从,主从异常报错1236

一 前言 MySQL 的主从复制作为一项高可用特性&#xff0c;用于将主库的数据同步到从库&#xff0c;在维护主从复制数据库集群的时候&#xff0c;作为专职的MySQL DBA&#xff0c;笔者相信大多数人都会遇到“Got fatal error 1236 from master when reading data from binary …

MySQL数据库:内置函数

日期函数 规定&#xff1a;日期&#xff1a;年月日 时间&#xff1a;时分秒 函数名称作用描述current_date()当前日期current_time()当前时间current_timestamp()当前时间戳date(datetime)返回datetime参数的日期部分date_add(date,interval d_value_type)在date中添加…

jenkins自动部署微服务到docker

1、代码上传到git&#xff1b; 2、jenkins拉取git的代码&#xff0c;maven打包&#xff0c;使用插件生成镜像&#xff0c;自动上传docker&#xff1b; 两个插件&#xff0c;一个打包插件&#xff0c;一个创建镜像上传docker仓库.&#xff08;将dockerfile内容搬到插件配置&…

仿mudou高性能高并发服务器

"这个结局是我的期待&#xff0c;我会一直为你祝福。" 项目实现目标: 仿muduo库One Thread One Loop式主从Reacto模型实现高并发服务器。通过实现高并发服务器组件&#xff0c;简洁快速完成搭建一个高性能服务器。并且&#xff0c;通过组件内提供的不同应⽤层协议⽀…

Kafka基本使用

查看Kafka的进程是否在运行 #命令行终端中运行如下命令 ps -ef | grep kafkafind / -iname kafka-server-start.shcd /usr/local/kafka/bin/#启动kafka ./kafka-server-start.sh -daemon /usr/local/kafka/config/server.propertiesKafka默认使用9092端口提供服务&#xf…

九、Linux下,如何在命令行进入文本编辑页面?

1、文本编辑基础 说到文本编辑页面&#xff0c;那就必须提到vi和vim&#xff0c;两者都是Linux系统中&#xff0c;常用的文本编辑器 2、三种工作模式 3、使用方法 &#xff08;1&#xff09;在进入Linux系统&#xff0c;在输入vim text.txt之后&#xff0c;会进入文本编辑中&…

第8章 CPU后端优化

CPU后端低效&#xff1a;当前端完成取指和译码后&#xff0c;后端发生了过载而不能处理新的指令。TMA将后端bound分为存储和计算bound。 8.1 存储bound 当应用程序执行大量的内存访问并且花费比较长的时间等待内存访问完成时&#xff0c;即被视为存储bound。意味着要改善存储…

vue静态html加载外部组件

当我们在开发vue应用时, 使用的是html页面开发, 需要引用外部vue组件, 怎么办呢, 首先我们引用http-vue-loader.js文件, 像下面这样: <script src"/assets/javascript/vue.min.js"></script> <script src"/assets/javascript/http-vue-loader.j…

每日一学——Vlan配置

VLAN&#xff08;Virtual Local Area Network&#xff09;是虚拟局域网的缩写&#xff0c;它是一种将多台主机和网络设备逻辑上划分成不同的局域网的技术。VLAN的实施可以基于端口、MAC地址、协议等多种方式进行。 VLAN的主要功能包括&#xff1a; 分割网络&#xff1a;VLAN可…