1 WSADATA
WSADATA 结构体包含了关于 Winsock 实现的一些详细信息,定义如下:
struct WSAData {
WORD wVersion; // Winsock版本号
WORD wHighVersion; // Winsock动态库支持的最高版本号
char szDescription[WSADESCRIPTION_LEN+1]; // Winsock描述
char szSystemStatus[WSASYSSTATUS_LEN+1]; // 系统状态
unsigned short iMaxSockets; // 最大并发Socket数
unsigned short iMaxUdpDg; // 最大UDP数据报大小
char FAR* lpVendorInfo; // 供应商信息指针
};
其中:
-
wVersion:表示 Winsock 的版本号,它是一个 16 位的值,高字节表示主版本号,低字节表示次版本号。
-
wHighVersion:表示 Winsock 支持的最高版本号,它也是一个 16 位的值,高字节表示主版本号,低字节表示次版本号。
-
szDescription:一个以空字符结尾的字符串,描述了 Winsock 实现的详细信息,如 “Winsock 2.0”。
-
szSystemStatus:一个以空字符结尾的字符串,描述了 Winsock 实现的系统状态,如 “Running”。
-
iMaxSockets:表示 Winsock 实现允许同时打开的最大套接字数量。
-
iMaxUdpDg:表示 Winsock 实现允许的最大 UDP 数据报大小(以字节为单位)。
-
lpVendorInfo:一个指向以空字符结尾的字符串的指针,该字符串包含了与 Winsock 实现相关的供应商特定信息。
要使用 Winsock,首先需要调用 WSAStartup() 函数,该函数会初始化 Winsock 并返回一个 WSADATA 结构体。在使用完 Winsock 后,需要调用 WSACleanup() 函数来释放资源。
以下是一个简单的示例,展示了如何使用 WSAStartup() 和 WSACleanup() 函数:
#include <winsock2.h>
#include<stdio.h>
int main() {
WSADATA wsaData;
int result;
// 初始化 Winsock
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
printf("WSAStartup failed with error: %d\n", result);
return 1;
}
printf("Winsock initialized successfully!\n");
printf("Winsock version: %d.%d\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
printf("Winsock description: %s\n", wsaData.szDescription);
printf("Winsock system status: %s\n", wsaData.szSystemStatus);
printf("Maximum sockets: %d\n", wsaData.iMaxSockets);
printf("Maximum UDP datagram size: %d\n", wsaData.iMaxUdpDg);
// 使用 Winsock 进行网络通信...
// 清理 Winsock
WSACleanup();
return 0;
}
上面代码的输出为:
Winsock initialized successfully!
Winsock version: 2.2
Winsock description: WinSock 2.0
Winsock system status: Running
Maximum sockets: 0
Maximum UDP datagram size: 0
在这个示例中,我们首先调用 WSAStartup() 函数来初始化 Winsock,并将返回的 WSADATA 结构体打印到控制台。然后,我们可以使用 Winsock 进行网络通信。最后,我们调用 WSACleanup() 函数来释放资源。
2 sockaddr_in
sockaddr_in 是一个用于表示 IPv4 地址的结构体,它属于 Windows 套接字(Winsock)库。该结构体定义如下:
struct sockaddr_in {
short sin_family; // 地址族,对于 IPv4 地址,应设置为 AF_INET
u_short sin_port; // 端口号,使用网络字节顺序
struct in_addr sin_addr; // IPv4 地址,使用网络字节顺序
char sin_zero[8]; // 未使用,应设置为 0
};
其中:
-
sin_family:表示地址族,对于 IPv4 地址,应设置为 AF_INET。
-
sin_port:表示端口号,使用网络字节顺序。可以使用 htons() 函数将主机字节顺序的端口号转换为网络字节顺序。
-
sin_addr:表示 IPv4 地址,使用网络字节顺序。可以使用 inet_addr() 函数将点分十进制表示的 IP 地址字符串转换为网络字节顺序的二进制表示,或者使用 inet_aton() 函数将点分十进制表示的 IP 地址字符串转换为 in_addr 结构体。
-
sin_zero:未使用,应设置为 0。
以下是一个简单的示例,展示了如何使用 sockaddr_in 结构体:
#include <winsock2.h>
#include<stdio.h>
int main() {
WSADATA wsaData;
int result;
// 初始化 Winsock
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
printf("WSAStartup failed with error: %d\n", result);
return 1;
}
// 创建一个 TCP 套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// 填充 sockaddr_in 结构体
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(80);
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.1");
memset(serverAddr.sin_zero, 0, sizeof(serverAddr.sin_zero));
// 连接到服务器
result = connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if (result == SOCKET_ERROR) {
printf("connect failed with error: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
}
// 使用套接字进行通信...
// 关闭套接字
closesocket(sock);
// 清理 Winsock
WSACleanup();
return 0;
}
在这个示例中,我们首先调用 WSAStartup() 函数来初始化 Winsock,并创建一个 TCP 套接字。然后,我们填充 sockaddr_in 结构体,并使用 connect() 函数连接到服务器。最后,我们可以使用套接字进行通信,并在完成后关闭套接字和清理 Winsock。
3 SOCKET
在 Windows 套接字(Winsock)编程中,SOCKET 是一个非常重要的数据类型,它代表了一个网络通信的端点。当应用程序想要进行网络通信(例如发送或接收数据)时,它会创建一个或多个套接字,并使用这些套接字与远程主机或本地服务进行通信。
SOCKET 本质上是一个句柄(handle),它用于在 Winsock API 函数调用中唯一标识一个套接字。这个句柄在内部由 Winsock 提供者管理,用于维护与该套接字关联的所有状态信息和资源。
以下是 SOCKET 类型的定义:
typedef UINT_PTR SOCKET;
其中 UINT_PTR 的定义为:
typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
(1)SOCKET 的创建
在 Windows 中,使用 socket() 函数来创建一个新的套接字。这个函数接受三个参数:地址族(例如 AF_INET 表示 IPv4),套接字类型(例如 SOCK_STREAM 表示 TCP 套接字,SOCK_DGRAM 表示 UDP 套接字),以及协议类型(通常设置为 0,表示使用默认的协议)。成功时,socket() 函数返回一个有效的 SOCKET 句柄;失败时返回 INVALID_SOCKET 并设置相应的错误代码。
(2)SOCKET 的使用
一旦创建了一个 SOCKET,应用程序就可以使用它来执行各种网络操作,如绑定到本地地址和端口、连接到远程主机、发送和接收数据等。这些操作通常通过调用其他 Winsock API 函数来完成,例如 bind()、connect()、send()、recv() 等。每个函数都需要一个有效的 SOCKET 句柄作为参数,以便识别要对哪个套接字执行操作。
(3)SOCKET 的关闭
当应用程序完成网络通信并不再需要某个套接字时,它应该使用 closesocket() 函数来关闭该套接字。这将释放与该套接字关联的所有资源,并允许 Winsock 提供者回收这些资源以供将来使用。忘记关闭不再需要的套接字可能会导致资源泄漏和其他问题。
(4)SOCKET 的状态
SOCKET 本身并不直接包含状态信息;状态信息是由 Winsock 提供者在内部维护的。然而,通过调用某些 Winsock API 函数(如 ioctlsocket()),应用程序可以查询或修改套接字的某些状态标志,例如非阻塞模式、广播模式等。
(5)错误处理
与大多数 Winsock API 函数一样,当使用 SOCKET 进行网络操作时,可能会发生错误。为了处理这些错误,应用程序应该检查每个 Winsock API 调用的返回值,并在必要时调用 WSAGetLastError() 来获取更详细的错误代码和信息。
(6)安全性
在使用 SOCKET 进行网络通信时,安全性是一个重要考虑因素。应用程序应该采取适当的措施来保护数据在传输过程中的机密性、完整性和真实性。这可能包括使用加密套接字层(SSL)或传输层安全性(TLS)来加密通信内容,以及验证远程主机的身份和授权。
(7)示例
#include <winsock2.h>
#include<stdio.h>
int main() {
WSADATA wsaData;
int result;
// 初始化 Winsock
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
printf("WSAStartup failed with error: %d\n", result);
return 1;
}
// 创建一个 TCP 套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// 使用套接字进行通信...
// 关闭套接字
closesocket(sock);
// 清理 Winsock
WSACleanup();
return 0;
}
在这个示例中,我们首先调用 WSAStartup() 函数来初始化 Winsock,并创建一个 TCP 套接字。然后,我们可以使用套接字进行通信,并在完成后关闭套接字和清理 Winsock。
4 WSK_SOCKET(一般用不到)
WSK_SOCKET 结构体在 Windows 套接字(Winsock)的扩展——Windows 套接字内核(WSK)中是一个核心组件。WSK 是 Windows 平台上的一个高级套接字 API,它允许开发者更紧密地集成到网络堆栈中,并提供比传统 Winsock 更高的性能和灵活性。
WSK_SOCKET 结构体通常用于表示一个 WSK 套接字实例,它封装了与特定套接字关联的状态和操作。虽然 WSK_SOCKET 的具体定义可能因 Windows 版本和具体实现而有所不同,但下面是一个大致的概念性描述:
typedef struct _WSK_SOCKET {
// 套接字句柄,用于在调用其他 WSK 函数时标识这个套接字
SOCKET SocketHandle;
// 指向 WSK 套接字的提供商控制块的指针
PWSK_PROVIDER_CONTROL_BLOCK ProviderControlBlock;
// 指向 WSK 套接字的传输控制块的指针
PWSK_TRANSPORT_CONTROL_BLOCK TransportControlBlock;
// 指向 WSK 套接字的扩展控制块的指针(如果有的话)
PWSK_EXTENSION_CONTROL_BLOCK ExtensionControlBlock;
// 套接字的状态信息,如是否绑定、是否连接等
ULONG State;
// 与套接字关联的发送和接收队列
WSK_SEND_QUEUE SendQueue;
WSK_RECEIVE_QUEUE ReceiveQueue;
// 其他套接字相关的信息和函数指针,如事件处理程序等
// ...
} WSK_SOCKET, *PWSK_SOCKET;
其中:
-
SocketHandle:这是套接字的句柄,用于在调用其他 WSK 函数时标识这个套接字。
-
ProviderControlBlock:指向 WSK 套接字的提供商控制块的指针。这个控制块通常包含与特定 WSK 提供商相关的信息,如提供商的句柄、配置等。
-
TransportControlBlock:指向 WSK 套接字的传输控制块的指针。这个控制块包含与套接字关联的传输层信息,如 IP 地址、端口号等。
-
ExtensionControlBlock:如果有的话,这是指向 WSK 套接字的扩展控制块的指针。这个控制块可以用于存储与套接字关联的自定义信息或状态。
-
State:这个字段包含套接字的状态信息,如是否绑定、是否连接等。它可以帮助开发者了解套接字的当前状态。
-
SendQueue 和 ReceiveQueue:这些队列用于管理套接字的发送和接收操作。它们可以帮助开发者以高效的方式处理网络数据的发送和接收。
-
其他字段:除了上述字段外,WSK_SOCKET 结构体还可能包含其他与套接字相关的信息和函数指针,如事件处理程序等。这些字段的具体内容和用途取决于 WSK 的实现和用途。
需要注意的是,WSK_SOCKET 结构体是一个底层结构,通常只在开发网络驱动程序或高性能网络应用程序时才需要直接操作。对于大多数应用程序来说,使用标准的 Winsock API 就足够了。
标签:SOCKET,Windows,WSK,编程,C++,result,接字,Winsock,函数 From: https://blog.csdn.net/h8062651/article/details/137511593