1 初始化与清理
1.1 WSAStartup
WSAStartup 函数用于初始化 Winsock 库,并指定应用程序所需的 Winsock 版本。它允许应用程序与 Winsock DLL(动态链接库)建立联系,并准备 Winsock 环境以供后续使用。
(1)函数原型如下:
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
(2)参数说明:
- wVersionRequested:指定应用程序请求的 Winsock 版本。通常,这个值设置为 MAKEWORD(2, 2),表示请求 Winsock 2.2 版本。
- lpWSAData:指向 WSADATA 结构体的指针,该结构体用于接收关于 Winsock 库的信息。
(3)返回值:
- 如果函数成功,返回值为 0。
- 如果函数失败,返回值为 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 函数来获取具体的错误代码。
(4)示例代码:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
int main() {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
printf("WSAStartup failed with error: %d\n", result);
return 1;
}
// 在这里进行网络操作...
WSACleanup(); // 完成网络操作后,调用 WSACleanup 清理 Winsock 库
return 0;
}
1.2 WSACleanup
WSACleanup 函数用于清理 Winsock 库,释放所有由 Winsock 分配的资源。在应用程序完成所有网络操作后,应该调用此函数来确保资源得到正确释放。
(1)函数原型如下:
int WSACleanup(void);
(2)返回值:
- 如果函数成功,返回值为 0。
- 如果函数失败,返回值为 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 函数来获取具体的错误代码。
在 1.1 的示例代码中,WSACleanup 函数被调用在完成所有网络操作之后,以确保 Winsock 库得到正确的清理。这是一个良好的编程实践,可以防止资源泄漏和其他潜在问题。
2 socket() 函数:创建套接字
在 Windows 套接字(Winsock)API 中,socket() 函数是用于创建一个新的套接字描述符的接口。套接字是网络通信中的一个端点,用于发送和接收数据。通过调用 socket() 函数,应用程序可以请求一个套接字,并根据其需要的通信类型进行配置。
(1)函数原型
SOCKET socket(int af, int type, int protocol);
(2)参数说明
-
af(地址族):这个参数指定了应用程序使用的通信协议族。对于 IPv4,通常使用 AF_INET;对于 IPv6,使用 AF_INET6。还有其他一些地址族,但这两个是最常用的。
-
type(套接字类型):这个参数指定了套接字的类型,它决定了套接字的行为以及数据的发送和接收方式。常见的套接字类型有:
- SOCK_STREAM:提供面向连接的、可靠的、基于字节流的服务,如 TCP。
- SOCK_DGRAM:提供无连接的、不可靠的、基于数据报的服务,如 UDP。
- SOCK_RAW:提供原始套接字,允许应用程序直接访问底层协议。
-
protocol(协议):这个参数通常设置为 0,表示让系统自动选择该地址族和套接字类型对应的默认协议。如果需要显式指定协议,这里可以填入协议号,但一般情况下不推荐这样做。
(3)返回值
-
如果函数成功,socket() 返回一个非负整数,即新创建的套接字描述符。这个描述符在后续的网络操作中用于标识该套接字。
-
如果函数失败,socket() 返回 SOCKET_ERROR,并且可以通过调用 WSAGetLastError() 来获取更详细的错误信息。
(4)示例代码
以下是一个简单的示例,展示如何使用 socket() 函数创建一个 TCP 套接字:
#include <winsock2.h>
#include <stdio.h>
int main() {
WSADATA wsaData;
int 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, 0);
if (sock == SOCKET_ERROR) {
int err = WSAGetLastError();
printf("socket() failed with error: %d\n", err);
WSACleanup();
return 1;
}
// 在这里进行网络操作,例如绑定、监听、连接等...
// 关闭套接字
closesocket(sock);
// 清理 Winsock 库
WSACleanup();
return 0;
}
在上面的示例中,我们首先调用 WSAStartup() 来初始化 Winsock 库。然后,我们使用 socket() 函数创建一个 IPv4(AF_INET)和 TCP(SOCK_STREAM)类型的套接字。如果 socket() 函数失败,我们通过调用 WSAGetLastError() 来获取错误信息,并清理 Winsock 库后退出程序。
3 套接字地址操作
3.1 inet_addr
inet_addr 函数是一个较老且相对简单的函数,用于将点分十进制的 IP 地址(例如 “192.168.1.1”)转换为一个 32 位的整数,该整数按照网络字节序(大端)排列。
(1)函数原型:
in_addr_t inet_addr(const char *cp);
(2)参数:
- cp:指向以空字符结尾的字符串的指针,该字符串表示一个点分十进制的 IPv4 地址。
(3)返回值:
- 如果转换成功,返回该 IP 地址对应的网络字节序整数。
- 如果转换失败(例如,输入的不是有效的 IP 地址),返回 INADDR_NONE(通常是 -1)。
(4)示例:
struct sockaddr_in serverAddr;
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.1");
if (serverAddr.sin_addr.s_addr == INADDR_NONE) {
// 处理错误
}
需要注意的是,inet_addr 函数不支持 IPv6 地址,并且不支持错误处理(只能通过返回值判断)。对于更复杂的地址转换需求,推荐使用 inet_pton 函数。
3.2 htons/htonl
htons 和 htonl 是一组用于转换主机字节序到网络字节序的函数。它们分别用于转换 16 位(短整数)和 32 位(长整数)的数值。
(1)函数原型:
uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);
(2)参数:
- hostshort:主机字节序的 16 位整数。
- hostlong:主机字节序的 32 位整数。
(3)返回值:
- 转换后的网络字节序的整数。
(4)示例:
struct sockaddr_in serverAddr;
serverAddr.sin_port = htons(12345); // 将端口号从主机字节序转换为网络字节序
3.3 ntohs/ntohl
ntohs 和 ntohl 是 htons 和 htonl 的反向操作,用于将网络字节序的整数转换回主机字节序。
(1)函数原型:
uint16_t ntohs(uint16_t netshort);
uint32_t ntohl(uint32_t netlong);
(2)参数:
- netshort:网络字节序的 16 位整数。
- netlong:网络字节序的 32 位整数。
(3)返回值:
- 转换后的主机字节序的整数。
(4)示例:
uint16_t receivedPort = ntohs(someNetworkShort); // 将从网络接收到的端口号转换为主机字节序
3.4 bind
bind 函数用于将套接字绑定到本地地址和端口。在创建套接字后,通常需要调用 bind 函数来指定套接字应该使用的本地地址和端口。
(1)函数原型:
int bind(SOCKET s, const struct sockaddr *name, int namelen);
(2)参数:
- s:要绑定的套接字描述符。
- name:指向包含本地地址信息的 sockaddr 结构体的指针。
- namelen:name 参数指向的地址结构体的长度。
(3)返回值:
- 如果成功,返回 0。
- 如果失败,返回 SOCKET_ERROR,可以通过 WSAGetLastError 获取错误代码。
(4)示例:
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); // 创建一个 IPv4 TCP 套接字
if (sock == INVALID_SOCKET) {
// 处理错误
}
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr)); // 初始化地址结构体
serverAddr.sin_family = AF_INET; // 使用 IPv4 地址
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定到任意本地地址
serverAddr.sin_port = htons(12345); // 绑定到端口 12345
if (bind(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
int error = WSAGetLastError();
// 处理错误
}
3.5 getpeername
getpeername 函数用于获取已连接套接字的远程地址。这对于服务器程序来说尤其有用,因为它们需要知道客户端的地址信息。
(1)函数原型:
int getpeername(SOCKET s, struct sockaddr *name, int *namelen);
(2)参数:
- s:已连接的套接字描述符。
- name:指向用于接收远程地址信息的 sockaddr 结构体的指针。
- namelen:指向 name 参数指向的地址结构体长度的指针。
(3)返回值:
- 如果成功,返回 0。
- 如果失败,返回 SOCKET_ERROR,可以通过 WSAGetLastError 获取错误代码。
(4)示例:
SOCKET sock = ...; // 假设 sock 是一个已连接的套接字
struct sockaddr_in peerAddr;
int addrlen = sizeof(peerAddr);
if (getpeername(sock, (struct sockaddr*)&peerAddr, &addrlen) == SOCKET_ERROR) {
int error = WSAGetLastError();
// 处理错误
} else {
char peerIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &peerAddr.sin_addr, peerIP, sizeof(peerIP));
printf("Remote peer IP address: %s\n", peerIP);
printf("Remote peer port: %d\n", ntohs(peerAddr.sin_port));
}
3.6 getsockname
getsockname 函数用于获取套接字的本地地址。这对于服务器和客户端程序都可能是有用的,因为它们可能需要知道它们自己的本地地址。
(1)函数原型:
int getsockname(SOCKET s, struct sockaddr *name, int *namelen);
(2)参数:
- s:要绑定的套接字描述符。
- name:指向包含本地地址信息的 sockaddr 结构体的指针。
- namelen:name 参数指向的地址结构体的长度。
(3)返回值:
- 如果成功,返回 0。
- 如果失败,返回 SOCKET_ERROR,可以通过 WSAGetLastError 获取错误代码。
(4)示例:
SOCKET sock = ...; // 假设 sock 是一个已绑定或已连接的套接字
struct sockaddr
sockaddr_in localAddr;
int addrlen = sizeof(localAddr);
if (getsockname(sock, (struct sockaddr*)&localAddr, &addrlen) == SOCKET_ERROR) {
int error = WSAGetLastError();
// 处理错误
} else {
char localIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &localAddr.sin_addr, localIP, sizeof(localIP));
printf("Local IP address: %s\n", localIP);
printf("Local port: %d\n", ntohs(localAddr.sin_port));
}
标签:函数,Windows,编程,C++,int,地址,接字,Winsock,SOCKET
From: https://blog.csdn.net/h8062651/article/details/137514013