首页 > 系统相关 >突破编程_C++_网络编程(Windows 套接字(API 接口(1)))

突破编程_C++_网络编程(Windows 套接字(API 接口(1)))

时间:2024-04-08 16:33:04浏览次数:27  
标签:函数 Windows 编程 C++ int 地址 接字 Winsock SOCKET

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

相关文章

  • 【每周例题】蓝桥杯 C++ 对称排序
    对称排序题目对称排序 题目分析1.因为数字是对称交换,所以我们只需要判断前n/2项需不需要交换就好了2.这里我采用了升序排序,你们也可以尝试降序排序3.我们只需要排序好后再遍历一下整个数组,找出不符合排序的就输出NO就好了代码#include<iostream>#include<bits/stdc+......
  • Java面象对象编程学习(保姆级教学)
    1、基本数据类型和引用数据类型的区别(用内存的角度):基本数据类型:数据值是存储在自己的空间中特点:赋的值也是真实的值引用数据类型:数据值存储在其他空间中,自己空间存储的是地址值特点:赋的值是地址值★【注意:在静态代码块中,随着类的加载进行,而且只进行一......
  • R语言编程和操作系统交互
    文章目录一、重复和循环1.for循环2.while循环二、条件分支1.if-else2.switch三、创建函数1.不含参数的函数2.含参数的函数四、和操作系统的交互1.计算CPUtime2.历史的存储和读取3.工作目录4.文件处理一、重复和循环1.for循环>x<-numeric(10)#占位符,否则无......
  • Windows下安装配置WinPcap
    winpcap官网:http://www.winpcap.org/1.首先下载安装winpcap.exe,http://www.winpcap.org/install/default.htm目的是安装相关驱动和dll,安装完成之后基于winpcap的应用程序才能够正常运行。2.下载winpcap的开发包,头问文件和库文件:http://www.winpcap.org/devel.htm 解压之后主......
  • Windows下配置使用WinPcap
     0、前提   windows:win7x64   WinPcap版本:4.1.3   WinPcap开发包:4.1.2   目标:在VS2010中配置使用winpcap获取目标计算机中安装的网卡列表 1、下载   http://www.winpcap.org/下载winpcap安装包和开发包安装包安装完毕后,解压开发包到某个......
  • 毕业设计jspm少儿编程教育网站系统
    摘要在国家重视教育影响下,教育部门的密确配合下,对教育进行改革、多样性、质量等等的要求,使教育系统的管理和运营比过去十年前更加理性化。依照这一现实为基础,设计一个快捷而又方便的网上少儿编程教育网站系统是一项十分重要并且有价值的事情。对于传统的少儿编程教育网站......
  • 题目 1035: [编程入门]自定义函数之字符类型统计
    一、题目 题目描述编写一函数,由实参传来一个字符串,统计此字符串中字母、数字、空格和其它字符的个数,在主函数中输入字符串以及输出上述结果。只要结果,别输出什么提示信息。输入格式一行字符串输出格式统计数据,4个数字,空格分开。样例输入!@#$%^QWERT   1234567......
  • 运维系列(创建windows服务,亲测有效):Windows 安装Redis(图文详解)
    Windows安装Redis(图文详解)Windows安装Redis(图文详解)一、Redis是什么数据库?二、安装Redis1、下载地址2、安装过程2.1将下载的压缩包解压到一个文件夹中:2.2打开cmd指令窗口,进入到解压的那个文件夹里:2.3输入redis-serverredis.windows.conf:2.4部署Redis在windows下的......
  • Python 高级编程必会之深浅拷贝
    浅拷贝和深拷贝在Python中各有用武之地,正确的选择取决于具体的应用场景、数据结构的复杂性以及对性能的要求。理解这两种方法的工作原理和差异,是每个Python开发者在进行数据复制操作时必须掌握的基础。 在我们进行Python编程的时候,复制(拷贝)数据结构是一种常见的操作,比如当......
  • Windows系统如何做端口映射?
    在网络通信中,端口映射是一项关键技术,允许将公共网络上的端口映射到私有网络上的特定设备或服务。对于Windows用户而言,端口映射为实现远程访问提供了便利。本文将探讨Windows端口映射及其应用。天联组网的优势天联组网是一项功能强大的服务,具有以下优势:无网络限制:天联组网......