网络编程 重叠IO模型

news/2024/11/17 9:55:12/

目录

1.概念

2.代码详解

        事件通知实现逻辑​

        1.WSASocket函数

        2.AcceptEx函数

        3.WSARecv函数

        4.WSAGetOverlappedTesult函数

        5.WSAResetEvent函数

        6.WSASend函数

##重叠IO模型事件通知整体代码

        完成例程实现逻辑​编辑

##重叠IO模型完成例程的整体代码


1.概念

        重叠IO模型是对C/S模型的直接优化,使用到的函数和概念如下图:

        重叠IO的流程图

 

2.代码详解

        事件通知实现逻辑

        重叠IO模型中的代码与select模型,事件选择模型以及异步选择模型差别很大,使用的函数也不一样。

        1.WSASocket函数

该函数创建绑定到特定传输服务提供程序的套接字,函数原型

SOCKET WSAAPI WSASocketA([in] int                 af,[in] int                 type,[in] int                 protocol,[in] LPWSAPROTOCOL_INFOA lpProtocolInfo,[in] GROUP               g,[in] DWORD               dwFlags
);

前三个参数和socket函数的三个参数是一样的

参数4 lpProtocolInfo:设置套接字详细属性,是一个指向 WSAPROTOCOL_INFO 结构体的指针,一般填写NULL

参数5 g:该参数填写0

参数6 dwFlags:指定套接字属性,填写 WSA_FLAG_OVERLAPPED

        返回值和socket函数一样

##代码样例

	SOCKET socketServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);if (socketServer == INVALID_SOCKET){//创建了无效的socketint a = WSAGetLastError();//获取错误码printf("创建出错\n");WSACleanup();return 0;}

        2.AcceptEx函数

该函数接受新连接,返回本地和远程地址,并接收客户端应用程序发送的第一个数据块,函数原型

BOOL AcceptEx([in]  SOCKET       sListenSocket,[in]  SOCKET       sAcceptSocket,[in]  PVOID        lpOutputBuffer,[in]  DWORD        dwReceiveDataLength,[in]  DWORD        dwLocalAddressLength,[in]  DWORD        dwRemoteAddressLength,[out] LPDWORD      lpdwBytesReceived,[in]  LPOVERLAPPED lpOverlapped
);

参数1:填服务器socket

参数2:需要手动创建一个socket,并且填入,函数会把客户端发来的IP地址和端口号绑定在该socket上

参数3:填字符串数组,会接收到新连接上发来的第一个数据

参数4:一般设置成0,表示取消参数3的功能

参数5:填写字节长度,要比本地的最大传输协议地址长度大至少16个字节,即sizeof(struct sockaddr_in)+16

参数6:填写字节长度,要比远程的最大传输协议地址长度大至少16个字节,即sizeof(struct sockaddr_in)+16

参数7:接收新连接第一次发来的数据,配合参数3和4使用,填DWORD变量的地址

参数8:填重叠IO结构,填的是服务器对应的IO事件

        返回值:如果返回TRUE,表示立即完成即同步,如果返回FALSE,错误码为 ERROR_IO_PENDING 表示异步等待,否则出错。

##代码样例

g_allsock[g_count] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);//手动创建一个socket,用来绑定客户端的ip和端口号g_allOlp[g_count].hEvent = WSACreateEvent();//绑定事件char str[1024] = { 0 };DWORD dwRecvcount;//返回值 返回TRUE表示立即完成,返回FALES,如果错误码是ERROR_IO_PENDING表示异步等待,否则出错BOOL bRes = AcceptEx(g_allsock[0], g_allsock[g_count], str, 0, sizeof(struct sockaddr_in) + 16, sizeof(struct sockaddr_in) + 16, &dwRecvcount, g_allOlp[g_count]);//接收连接 

        3.WSARecv函数

该函数投递异步接收消息,函数原型

int WSAAPI WSARecv([in]      SOCKET                             s,[in, out] LPWSABUF                           lpBuffers,[in]      DWORD                              dwBufferCount,[out]     LPDWORD                            lpNumberOfBytesRecvd,[in, out] LPDWORD                            lpFlags,[in]      LPWSAOVERLAPPED                    lpOverlapped,[in]      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

参数1:客户端socket

参数2:是WSABUF类型的结构体对象,把接收到的消息存放在结构体buf中

参数3:是WSABUF对象的个数

参数5:接收消息成功,会把字节数返回到该参数

参数5:用于修改WSARecv函数调用行为的标志的指针

参数6:重叠IO结构

参数7:回调函数,在这里填NULL

        返回值:立即发生,会返回0,否则发生错误,如果错误码是 ERROR_IO_PENDING ,表示延迟处理。

##代码样例

int PostRecv(int index)
{WSABUF wsabuf;//参数2wsabuf.buf = g_strRecv;wsabuf.len = MAX_RECV_COUNT;DWORD dwRecvCount;//参数4DWORD dwFlag = 0;//参数5int wRes = WSARecv(g_allsock[index], &wsabuf, 1, &dwRecvCount, &dwFlag, &g_allOlp[index], NULL);if (wRes == 0){//立即完成//输出信息printf("%s\n", wsabuf.buf);memset(g_strRecv, 0, MAX_RECV_COUNT);//把数组重新置0//根据情况投递send//继续对自己投递接收PostRecv(index);return 0;}else{int a = WSAGetLastError();if (ERROR_IO_PENDING == a){//延迟处理}else{//出错}}
}

        4.WSAGetOverlappedTesult函数

该函数检索指定套接字上重叠操作的结果,即获取对应socket上的具体情况,函数原型

BOOL WSAAPI WSAGetOverlappedResult([in]  SOCKET          s,[in]  LPWSAOVERLAPPED lpOverlapped,[out] LPDWORD         lpcbTransfer,[in]  BOOL            fWait,[out] LPDWORD         lpdwFlags
);

参数1:有发生信号的客户端socket

参数2:socket所对应的重叠结构

参数3:获取到发生或者接收到的实际字节数,返回0表示下线

参数4:填TRUE

参数5:装填WSARecv函数的参数5

        返回值:成功返回TRUE,失败返回FALSE

##代码样例

WORD dwState;
WORD dwFlag;
BOOL bFlag = WSAGetOverlappedResult(g_allsock[i], &g_allOlp[i], &dwState, TRUE, &dwFlag);

        5.WSAResetEvent函数

该函数重置指定事件对象的状态为无信号。函数原型

BOOL WSAAPI WSAResetEvent([in] WSAEVENT hEvent
);

参数传递需要重置的事件

        返回值:成功返回TRUE,失败返回FALSE

        6.WSASend函数

该函数在连接的套接字上发送数据,函数原型

int WSAAPI WSASend([in]  SOCKET                             s,[in]  LPWSABUF                           lpBuffers,[in]  DWORD                              dwBufferCount,[out] LPDWORD                            lpNumberOfBytesSent,[in]  DWORD                              dwFlags,[in]  LPWSAOVERLAPPED                    lpOverlapped,[in]  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

参数和WSARecv的参数是一样的,在这里参数5就不需要取地址

返回值也是一样的

##代码样例

int Postsend(int index)
{WSABUF wsabuf;//参数2wsabuf.buf = "你好";wsabuf.len = MAX_RECV_COUNT;DWORD dwSendCount;//参数4DWORD dwFlag = 0;//参数5int wRes = WSASend(g_allsock[index], &wsabuf, 1, &dwSendCount, dwFlag, &g_allOlp[index], NULL);if (wRes == 0){//立即完成printf("send succee\n");return 0;}else{int a = WSAGetLastError();if (ERROR_IO_PENDING == a){//延迟处理return 0;}else{//出错return 0;}}
}

##重叠IO模型事件通知整体代码

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include<stdio.h>
#include<Winsock2.h>
#include<mswsock.h>//需要放在Winsock2.h下面
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")#define MAX_COUNT 1024
#define MAX_RECV_COUNT 1024
SOCKET g_allsock[MAX_COUNT];//socket数组
OVERLAPPED g_allOlp[MAX_COUNT];//事件数组
int g_count;
char g_strRecv[MAX_RECV_COUNT];int PostAccept();//接收连接的函数
int PostRecv(int index);//接收消息
int Postsend(int index);//发送消息//清理函数
void Clear()
{for (int i = 0; i < g_count; i++){closesocket(g_allsock[i]);WSACloseEvent(g_allOlp[i].hEvent);}
}
BOOL WINAPI fun(DWORD dwCtrlType)
{switch (dwCtrlType){case CTRL_CLOSE_EVENT://释放所有soket和事件Clear();break;}return TRUE;
}int main()
{SetConsoleCtrlHandler(fun, TRUE);//第一步 打开网络库并校验版本WORD wdVersion = MAKEWORD(2, 2);WSADATA wdsockMsg;int nRes = WSAStartup(wdVersion, &wdsockMsg);if (nRes != 0){printf("打开网络库失败\n");return 0;}if (2 != HIBYTE(wdsockMsg.wVersion) || 2 != LOBYTE(wdsockMsg.wVersion)){printf("版本不对\n");WSACleanup();return 0;}//第二步 创建socketSOCKET socketServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);if (socketServer == INVALID_SOCKET){//创建了无效的socketint a = WSAGetLastError();//获取错误码printf("创建出错\n");WSACleanup();return 0;}//第三步 绑定ip地址和端口号struct sockaddr_in si;si.sin_family = AF_INET;si.sin_port = htons(12332);si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");bind(socketServer, (const struct sockaddr*)&si, sizeof(si));//第四步 开始监听if (SOCKET_ERROR == listen(socketServer, SOCK_STREAM)){printf("监听失败\n");closesocket(socketServer);WSACleanup();return 0;}//服务器socket绑定事件,并且放入到数组中g_allsock[g_count] = socketServer;g_allOlp[g_count].hEvent = WSACreateEvent();g_count++;if (0 != PostAccept()){Clear();WSACleanup();return 0;}while (1){for (int i = 0; i < g_count; i++){int wRes = WSAWaitForMultipleEvents(1, &(g_allOlp[i].hEvent), FALSE, 0, FALSE);//获取第i个事件的信号if (wRes == WSA_WAIT_FAILED || wRes == WSA_WAIT_TIMEOUT)//出错或者超时{continue;}//有信号WORD dwState;WORD dwFlag;BOOL bFlag = WSAGetOverlappedResult(g_allsock[i], &g_allOlp[i], &dwState, TRUE, &dwFlag);//获取socket上的对应情况WSAResetEvent(g_allOlp[i].hEvent);//把信号置空if (bFlag == FALSE)//出错{int a = WSAGetLastError();if (a == 10054){printf("force close\n");//关闭closesocket(g_allsock[i]);WSACloseEvent(g_allOlp[i].hEvent);//从数组中删掉g_allsock[i] = g_allsock[g_count - 1];g_allOlp[i] = g_allOlp[g_count - 1];//循环控制变量-1i--;//下标减一g_count--;}continue;}if (0 == i){Postsend(g_count);printf("accept\n");//完成连接//投递recvPostRecv(g_count);//根据情况投递send//客户端适量++g_count++;//投递acceptPostAccept();continue;}if (0 == dwState){//客户端下线printf("close\n");//关闭closesocket(g_allsock[i]);WSACloseEvent(g_allOlp[i].hEvent);//从数组中删掉g_allsock[i] = g_allsock[g_count - 1];g_allOlp[i] = g_allOlp[g_count - 1];//循环控制变量-1i--;//下标减一g_count--;continue;}if (0 != dwState){//表示发送或者接收成功if (g_strRecv[0] != 0)//判断第一个元素不为空表示接收到消息{//输出信息printf("%s\n", g_strRecv);memset(g_strRecv, 0, MAX_RECV_COUNT);//把数组重新置0//继续对自己投递接收PostRecv(i);}}}}closesocket(socketServer);Clear();WSACleanup();return 0;
}int PostAccept()
{//手动创建一个socket,用来绑定客户端的ip和端口号g_allsock[g_count] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);g_allOlp[g_count].hEvent = WSACreateEvent();//绑定事件char str[1024] = { 0 };DWORD dwRecvcount;//返回值 返回TRUE表示立即完成,返回FALES,如果错误码是ERROR_IO_PENDING表示异步等待,否则出错BOOL bRes = AcceptEx(g_allsock[0], g_allsock[g_count], str, 0, sizeof(struct sockaddr_in) + 16, sizeof(struct sockaddr_in) + 16, &dwRecvcount, &g_allOlp[0]);//接收连接 if (bRes == TRUE){//立即完成//投递recvPostRecv(g_count);//根据情况投递send//客户端适量++g_count++;//投递acceptPostAccept();//递归完成return 0;}else{int a = WSAGetLastError();if (a == ERROR_IO_PENDING){//异步等待return 0;}else{//出错return 0;}}
}int PostRecv(int index)
{WSABUF wsabuf;//参数2wsabuf.buf = g_strRecv;wsabuf.len = MAX_RECV_COUNT;DWORD dwRecvCount;//参数4DWORD dwFlag = 0;//参数5int wRes = WSARecv(g_allsock[index], &wsabuf, 1, &dwRecvCount, &dwFlag, &g_allOlp[index], NULL);if (wRes == 0){//立即完成//输出信息printf("%s\n", wsabuf.buf);memset(g_strRecv, 0, MAX_RECV_COUNT);//把数组重新置0//根据情况投递send//继续对自己投递接收PostRecv(index);return 0;}else{int a = WSAGetLastError();if (ERROR_IO_PENDING == a){//延迟处理return 0;}else{//出错return 0;}}
}int Postsend(int index)
{WSABUF wsabuf;//参数2wsabuf.buf = "你好";wsabuf.len = MAX_RECV_COUNT;DWORD dwSendCount;//参数4DWORD dwFlag = 0;//参数5int wRes = WSASend(g_allsock[index], &wsabuf, 1, &dwSendCount, dwFlag, &g_allOlp[index], NULL);if (wRes == 0){//立即完成printf("send succee\n");return 0;}else{int a = WSAGetLastError();if (ERROR_IO_PENDING == a){//延迟处理return 0;}else{//出错return 0;}}
}

        完成例程实现逻辑

在这个模型中的WSAWaitFormultipleEvents函数中的参数6需要改为TRUE,意义:将等待事件函数与完成例程有机制结合在一起,实现等待事件函数与完成例程函数的异步执行,执行完并给等待事件函数信号,即 WSAWaitFormultipleEvents函数不仅能获取事件的信号通知,还能获取完成例程的执行通知。函数WSARecv和函数WSASend都需要使用回调函数

        回调函数需要使用系统给定的函数,函数原型

void
(CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(IN DWORD dwError,IN DWORD cbTransferred,IN LPWSAOVERLAPPED lpOverlapped,IN DWORD dwFlags);

参数1:获取到客户端socke的错误码

参数2:获取到客户端的发收字节数,为0表示客户端退出

参数3:获取到重叠IO的地址

参数4:表示函数执行的方式

 

##重叠IO模型完成例程的整体代码

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<WinSock2.h>
#include<mswsock.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")#define MAX_COUNT 1024
#define MAX_RECV_COUNT 1024SOCKET g_allsock[MAX_COUNT];
OVERLAPPED g_allIOp[MAX_COUNT];
int g_count;
char g_recvbuf[MAX_RECV_COUNT];//用来接收信息int PostAccept();//投递连接
int PostRecv(int index);//投递接收信息
int PostSend(int index);void Clear()
{for (int i = 0; i < g_count; i++){closesocket(g_allsock[i]);WSACloseEvent(g_allIOp[i].hEvent);}
}int main()
{//第一步 打开网络库并校验版本WORD wdVersion = MAKEWORD(2, 2);WSADATA wdSockMsg;int nRes = WSAStartup(wdVersion, &wdSockMsg);if (nRes != 0){printf("打开网络库失败\n");return 0;}if (HIBYTE(wdSockMsg.wVersion) != 2 || LOBYTE(wdSockMsg.wVersion) != 2){printf("版本不对\n");WSACleanup();return 0;}//第二步 创建socketSOCKET socketServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);if (socketServer == INVALID_SOCKET){printf("创建socket失败\n");WSACleanup();return 0;}//第三步 绑定ip地址和端口号struct sockaddr_in si;si.sin_family = AF_INET;si.sin_port = htons(12332);si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");if (SOCKET_ERROR == bind(socketServer, (const struct sockaddr*)&si, sizeof(si))){printf("绑定出错\n");closesocket(socketServer);WSACleanup();return 0;}//第四步 开始监听if (SOCKET_ERROR == listen(socketServer, SOCK_STREAM)){printf("监听失败\n");closesocket(socketServer);WSACleanup();return 0;}//第五步 重叠IO//把socket和对应事件放入到数组中g_allsock[g_count] = socketServer;g_allIOp[g_count].hEvent = WSACreateEvent();g_count++;//投递连接if (0 != PostAccept()){Clear();WSACleanup();return 0;}//循环处理每一个socketwhile (1){//接收消息int wRes = WSAWaitForMultipleEvents(1, &(g_allIOp[0].hEvent), FALSE, WSA_INFINITE, TRUE);//获取信号if (wRes == WSA_WAIT_FAILED || wRes == WSA_WAIT_IO_COMPLETION){//获取信号错误continue;}WSAResetEvent(g_allIOp[0].hEvent);//把信号置空//PostSend(g_count);//完成连接printf("accept\n");//投递RecvPostRecv(g_count);//数量增加g_count++;//继续投递PostAccept();}Clear();WSACleanup();return 0;
}int PostAccept()
{while (1){//手动创建socketg_allsock[g_count] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);g_allIOp[g_count].hEvent = WSACreateEvent();//绑定事件if (g_allsock[g_count] == SOCKET_ERROR)//创建失败{return 0;}char str[1024] = { 0 };DWORD dwRecvcount;BOOL aRes = AcceptEx(g_allsock[0], g_allsock[g_count], str, 0, sizeof(struct sockaddr) + 16,sizeof(struct sockaddr) + 16, &dwRecvcount, &g_allIOp[0]);if (aRes == TRUE)//表示立即完成{//接收信息//投递RECVPostRecv(g_count);//数量增加g_count++;//循环该客户端//PostAccept();continue;}else{int a = WSAGetLastError();if (a == ERROR_IO_PENDING){//异步等待break;}else{//出错break;}}}return 0;
}void CALLBACK RecvCall(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{int i = (int)(lpOverlapped - &g_allIOp[0]);//地址相减拿到下标if (dwError == 10054 || cbTransferred == 0)//客户端退出{//关闭printf("close\n");closesocket(g_allsock[i]);WSACloseEvent(g_allIOp[i].hEvent);g_allsock[i] = g_allsock[g_count - 1];g_allIOp[i] = g_allIOp[g_count - 1];g_count--;}else{printf("%s\n", g_recvbuf);memset(g_recvbuf, 0, MAX_RECV_COUNT);PostRecv(i);}
}int PostRecv(int index)
{WSABUF wsabuf;wsabuf.buf = g_recvbuf;wsabuf.len = MAX_RECV_COUNT;DWORD dwRecvCount;DWORD dwFlag = 0;int wRes = WSARecv(g_allsock[index], &wsabuf, 1, &dwRecvCount, &dwFlag, &g_allIOp[index], RecvCall);if (wRes == 0){//立即完成printf("%s\n", wsabuf.buf);//把内存置为0memset(g_recvbuf, 0, MAX_RECV_COUNT);//继续投递PostRecv(index);return 0;}else{int a = WSAGetLastError();if (a == WSA_IO_PENDING){//已成功启动重叠的操作,延迟完成return 0;}else{//出现错误return 0;}}
}void CALLBACK SendCall(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{printf("send succee\n");
}int PostSend(int index)
{WSABUF wsabuf;wsabuf.buf = "你好";wsabuf.len = MAX_RECV_COUNT;DWORD dwSendcount;DWORD dFlag = 0;int wRes = WSASend(g_allsock[index], &wsabuf, 1, &dwSendcount, dFlag, &g_allIOp[index], SendCall);if (wRes == 0){//立即完成发送printf("send succee\n");return 0;}else{int a = WSAGetLastError();if (a == ERROR_IO_PENDING){//延迟处理,异步等待return 0;}else{//出现错误return 0;}}
}


http://www.ppmy.cn/news/7657.html

相关文章

BCryptPasswordEncoder加密与MD5加密的区别

MD5 加密说明 MD5&#xff08;Message Digest Algorithm 5&#xff09;中文名为消息摘要算法第五版&#xff0c;是计算机安全领域广泛使用的一种散列函数&#xff0c;用以提供消息的完整性保护。 MD5作为一种常用的摘要算法&#xff08;或指纹算法&#xff09;&#xff0c;其…

B/S结构和C/S结构详细介绍

什么是c/s结构、b/s结构 1、C/S结构&#xff0c;即Client/Server(客户机/服务器)结构&#xff0c;是大家熟知的软件系统体系结构&#xff0c;通过将任务合理分配到Client端和Server端&#xff0c;降低了系统的通讯开销&#xff0c;充分利用两端硬件环境的优势。早期的软件系统…

Spring MVC框架学习

前言:本篇博客将从三个方面来写我们要学习SpringMVC的什么: 连接:当用户在游览器中输入一个url之后,能将这个url请求映射到自己写的程序,也就是访问一个地址时,能够连接到门自己写的服务器. 获取参数:用户访问时如果带一些参数,我该怎样获取.返回数据:执行业务代码之后…

47. 批量规范化 代码从零开始实现 + 简洁实现

1. 从零实现 下面&#xff0c;我们从头开始实现一个具有张量的批量规范化层。 import torch from torch import nn from d2l import torch as d2l# X是输入&#xff0c;gamma, beta是两个可以学习的参数&#xff0c;moving_mean, moving_var是整个数据集的均值和方差&#xf…

我把这一年学的 CSS 知识点精炼总结成了一篇文档

文章目录一.CSS简介1.什么是CSS&#xff1f;二.CSS语法1.语法规则2.注释三.CSS选择器1.CSS的id选择器2.CSS的class选择器四.CSS创建1.外部样式表2.内部样式表3.内联样式4.多重样式5.多重样式的优先级五.CSS 背景1.背景颜色2.背景图像3.背景图像 - 水平或垂直平铺4.背景图像- 设…

【微服务】3、NACOS 的使用

&#x1f516; Eureka 可以做注册中心【https://github.com/Netflix/eureka】 &#x1f516; 但它的功能比较少&#xff0c;仅仅注册中心 &#x1f516; nacos 也可做注册中心&#xff0c;且功能更加丰富【https://nacos.io/】 一、了解 Nacos ✏️ Nacos 是阿里巴巴的产品&am…

linux 分析启动时服务时间消耗

工具systemd-analyze systemd-analyze是一个分析启动性能的工具&#xff0c;用于分析启动时服务时间消耗。 1 systemd-analyze使用 1.1 查看启动耗时 rootloongson-pc:/# systemd-analyze 1.2 查看每个服务的启动耗时 rootloongson-pc:/# systemd-analyze blame 1.3 显…

2022年个人融资方法和工具研究报告

第一章 理论和概况 1.1 融资概念 融资&#xff0c;英文为Financing&#xff0c;指为支付超过现金或转账的购货款而采取的货币交易手段&#xff0c;或者为取得特定资产而筹集资金所采取的货币手段。融资通常指货币资金的持有者和需求者之间&#xff0c;直接或间接地进行资金融…