TCP/IP 事件选择模型

OSI模型和TCP/IP模型 本文主要介绍了 OSI 模型和 TCP/IP 模型的相关内容,包括各层的功能、数据传输单位、典型协议以及两者的区别等 阅读详情

服务端:

1.打开网络库

int WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);

2.校验版本号

2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion)  // (检验版本号是 2.2)

3.创建socket 套接字

SOCKET socket(int af, int type, int protocol);

 4.绑定地址与端口号

int bind(SOCKET s, const sockaddr* addr, int namelen);

 5.进行监听

int WSAAPI listen(SOCKET s, int backlog);

6.事件选择模型开始

第一步:创建事件对象:

WSAEVENT WSAAPI WSACreateEvent();

第二步:绑定并投递

int WSAAPI WSAEventSelect
(
  SOCKET   s,
  WSAEVENT hEventObject,
  long     lNetworkEvents
);

第三步:创建结构体用于装所有的socket和对应的事件对象,并记录对应的个数

struct fd_es_set
{
	SOCKET allsocks[64];	// 装所有的socket
	WSAEVENT allevents[64];	// 装所有的事件
	int count;				// 记录个数
};

第四步:等待事件

DWORD WSAAPI WSAWaitForMultipleEvents(
  DWORD          cEvents,             //事件,socket的个数
  const WSAEVENT *lphEvents,  //事件数组的首地址
  BOOL           fWaitAll,               //直接填FALSE
  DWORD          dwTimeout,      //可以填WSA_INFINITE,表示一直等待事件的发生
  BOOL           fAlertable             //直接填FALSE
);

        如果WSAWaitForMultipleEvents()函数中的参数4 填具体的等待时间的话,要进行判断是否超时操作:

判断是否超时

if (WSA_WAIT_TIMEOUT == retWaitEv)
{
	// 在规定的时间每没有等待到事件发生 直接继续进行等待
	continue;
}

第五步:列举事件

int WSAAPI WSAEnumNetworkEvents(
  SOCKET             s,
  WSAEVENT           hEventObject,
  LPWSANETWORKEVENTS lpNetworkEvents
);

第六步:分类处理 FD_ACCEPT FD_READ FD_WRITE FD_CLOSE

// 处理 FD_ACCEPT FD_READ FD_WRITE FD_CLOSE
if (lpNetworkEvents->lNetworkEvents & FD_ACCEPT)
{
    if (lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] == 0)
    {
       
    }
}

代码如下:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

/*
	事件选择模型步骤:
	第一步:创建一个事件对象	
				WSACreateEvent();
	第二步:将socket 和 对应的事件绑定在一起 并投递给系统,由系统帮我们监视着
				WSAEventSelect();
	第三步:创建一个结构体,用来装所有的socket和对应的事件,每创建一个socket和对应的事件都装进结构体对应的数组中
				struct fd_eventsocket_set{SOCKET allsock[64]; WSAEVENT allevent[64]; int count;};
				注意每装一次 对应的结构体的变量 count就要+1
	第四步:查看事件是否有信号  
				WSAWaitForMultipleEvents();
	第五步:有信号的话进行分类处理
				WSAEnumNetworkEvents();
	第六步:分类处理 FD_ACCEPT FD_WRITE FD_READ FD_CLOSE
*/

// 6.3、创建结构体用来装所有的socket和对应的事件
struct fd_es_set
{
	SOCKET allsocks[64];	// 装所有的socket
	WSAEVENT allevents[64];	// 装所有的事件
	int count;				// 记录个数
};
// 定义结构体对象
struct fd_es_set esSet = { {0}, {NULL}, 0 };

// 声明WSAStartup 函数中参数2所需的结构体
WSADATA wsadata;	

// 监视窗口的回调函数
BOOL WINAPI fun(DWORD dwCtrlType)
{
	switch (dwCtrlType)
	{
	case CTRL_CLOSE_EVENT:
	{
		// 关闭套接字 和对应的事件
		for (int i = 0; i < esSet.count; i++)
		{
			closesocket(esSet.allsocks[i]);
			WSACloseEvent(esSet.allevents[i]);
		}
		// 清理网络库
		WSACleanup();
	}
	break;
	}
	return TRUE;
}

// 1.打开网络库
void OpenWSAStarup()
{
	WORD version = MAKEWORD(2, 2);	// 设置版本号为 2.2	
	int retStartup = WSAStartup(version, &wsadata);
	// 检验是否成功打开网络库
	if (0 != retStartup)
	{
		// 出错了
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("打开网络库失败,错误码为: %d\n", error);
		return;	// 退出
	}
}

// 2.检验版本号
void CheckVersion()
{
	if (2 != HIBYTE(wsadata.wVersion) || 2 != LOBYTE(wsadata.wVersion))
	{
		// 出错了
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("检验版本号出错,错误码为: %d\n", error);
		// 清理网络库
		WSACleanup();
		return;	// 退出
	}
}

// 3.创建socket 服务端的socket
SOCKET createSocket()
{
	SOCKET socket_Server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	// 检验是否成功创建socket
	if (INVALID_SOCKET == socket_Server)
	{
		// 出错了
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("创建socket错误,错误码为: %d\n", error);
		// 清理网络库
		WSACleanup();
		return 0;	// 退出
	}
	return socket_Server;
}

// 4.绑定地址与端口号
void Bind(SOCKET socket_Server)
{
	// 声明bind() 函数所需的参数2 的结构体
	struct sockaddr_in serverMsg;
	// 给结构体成员初始化
	serverMsg.sin_family = AF_INET;								// ip 地址的类型
	serverMsg.sin_port = htons(12345);							// 端口号
	serverMsg.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");	// 本地ip
	int retBind = bind(socket_Server, (struct sockaddr*)&serverMsg, sizeof(serverMsg));
	// 检验是否成功绑定ip和端口号
	if (SOCKET_ERROR == retBind)
	{
		// 出错了
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("绑定ip和端口号失败,错误码为: %d\n", error);
		// 关闭套接字
		closesocket(socket_Server);
		// 清理网络库
		WSACleanup();
		return;	// 退出
	}
}

// 5.进行监听
void Listen(SOCKET socket_Server)
{
	if (SOCKET_ERROR == listen(socket_Server, SOMAXCONN))
	{
		// 出错了
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("进行监听失败,错误码为: %d\n", error);
		// 关闭套接字
		closesocket(socket_Server);
		// 清理网络库
		WSACleanup();
		return;	// 退出
	}
}

// 6.事件选择模型核心代码
void EventSelect(SOCKET socket_Server)
{
	// 6.1、创建一个事件对象
	WSAEVENT eventServer = WSACreateEvent();
	// 检验是否成功创建事件对象
	if (WSA_INVALID_EVENT == eventServer)
	{
		// 创建事件对象失败
		// 出错了
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("WSACreateEvent() 创建事件对象失败,错误码为: %d\n", error);
		// 关闭套接字
		closesocket(socket_Server);
		// 清理网络库
		WSACleanup();
		return;	// 退出
	}
	// 6.2、绑定并投递
	int retEtSel = WSAEventSelect(socket_Server, eventServer, FD_ACCEPT);
	// 检验是否成功绑定并投递
	if (SOCKET_ERROR == retEtSel)
	{
		// 绑定并投递失败
		int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
		printf("WSAEventSelect() 绑定并投递失败,错误码为: %d\n", error);
		// 关闭套接字
		closesocket(socket_Server);
		// 关闭事件对象
		WSACloseEvent(eventServer);
		// 清理网络库
		WSACleanup();
		return;	// 退出
	}
	//// 6.3、创建结构体用来装所有的socket和对应的事件
	//struct fd_es_set
	//{
	//	SOCKET allsocks[64];	// 装所有的socket
	//	WSAEVENT allevents[64];	// 装所有的事件
	//	int count;				// 记录个数
	//};
	//// 定义结构体对象
	//struct fd_es_set esSet = { {0}, {NULL}, 0 };
	// 将socket装进数组中
	esSet.allsocks[esSet.count] = socket_Server;
	// 将对应的事件装进数组中
	esSet.allevents[esSet.count] = eventServer;
	// 记录个数++
	esSet.count++;
	// 循环等待事件 一直进行等待
	while (1)
	{
		// 6.4、等待事件 参数1:事件、socket 的个数 参数2:事件数组的首地址 参数3:直接填FALSE 参数4:等待时间(WSA_INFINITE 等待直到事件发生)  参数5:直接填FALSE
		DWORD retWaitEvn = WSAWaitForMultipleEvents(esSet.count, esSet.allevents, FALSE, WSA_INFINITE, FALSE);
		// 检验是否等到事件发生
		if (WSA_WAIT_FAILED == retWaitEvn)
		{
			// 没有等到事件的发生 进行继续等待
			continue;
		}
		// 获取发生事件所在的数组下标
		DWORD iIndex = retWaitEvn - WSA_WAIT_EVENT_0;
		// 获取下标之后的操作
		// 6.5、列举事件 获取事件类型,并将事件上的信号重置
		// 声明 WSAEnumNetworkEvents()函数 中参数3所需的结构体 
		/*
		typedef struct _WSANETWORKEVENTS {
			long lNetworkEvents;
			int  iErrorCode[FD_MAX_EVENTS];
		} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
		*/
		WSANETWORKEVENTS NetworkEvents;
		int retEumEv = WSAEnumNetworkEvents(esSet.allsocks[iIndex], esSet.allevents[iIndex], &NetworkEvents);
		// 判断列举事件是否出错
		if (SOCKET_ERROR == retEumEv)
		{
			// 列举事件出错
			int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
			printf("WSAEnumNetworkEvents() 列举事件出错,错误码为: %d\n", error);
			continue;
		}
		// 6.6、分类处理 FD_ACCEPT FD_WRITE FD_READ FD_CLOSE
		// 处理FD_ACCEPT
		if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
		{
			if (0 == NetworkEvents.iErrorCode[FD_ACCEPT_BIT])
			{
				// accept进行链接 本质创建客户端socket
				SOCKET socketClient = accept(esSet.allsocks[iIndex], NULL, NULL);
				// 判断是否成功创建客户端socket
				if (INVALID_SOCKET == socketClient)
				{
					// 创建客户端socket失败
					int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
					printf("处理FD_ACCEPT 创建客户端socket失败,错误码为: %d\n", error);
					continue;
				}
				// 创建对应的事件对象
				WSAEVENT eventClient = WSACreateEvent();
				// 检验是否成功创建事件对象
				if (WSA_INVALID_EVENT == eventClient)
				{
					// 创建对应的事件对象失败 				
					int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
					printf("创建对应的(client)事件对象失败,错误码为: %d\n", error);
					// 关闭客户端socket
					closesocket(socketClient);
					continue;
				}
				// 将客户端socket和对应的事件对象绑定在一起并投递给系统
				int retEventSel = WSAEventSelect(socketClient, eventClient, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE);
				// 判断是否绑定并投递成功
				if (SOCKET_ERROR == retEventSel)
				{
					// 绑定并投递失败 				
					int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
					printf("绑定并投递失败(client),错误码为: %d\n", error);
					// 关闭客户端socket
					closesocket(socketClient);
					// 关闭事件对象
					WSACloseEvent(eventClient);
					continue;
				}
				// 将客户端socket和对应的事件对象装进到数组中
				esSet.allsocks[esSet.count] = socketClient;
				esSet.allevents[esSet.count] = eventClient;
				esSet.count++;	// 注意个数要++
				// 可以打印提示一下成功处理 FD_ACCEPT
				printf("accept success\n");
			}
			else
			{
				// 处理FD_ACCEPT 出错 
				printf("处理FD_ACCEPT出错 错误码为%d\n", NetworkEvents.iErrorCode[FD_ACCEPT_BIT]);
				continue;
			}
		}
		// 处理FD_WRITE
		if (NetworkEvents.lNetworkEvents & FD_WRITE)
		{
			if (0 == NetworkEvents.iErrorCode[FD_WRITE_BIT])
			{
				// 进行 send
				if (SOCKET_ERROR == send(esSet.allsocks[iIndex], "connection ok", sizeof("connection ok"), 0))
				{
					// 发送数据失败
					int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
					printf("处理FD_WRITE send 发送数据失败,错误码为: %d\n", error);
					continue;
				}
				printf("write ok\n");
			}
			else
			{
				// 处理FD_WRITE 出错
				printf("处理FD_WRITE出错 错误码为%d\n", NetworkEvents.iErrorCode[FD_WRITE_BIT]);
				continue;
			}
		}
		// 处理FD_READ
		if (NetworkEvents.lNetworkEvents & FD_READ)
		{
			if (0 == NetworkEvents.iErrorCode[FD_READ_BIT])
			{
				// recv 接收信息
				// 定义接收数据的缓存区
				char recvBuf[1024] = { 0 };
				int retRecv = recv(esSet.allsocks[iIndex], recvBuf, sizeof(recvBuf), 0);
				// 判断是否成功接收到信息
				if (SOCKET_ERROR == retRecv)
				{
					// 接收到信息
					int error = WSAGetLastError();	// 通过WSAGetLastError 获取错误码
					printf("处理FD_READ recv 接收到信息,错误码为: %d\n", error);
					continue;
				}
				printf("客户端say: %s\n", recvBuf);
			}
			else
			{
				// 处理FD_READ_BIT 出错 
				printf("处理FD_READ出错 错误码为%d\n", NetworkEvents.iErrorCode[FD_READ_BIT]);
				continue;
			}
		}
		// 处理FD_CLOSE
		if (NetworkEvents.lNetworkEvents & FD_CLOSE)
		{
			// 打印客户端下线了
			printf("客户端下线了!!!\n");
			// 出错了
			// 先关闭对应的socket 在 删除,删除的时候可以将数组最后的一个元素覆盖掉要删除的元素
			closesocket(esSet.allsocks[iIndex]);
			esSet.allsocks[iIndex] = esSet.allsocks[esSet.count - 1];
			// 先关闭对应的事件 在删除 同上
			WSACloseEvent(esSet.allevents[iIndex]);
			esSet.allevents[iIndex] = esSet.allevents[esSet.count - 1];
			// 注意socket、对应的事件个数要--
			esSet.count--;
		}
	}
}


int main()
{
	// 监视关闭窗口按钮
	SetConsoleCtrlHandler(fun, TRUE);

	// 1.打开网络库
	OpenWSAStarup();

	// 2.检验版本号
	CheckVersion();

	// 3.创建socket 服务端的socket
	SOCKET socketServer = createSocket();

	// 4.绑定地址与端口号
	Bind(socketServer);

	// 5.进行监听
	Listen(socketServer);

	// 6.事件选择模型核心代码
	EventSelect(socketServer);

	// 关闭套接字 和对应的事件
	for (int i = 0; i < esSet.count; i++)
	{
		closesocket(esSet.allsocks[i]);
		WSACloseEvent(esSet.allevents[i]);
	}
	
	// 清理网络库
	WSACleanup();
	system("pause");
	return 0;
}

客户端代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Winsock.h>
#pragma comment(lib,"ws2_32.lib")

WSADATA WSAData;
// 1,打开网络库
void OpenWSAStarup()
{
	// 1,打开网络库
	WORD version = MAKEWORD(2, 2);	//设置要使用的库的版本 MAKEWORD(主版本,副版本); 
	int n = WSAStartup(version, &WSAData);
	// 检验是否成功打开网络库
	if (0 != n)
	{
		// 打开网络库失败,通过n 返回的错误码,给出提示
		switch (n)
		{
		case WSASYSNOTREADY:
			printf("重启电脑试试,或者检查ws_2_32库是否存在\n");
			break;
		case WSAVERNOTSUPPORTED:
			printf("当前库版本号不支持,尝试更换版本试试\n");
			break;
		case WSAEPROCLIM:
			printf("已达到对Windows套接字实现支持的任务数量的限制\n");
			break;
		case WSAEINPROGRESS:
			printf("正在阻止Windows Sockets 1.1操作,当前函数运行期间,因为某些原因造成阻塞\n");
			break;
		case WSAEFAULT:
			printf("lpWASData参数不是有效的指针,参数写错了\n");
			break;
		default:
			break;
		}
	}
}
// 2.检验版本
void CheckVersion()
{
	if (2 != HIBYTE(WSAData.wVersion) || 2 != LOBYTE(WSAData.wVersion))
	{
		// 打开版本号 2.2 失败
		printf("打开版本号 2.2 失败, 正在退出程序...\n");
		// 关闭网络库
		WSACleanup();
		// 退出程序
		return;
	}
}
// 3.创建socket
SOCKET CreateSocket()
{
	// 3.创建套接字 socket 创建服务端的socket
	SOCKET socketCreate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	// 检验是否成功创建套接字
	if (INVALID_SOCKET == socketCreate)
	{
		// 创建套接字失败
		// 获取错误码
		int error = WSAGetLastError();
		printf("创建套接字失败,返回错误号为:%d\n", error);
		// 关闭网络库
		WSACleanup();
		// 退出程序
		return 0;
	}
	return socketCreate;
}
// 4.连接服务器
void Connection(SOCKET socket_)
{
	// 4.连接到服务器
	// 创建connect() 函数中参数2所需的结构体 用来装IP地址和端口号
	sockaddr_in client_s;
	//给结构体成员赋值
	client_s.sin_family = AF_INET;		//IP地址类型
	client_s.sin_port = htons(12345);	//端口号
	client_s.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int nCon = connect(socket_, (struct sockaddr*)&client_s, sizeof(client_s));
	// 检验是否成功连接到服务端
	if (SOCKET_ERROR == nCon)
	{
		// 连接服务端失败
		// 获取错误码
		int error = WSAGetLastError();
		printf("连接服务端失败,返回错误号为:%d\n", error);
		// 关闭套接字
		closesocket(socket_);
		// 关闭网络库
		WSACleanup();
		// 退出程序
		return;
	}
}

// 5.与服务端发送信息
void RecvAndSend(SOCKET socket_)
{
	// 只收一次 信息
	// 定义接收服务端信息的缓存区
	char recvBuf[1024] = { 0 };
	int res = recv(socket_, recvBuf, 1024, 0);
	// 判断是否成功接收到信息
	if (0 == res)
	{
		printf("服务端下线了\n");
		return;
	}
	else if (SOCKET_ERROR == res)
	{
		// 获取错误码
		int error = WSAGetLastError();
		printf("连接服务端失败,返回错误号为:%d", error);
		printf("\n");
		return;
	}
	else
	{
		// 打印信息
		printf("服务端say: %s\n", recvBuf);
	}
	printf("我是客户端,正在发送信息,请稍等...\n");

	// 5.与服务端进行收发信息
	while (1)
	{
		// 发信息
		char sendBuf[1024] = { 0 };
		scanf_s("%s", sendBuf, 1024);
		// 设置输入 0 时自动退出
		if ('0' == sendBuf[0])
		{
			break;	//退出循环
		}
		send(socket_, sendBuf, 1024, 0);
	}
}

int main()
{
	// 1,打开网络库
	OpenWSAStarup();
	// 2.校验版本
	CheckVersion();
	// 3.创建socket
	SOCKET socketServer = CreateSocket();
	// 4.连接服务器
	Connection(socketServer);
	// 5.与服务端发送信息
	RecvAndSend(socketServer);

	// 关闭套接字
	closesocket(socketServer);
	// 关闭网络库
	WSACleanup();
	system("pause");
	return 0;
}

程序运行结果:

OSI 模型,TCP/IP模型 主机 A 中的主机到主机层会将文件分成更小的段,添加纠错和流量控制信息,然后通过网络将数据段传输到主机 B。它将计算机网络通信过程划分为七个不同的层次,每个层次负责执行特定的功能,从而实现网络中的数据传输。在此示例中,Internet 层在将电子邮件从您的计算机传送到您朋友的计算机中起着至关重要的作用。一个建立连接的起点,整个字节顺序的传输,和一个关闭连接的终点组成了这次传输。在这个例子中,主机到主机层负责在主机 A 和主机 B 之间提供可靠的连接,将文件分成更小的段,并在目的地重新组装这些段。 阅读详情

相关推荐

TCP/IP四层模型

TCP/IP 网络分层模型 还是先从 TCP/IP 协议开始讲起,一是因为它非常经典,二是因为它是目前事实上的网络通信标准,研究它的实用价值最大。TCP/IP 当初的设计者真的是非常聪明,创造性地提出了“分层”的概念,把复杂的网络通信划分出多个层次,再给每一个层次分配不同的职责,层次内只专心做自己的事情就好,用“分而治之”的思想把一个“大麻烦”拆分成了数个“小麻烦”,从而解决了网络通信的难题。你应该对 TCP/IP 的协议栈有所了解吧,这里我再贴一下层次图。 TCP/IP 协议总共有四层,就像搭积木

m0_37145844的博客 1万+

基于event实现的tcp服务器

可以进行如下的测试重现异常情况: 先后在终端A和B上执行nc 127.1 8888命令, 然后ctrl+c结束掉终端A上的nc命令, 再次进如到终端B上, 则会出现异常情况.(原因是由于connev是一个全局变量, 所以connev只能保留最后一次所赋的值, 当客户端退出后, 服务端会调用event_del(connev);若先结束终端B上的nc命令, 不会出现异常情况.在堆区开辟空间,利用event_new函数最后一个参数传递读事件。

SDTyuan的博客 222

详解TCP/IP协议模型

本文阅读大约10分钟图解什么是 TCP/IP 模型?1. 网络访问层(数据连接 + 物理层)1.1 作用1.2 协议应用2. 网络层2.1 作用2.2 协议应用3. 传输层3.1 作用3.2 协议应用4. 应用层4.1 作用4.2 协议应用5. Socket6. ping到底是用的TCP还是UDP? 图解 网络传输图 什么是 TCP/IP 模型? TCP/IP 模型有四个抽象的层次,描述了总体...

巴黎会飞的猪 5766

TCP之 Event select模型

前记:select模型主要用于解决传统tcp通信线程过多的问题,而EventSelect模型则用于解决select模型的效率问题,因为select模型的内部是使用Sleep函数来阻塞线程,然后消耗系统时间片,从而降低了效率,而event select模型则使用WSAEVENT的通知机制。服务端:// 20180527_socket.cpp : 定义控制台应用程序的入口点。 // #include...

qingzai_的专栏 1102

tcp事件选择模型服务器

在学习服务器知识时用事件选择模型写的服务器,里面有大量注释供读者解读理解。

使用libx265对YUV进行h265编码

使用libx265对YUV进行h265编码

Embedded engineer 3079

Tcp心跳

心跳包(HeartBeat)就是在客户端和服务器间定时通知对方自己状态的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。     心跳是用来判断对方(客户端或者服务端)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的

863

告别重启烦恼:用WSL2让Docker和VMware在Win10上真正共存

本文详细介绍了如何在Windows 10系统上,借助WSL2实现Docker与VMware的真正共存,彻底告别以往需要反复重启切换的烦恼。通过启用Hyper-V兼容模式并进行正确配置,开发者无需重启即可同时高效运行容器和虚拟机,显著提升开发与测试工作流的连续性和效率。

salt9的博客 988

tcp中accept()的理解

服务端的曾经绑定的套接字描述符包含客户端的ip,端口号,(客户端的属性)

weixin_73964834的博客 732

(UE5 5.2)HISM Mobile DrawInstance在渲染层的实现浅分析

在 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析 这篇博客大致介绍HISM组件从游戏线程到渲染线程的重建KD-Tree和剔除并提交DrawCall逻辑,但是没有分析渲染层的大致数据结构和实现. 可以看出FHierarchicalStaticMeshSceneProxy 实际存储Instance数组数据来自于FInstancedStaticMeshSceneProxy FHierarchicalStaticMeshSceneProxy只是以FClu

qq_29523119的博客 2725

BALM2深度解析 | 港大MARS实验室如何用点簇革新激光BA?

本文深度解析了港大MARS实验室提出的BALM2方案如何通过点簇技术革新激光BA(Bundle Adjustment)处理。BALM2将点云数据聚合为点簇,显著提升计算效率,实测显示其计算耗时仅为传统方法的1/20。文章详细介绍了点簇的核心原理、二阶优化方法及与传统方法的性能对比,展示了其在激光SLAM领域的突破性应用。

weixin_29212867的博客 153

使用libevent实现基于event的tcp服务器

Libevent 介绍:Libevent 是一个用于编写快速可移植非阻塞 IO 的库

m0_60663280的博客 2321

从OAuth到DID:Web4.0身份验证协议的技术演进图谱

在数字身份体系从Web2.0向Web4.0跨越的进程中,身份验证协议正经历着从中心化授权到自主主权的范式转移。本文通过对比OAuth 2.0、OpenID Connect等传统方案与W3C DID、ION等去中心化协议的技术架构,揭示身份验证技术在性能、安全、隐私三大维度的代际差异。基于对GitHub、欧盟数字身份钱包等典型系统的实测数据分析,量化评估中心化授权服务器的单点故障风险与DID链上验证的吞吐量瓶颈。结合零知识证明、分布式密钥管理等前沿技术,为开发者提供面向Web4.0的渐进式身份架构迁移策略。

水务人 835

windows TCP/IP 网络编程(三)5种windows网络模型(2) WsaEventSelect事件选择模型

1 windows处理用户行为的两种方式 2 事件选择的原理

weixin_39303983的博客 2417

LangGraph的容错机制:从节点失败到图级回滚

核心概念铺垫:讲解LLM应用容错与事务性的核心概念(幂等性、重试策略、降级策略、快照、回滚、原子性、一致性、隔离性、持久性、最终一致性),对比LangGraph容错机制与传统数据库ACID事务、Apache Airflow/Kubernetes Workflow/Kubeflow Pipelines容错机制的异同;LangGraph容错机制的演进历史:用markdown表格梳理LangGraph从0.0.1到1.5.0(截止202X年X月)的容错机制发展历程;节点级别的容错:重试与降级。

AI Python 编程之道的博客 172

26.Labview波形图、XY图、强度图使用精讲

1. 波形图基础概念,如何使用,1.1 波形图与波形图表1.2 XY图如何设计、如何使用?1.3 强度图原理、如何使用、使用案例;2. 图形的参数设置2.1 波形图及波形图表的外观设计2.2 XY图的前面板设计2.3 强度图属性设置。

关注我,更多技术问题欢迎私聊~ 7502

TCP.03.事件选择模型

文章目录基础知识消息机制事件机制事件选择模型步骤事件选择模型相关函数创建、销毁、重置事件对象绑定,投递事件对象(重点)等待事件 https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket 基于TCP/IP的网络编程还有5种模型: SELECT模型 事件选择模型 异步选择模型 重叠IO模型 完成端口模型 这次先讲第二种。 基础知识 windows处理用户行为有两种方式: 消息机制 其核心是消息队列,就是将要处理的

老毛的博客 2108

使用Python爬取在线图书馆的图书馆藏和阅读记录

通过使用Python编写爬虫程序,我们可以从在线图书馆上获取图书馆藏和阅读记录,帮助人们更好地管理和利用图书馆资源。本文简要介绍了爬虫程序的准备工作、网页解析和数据提取、数据的保存和处理的关键步骤,并提供了一个示例代码。在实际应用中,我们需要注意遵守在线图书馆的使用规则和爬虫道德准则,确保合法、合规地进行爬取操作。以上仅为概述,实际应用的过程中可能需要根据具体需求进行适当的调整和改进。

2201_76125393的博客 729

OSI 模型和 TCP/IP 模型异同比较

OSI 模型和 TCP/IP 模型异同比较 相同点 ① OSI 参考模型与 TCP/IP 参考模型都采用了层次结构。 ② 都能够提供面向连接和无连接两种通信服务机制。 不同点 ① OSI 采用的七层模型; TCP/IP 是四层结构。 ② TCP/IP 参考模型没有对网络接口层进行细分,只是一些概念性的描述; OSI 参考模型对服务和协议做了明确的区分。 ③ OSI 先有模型,后有协议规范,适合于描述各种网络;TCP/IP 是先有协议集然后建立模型,不适用于非 TCP/IP 网络。 ④ TCP/IP 一开始就

lxh_____的博客 2万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

TCP/IP 模型中,网络层对 IP 地址的分配与路由选择

IP 地址分配:通过静态或动态(DHCP)方式分配 IP 地址,结合子网掩码进行网络和主机部分的划分,确保网络中的设备可以互相通信。路由选择:通过路由器和路由协议,基于目标 IP 地址和路由表的规则动态选择数据包的最佳路径,最终将数据包从源设备送达目标设备。网络层的 IP 地址分配和路由选择是确保互联网和局域网通信顺畅的关键技术,它们通过合理的地址管理和路径选择机制,有效地支持了全球范围内的通信。作者:神的孩子都在歌唱。

智的博客 2501

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

网络模型——OSI模型与TCP/IP模型

OSI模型与TCP/IP模型

qq_53499304的博客 9793

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

TCP/IP网络模型详解

在计算机网络领域,网络模型通常指的是 OSI(Open Systems Interconnection)参考模型或 TCP/IP(Transmission Control Protocol/Internet Protocol)模型。这些模型描述了网络中数据传输的层次结构,便于理解和设计网络系统。

qq_42037383的博客 3862

TCP/IP模型

1.   TCP/IP协议介绍TCP/IP(又称TCP/IP协议簇)是一组用于实现网络互连的通信协议,其名称来源于该协议簇中两个重要的协议(IP协议和TCP协议)。基于TCP/IP的参考模型将协议分成四个层次,它们分别是网络接口层、网际互连层(IP层)、传输层

guoping16的专栏 1万+

深度了解TCP/IP模型

TCP/IP模型是一个网络通信协议体系,由两个核心协议组成:传输控制协议(TCP)和因特网协议(IP)。这两个协议协同工作,确保数据能够在网络中可靠、高效地传输。TCP/IP模型的起源可以追溯到上世纪60年代,由美国国防部的研究项目ARPANET的发展过程中逐步形成。经过几轮的完善和演变,TCP/IP模型成为事实上的标准,并在1983年成为互联网的正式协议。通过深度解析TCP/IP模型,我们更好地理解了网络通信的基本原理和结构。

dgw2648633809的博客 3066
上一篇: C语言 函数返回二维数组
下一篇: TCP/IP网络模型之异步选择模型
xundao_803817
博客等级 码龄5年 7粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值